1use crate::bump::BumpAlloc;
10use crate::config::{CACHE_LINE_ALIGN, PAGE_ALIGN};
11use std::sync::Arc;
12
13pub struct PolynomialArena {
17 inner: Arc<BumpAlloc>,
18}
19
20impl PolynomialArena {
21 #[inline]
23 pub fn new(inner: Arc<BumpAlloc>) -> Self {
24 Self { inner }
25 }
26
27 #[inline]
34 pub fn alloc_fft_friendly(&self, size: usize) -> *mut u8 {
35 debug_assert!(size > 0);
36 self.inner.alloc(size, CACHE_LINE_ALIGN)
37 }
38
39 #[inline]
46 pub fn alloc_huge(&self, size: usize) -> *mut u8 {
47 debug_assert!(size > 0);
48 self.inner.alloc(size, PAGE_ALIGN)
49 }
50
51 #[inline]
56 pub fn alloc(&self, size: usize, align: usize) -> *mut u8 {
57 debug_assert!(size > 0);
58 debug_assert!(align > 0);
59 debug_assert!(align.is_power_of_two());
60 self.inner.alloc(size, align)
61 }
62
63 #[inline]
72 pub unsafe fn alloc_slice<T>(&self, count: usize) -> *mut T {
73 debug_assert!(count > 0);
74 let size = count * std::mem::size_of::<T>();
75 let align = std::mem::align_of::<T>().max(CACHE_LINE_ALIGN);
76 self.inner.alloc(size, align) as *mut T
77 }
78
79 #[inline]
84 pub unsafe fn reset(&self) {
85 self.inner.reset();
86 }
87
88 #[inline]
90 pub fn remaining(&self) -> usize {
91 self.inner.remaining()
92 }
93
94 #[inline]
96 pub fn used(&self) -> usize {
97 self.inner.used()
98 }
99
100 #[inline]
102 pub fn capacity(&self) -> usize {
103 self.inner.capacity()
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110 use crate::arena::ArenaManager;
111
112 #[test]
113 fn test_fft_alignment() {
114 let manager = ArenaManager::with_sizes(1024 * 1024, 2 * 1024 * 1024, 1024 * 1024).unwrap();
115 let poly = PolynomialArena::new(manager.polynomial());
116
117 for _ in 0..100 {
118 let ptr = poly.alloc_fft_friendly(1024);
119 assert!(!ptr.is_null());
120 assert_eq!(
121 (ptr as usize) % CACHE_LINE_ALIGN,
122 0,
123 "FFT allocation not 64-byte aligned"
124 );
125 }
126 }
127
128 #[test]
129 fn test_huge_alignment() {
130 let manager = ArenaManager::with_sizes(1024 * 1024, 2 * 1024 * 1024, 1024 * 1024).unwrap();
131 let poly = PolynomialArena::new(manager.polynomial());
132
133 for _ in 0..10 {
134 let ptr = poly.alloc_huge(64 * 1024);
135 assert!(!ptr.is_null());
136 assert_eq!(
137 (ptr as usize) % PAGE_ALIGN,
138 0,
139 "Huge allocation not page-aligned"
140 );
141 }
142 }
143
144 #[test]
145 fn test_typed_slice_allocation() {
146 let manager = ArenaManager::with_sizes(1024 * 1024, 2 * 1024 * 1024, 1024 * 1024).unwrap();
147 let poly = PolynomialArena::new(manager.polynomial());
148
149 let ptr: *mut u64 = unsafe { poly.alloc_slice(1024) };
151 assert!(!ptr.is_null());
152 assert_eq!(
153 (ptr as usize) % std::mem::align_of::<u64>(),
154 0,
155 "Slice not aligned for u64"
156 );
157
158 unsafe {
160 for i in 0..1024 {
161 *ptr.add(i) = i as u64;
162 }
163 for i in 0..1024 {
164 assert_eq!(*ptr.add(i), i as u64);
165 }
166 }
167 }
168
169 #[test]
170 fn test_custom_alignment() {
171 let manager = ArenaManager::with_sizes(1024 * 1024, 2 * 1024 * 1024, 1024 * 1024).unwrap();
172 let poly = PolynomialArena::new(manager.polynomial());
173
174 for align_pow in 0..12 {
176 let align = 1usize << align_pow;
177 let ptr = poly.alloc(64, align);
178 assert!(!ptr.is_null());
179 assert_eq!(
180 (ptr as usize) % align,
181 0,
182 "Custom alignment {} failed",
183 align
184 );
185 }
186 }
187}