use alloc::alloc::{alloc, dealloc, Layout};
use alloc::boxed::Box;
use alloc::vec;
use alloc::vec::Vec;
use core::ptr::NonNull;
pub const AVX2_ALIGNMENT: usize = 32;
pub const SSE_ALIGNMENT: usize = 16;
pub const CACHE_LINE_SIZE: usize = 64;
#[repr(C)]
pub struct AlignedMemory<T: Copy> {
ptr: NonNull<T>,
layout: Layout,
}
impl<T: Copy> AlignedMemory<T> {
pub fn new(count: usize, alignment: usize) -> Result<Self, &'static str> {
let size = count * core::mem::size_of::<T>();
let layout = Layout::from_size_align(size, alignment)
.map_err(|_| "Invalid layout for aligned allocation")?;
let ptr = unsafe { alloc(layout) as *mut T };
if ptr.is_null() {
return Err("Failed to allocate aligned memory");
}
let ptr = unsafe { NonNull::new_unchecked(ptr) };
Ok(Self { ptr, layout })
}
pub fn as_ptr(&self) -> *const T {
self.ptr.as_ptr()
}
pub fn as_mut_ptr(&mut self) -> *mut T {
self.ptr.as_ptr()
}
pub fn capacity(&self) -> usize {
self.layout.size() / core::mem::size_of::<T>()
}
}
impl<T: Copy> Drop for AlignedMemory<T> {
fn drop(&mut self) {
unsafe {
dealloc(self.ptr.as_ptr() as *mut u8, self.layout);
}
}
}
pub fn create_aligned_f64_vec(count: usize) -> Vec<f64> {
if count <= 16 {
return vec![0.0; count];
}
let mut vec = Vec::with_capacity(count);
vec.resize(count, 0.0);
let ptr = vec.as_ptr() as usize;
if count == 8 && !ptr.is_multiple_of(AVX2_ALIGNMENT) {
let mut aligned_vec = Vec::with_capacity(count + (AVX2_ALIGNMENT / 8));
aligned_vec.resize(count, 0.0);
let start_ptr = aligned_vec.as_ptr() as usize;
let aligned_offset = (AVX2_ALIGNMENT - (start_ptr % AVX2_ALIGNMENT)) % AVX2_ALIGNMENT / 8;
if aligned_offset < aligned_vec.len() - count {
aligned_vec.drain(0..aligned_offset);
aligned_vec.truncate(count);
return aligned_vec;
}
}
vec
}
pub struct MemoryPool {
blocks: Vec<AlignedMemory<f64>>,
block_size: usize,
alignment: usize,
}
impl MemoryPool {
pub fn new(block_size: usize, alignment: usize) -> Self {
Self {
blocks: Vec::new(),
block_size,
alignment,
}
}
pub fn for_3d_clifford() -> Self {
Self::new(8, AVX2_ALIGNMENT)
}
pub fn allocate(&mut self) -> Result<Box<[f64]>, &'static str> {
let coefficients = create_aligned_f64_vec(self.block_size);
Ok(coefficients.into_boxed_slice())
}
pub fn pre_allocate(&mut self, count: usize) -> Result<(), &'static str> {
for _ in 0..count {
let block = AlignedMemory::new(self.block_size, self.alignment)?;
self.blocks.push(block);
}
Ok(())
}
}
pub struct AlignedCoefficients {
data: Box<[f64]>,
}
impl AlignedCoefficients {
pub fn new(count: usize) -> Self {
Self {
data: create_aligned_f64_vec(count).into_boxed_slice(),
}
}
pub fn zero(count: usize) -> Self {
let mut coeffs = Self::new(count);
coeffs.data.fill(0.0);
coeffs
}
pub fn as_slice(&self) -> &[f64] {
&self.data
}
pub fn as_mut_slice(&mut self) -> &mut [f64] {
&mut self.data
}
pub fn into_boxed_slice(self) -> Box<[f64]> {
self.data
}
pub fn is_simd_aligned(&self) -> bool {
let ptr = self.data.as_ptr() as usize;
ptr.is_multiple_of(AVX2_ALIGNMENT)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_aligned_memory() {
let mem = AlignedMemory::<f64>::new(8, AVX2_ALIGNMENT).unwrap();
let ptr = mem.as_ptr() as usize;
assert_eq!(ptr % AVX2_ALIGNMENT, 0);
assert_eq!(mem.capacity(), 8);
}
#[test]
fn test_aligned_coefficients() {
let coeffs = AlignedCoefficients::zero(8);
assert_eq!(coeffs.as_slice().len(), 8);
assert!(coeffs.as_slice().iter().all(|&x| x == 0.0));
}
#[test]
fn test_memory_pool() {
let mut pool = MemoryPool::for_3d_clifford();
let _block = pool.allocate().unwrap();
assert_eq!(pool.block_size, 8);
assert_eq!(pool.alignment, AVX2_ALIGNMENT);
}
#[test]
fn test_aligned_f64_vec() {
let vec = create_aligned_f64_vec(8);
assert_eq!(vec.len(), 8);
let ptr = vec.as_ptr() as usize;
assert_eq!(ptr % 8, 0);
}
}