use crate::bump::BumpAlloc;
use crate::config::{CACHE_LINE_ALIGN, PAGE_ALIGN};
use std::sync::Arc;
pub struct PolynomialArena {
inner: Arc<BumpAlloc>,
}
impl PolynomialArena {
#[inline]
pub fn new(inner: Arc<BumpAlloc>) -> Self {
Self { inner }
}
#[inline]
pub fn alloc_fft_friendly(&self, size: usize) -> *mut u8 {
debug_assert!(size > 0);
self.inner.alloc(size, CACHE_LINE_ALIGN)
}
#[inline]
pub fn alloc_huge(&self, size: usize) -> *mut u8 {
debug_assert!(size > 0);
self.inner.alloc(size, PAGE_ALIGN)
}
#[inline]
pub fn alloc(&self, size: usize, align: usize) -> *mut u8 {
debug_assert!(size > 0);
debug_assert!(align > 0);
debug_assert!(align.is_power_of_two());
self.inner.alloc(size, align)
}
#[inline]
pub unsafe fn alloc_slice<T>(&self, count: usize) -> *mut T {
debug_assert!(count > 0);
let size = count * std::mem::size_of::<T>();
let align = std::mem::align_of::<T>().max(CACHE_LINE_ALIGN);
self.inner.alloc(size, align) as *mut T
}
#[inline]
pub unsafe fn reset(&self) {
self.inner.reset();
}
#[inline]
pub fn remaining(&self) -> usize {
self.inner.remaining()
}
#[inline]
pub fn used(&self) -> usize {
self.inner.used()
}
#[inline]
pub fn capacity(&self) -> usize {
self.inner.capacity()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::arena::ArenaManager;
#[test]
fn test_fft_alignment() {
let manager = ArenaManager::with_sizes(1024 * 1024, 2 * 1024 * 1024, 1024 * 1024).unwrap();
let poly = PolynomialArena::new(manager.polynomial());
for _ in 0..100 {
let ptr = poly.alloc_fft_friendly(1024);
assert!(!ptr.is_null());
assert_eq!(
(ptr as usize) % CACHE_LINE_ALIGN,
0,
"FFT allocation not 64-byte aligned"
);
}
}
#[test]
fn test_huge_alignment() {
let manager = ArenaManager::with_sizes(1024 * 1024, 2 * 1024 * 1024, 1024 * 1024).unwrap();
let poly = PolynomialArena::new(manager.polynomial());
for _ in 0..10 {
let ptr = poly.alloc_huge(64 * 1024);
assert!(!ptr.is_null());
assert_eq!(
(ptr as usize) % PAGE_ALIGN,
0,
"Huge allocation not page-aligned"
);
}
}
#[test]
fn test_typed_slice_allocation() {
let manager = ArenaManager::with_sizes(1024 * 1024, 2 * 1024 * 1024, 1024 * 1024).unwrap();
let poly = PolynomialArena::new(manager.polynomial());
let ptr: *mut u64 = unsafe { poly.alloc_slice(1024) };
assert!(!ptr.is_null());
assert_eq!(
(ptr as usize) % std::mem::align_of::<u64>(),
0,
"Slice not aligned for u64"
);
unsafe {
for i in 0..1024 {
*ptr.add(i) = i as u64;
}
for i in 0..1024 {
assert_eq!(*ptr.add(i), i as u64);
}
}
}
#[test]
fn test_custom_alignment() {
let manager = ArenaManager::with_sizes(1024 * 1024, 2 * 1024 * 1024, 1024 * 1024).unwrap();
let poly = PolynomialArena::new(manager.polynomial());
for align_pow in 0..12 {
let align = 1usize << align_pow;
let ptr = poly.alloc(64, align);
assert!(!ptr.is_null());
assert_eq!(
(ptr as usize) % align,
0,
"Custom alignment {} failed",
align
);
}
}
}