use super::aligned::{AlignedAllocator, AlignmentConfig};
use crate::error::{MemoryError, NumRs2Error, Result};
use std::alloc::{alloc, dealloc, Layout};
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
use std::{fmt, mem, ptr, slice};
pub struct AlignedBox<T> {
ptr: NonNull<T>,
alignment: usize,
}
impl<T> AlignedBox<T> {
pub fn new(value: T) -> Result<Self> {
Self::with_alignment(value, 64)
}
pub fn with_alignment(value: T, alignment: usize) -> Result<Self> {
if !alignment.is_power_of_two() {
return Err(NumRs2Error::from(MemoryError::allocation_failed(
"Alignment must be a power of 2",
alignment,
)));
}
let type_align = mem::align_of::<T>();
let final_align = alignment.max(type_align);
let size = mem::size_of::<T>();
if size == 0 {
return Ok(Self {
ptr: NonNull::dangling(),
alignment: final_align,
});
}
let layout = Layout::from_size_align(size, final_align).map_err(|e| {
NumRs2Error::from(MemoryError::allocation_failed(
&format!("Invalid layout: {}", e),
size,
))
})?;
unsafe {
let raw_ptr = alloc(layout);
if raw_ptr.is_null() {
return Err(NumRs2Error::from(MemoryError::allocation_failed(
"Memory allocation failed",
size,
)));
}
let ptr = NonNull::new_unchecked(raw_ptr as *mut T);
ptr::write(ptr.as_ptr(), value);
Ok(Self {
ptr,
alignment: final_align,
})
}
}
pub fn new_simd_512(value: T) -> Result<Self> {
Self::with_alignment(value, 64)
}
pub fn new_simd_256(value: T) -> Result<Self> {
Self::with_alignment(value, 32)
}
pub fn new_simd_128(value: T) -> Result<Self> {
Self::with_alignment(value, 16)
}
pub fn alignment(&self) -> usize {
self.alignment
}
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 verify_alignment(&self) -> bool {
let addr = self.ptr.as_ptr() as usize;
addr.is_multiple_of(self.alignment)
}
}
impl<T> Deref for AlignedBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { self.ptr.as_ref() }
}
}
impl<T> DerefMut for AlignedBox<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.ptr.as_mut() }
}
}
impl<T> Drop for AlignedBox<T> {
fn drop(&mut self) {
let size = mem::size_of::<T>();
if size == 0 {
return;
}
unsafe {
ptr::drop_in_place(self.ptr.as_ptr());
let layout = Layout::from_size_align_unchecked(size, self.alignment);
dealloc(self.ptr.as_ptr() as *mut u8, layout);
}
}
}
impl<T: fmt::Debug> fmt::Debug for AlignedBox<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AlignedBox")
.field("value", &**self)
.field("alignment", &self.alignment)
.field("address", &(self.ptr.as_ptr() as usize))
.finish()
}
}
impl<T: Clone> Clone for AlignedBox<T> {
fn clone(&self) -> Self {
Self::with_alignment((**self).clone(), self.alignment)
.expect("Clone should not fail if original allocation succeeded")
}
}
unsafe impl<T: Send> Send for AlignedBox<T> {}
unsafe impl<T: Sync> Sync for AlignedBox<T> {}
pub struct AlignedVec<T> {
ptr: NonNull<T>,
len: usize,
capacity: usize,
alignment: usize,
}
impl<T> AlignedVec<T> {
pub fn new() -> Self {
Self {
ptr: NonNull::dangling(),
len: 0,
capacity: 0,
alignment: 64,
}
}
pub fn with_capacity(capacity: usize) -> Result<Self> {
Self::with_capacity_and_alignment(capacity, 64)
}
pub fn with_capacity_and_alignment(capacity: usize, alignment: usize) -> Result<Self> {
if !alignment.is_power_of_two() {
return Err(NumRs2Error::from(MemoryError::allocation_failed(
"Alignment must be a power of 2",
alignment,
)));
}
if capacity == 0 || mem::size_of::<T>() == 0 {
return Ok(Self {
ptr: NonNull::dangling(),
len: 0,
capacity: 0,
alignment,
});
}
let type_align = mem::align_of::<T>();
let final_align = alignment.max(type_align);
let size = mem::size_of::<T>().checked_mul(capacity).ok_or_else(|| {
NumRs2Error::from(MemoryError::allocation_failed(
"Capacity overflow",
capacity,
))
})?;
let layout = Layout::from_size_align(size, final_align).map_err(|e| {
NumRs2Error::from(MemoryError::allocation_failed(
&format!("Invalid layout: {}", e),
size,
))
})?;
unsafe {
let raw_ptr = alloc(layout);
if raw_ptr.is_null() {
return Err(NumRs2Error::from(MemoryError::allocation_failed(
"Memory allocation failed",
size,
)));
}
Ok(Self {
ptr: NonNull::new_unchecked(raw_ptr as *mut T),
len: 0,
capacity,
alignment: final_align,
})
}
}
pub fn simd_512_with_capacity(capacity: usize) -> Result<Self> {
Self::with_capacity_and_alignment(capacity, 64)
}
pub fn simd_256_with_capacity(capacity: usize) -> Result<Self> {
Self::with_capacity_and_alignment(capacity, 32)
}
pub fn simd_128_with_capacity(capacity: usize) -> Result<Self> {
Self::with_capacity_and_alignment(capacity, 16)
}
pub fn push(&mut self, value: T) -> Result<()> {
if self.len == self.capacity {
self.grow()?;
}
unsafe {
ptr::write(self.ptr.as_ptr().add(self.len), value);
}
self.len += 1;
Ok(())
}
pub fn pop(&mut self) -> Option<T> {
if self.len == 0 {
return None;
}
self.len -= 1;
unsafe { Some(ptr::read(self.ptr.as_ptr().add(self.len))) }
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn alignment(&self) -> usize {
self.alignment
}
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 as_slice(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
}
pub fn clear(&mut self) {
unsafe {
ptr::drop_in_place(std::ptr::slice_from_raw_parts_mut(
self.ptr.as_ptr(),
self.len,
));
}
self.len = 0;
}
pub fn reserve(&mut self, additional: usize) -> Result<()> {
let required_cap = self.len.checked_add(additional).ok_or_else(|| {
NumRs2Error::from(MemoryError::allocation_failed(
"Capacity overflow",
additional,
))
})?;
if required_cap <= self.capacity {
return Ok(());
}
self.grow_to(required_cap)
}
pub fn verify_alignment(&self) -> bool {
let addr = self.ptr.as_ptr() as usize;
addr.is_multiple_of(self.alignment)
}
fn grow(&mut self) -> Result<()> {
let new_capacity = if self.capacity == 0 {
8
} else {
self.capacity.saturating_mul(2)
};
self.grow_to(new_capacity)
}
fn grow_to(&mut self, min_capacity: usize) -> Result<()> {
if mem::size_of::<T>() == 0 {
self.capacity = usize::MAX;
return Ok(());
}
let new_capacity = min_capacity.max(self.capacity);
let new_size = mem::size_of::<T>()
.checked_mul(new_capacity)
.ok_or_else(|| {
NumRs2Error::from(MemoryError::allocation_failed(
"Capacity overflow in grow",
new_capacity,
))
})?;
let new_layout = Layout::from_size_align(new_size, self.alignment).map_err(|e| {
NumRs2Error::from(MemoryError::allocation_failed(
&format!("Invalid layout in grow: {}", e),
new_size,
))
})?;
unsafe {
let new_ptr = alloc(new_layout);
if new_ptr.is_null() {
return Err(NumRs2Error::from(MemoryError::allocation_failed(
"Memory allocation failed in grow",
new_size,
)));
}
if self.capacity > 0 {
ptr::copy_nonoverlapping(self.ptr.as_ptr(), new_ptr as *mut T, self.len);
let old_size = mem::size_of::<T>() * self.capacity;
let old_layout = Layout::from_size_align_unchecked(old_size, self.alignment);
dealloc(self.ptr.as_ptr() as *mut u8, old_layout);
}
self.ptr = NonNull::new_unchecked(new_ptr as *mut T);
self.capacity = new_capacity;
}
Ok(())
}
}
impl<T> Default for AlignedVec<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> Deref for AlignedVec<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl<T> DerefMut for AlignedVec<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_slice()
}
}
impl<T> Drop for AlignedVec<T> {
fn drop(&mut self) {
if self.capacity == 0 || mem::size_of::<T>() == 0 {
return;
}
unsafe {
ptr::drop_in_place(std::ptr::slice_from_raw_parts_mut(
self.ptr.as_ptr(),
self.len,
));
let size = mem::size_of::<T>() * self.capacity;
let layout = Layout::from_size_align_unchecked(size, self.alignment);
dealloc(self.ptr.as_ptr() as *mut u8, layout);
}
}
}
impl<T: fmt::Debug> fmt::Debug for AlignedVec<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AlignedVec")
.field("data", &self.as_slice())
.field("len", &self.len)
.field("capacity", &self.capacity)
.field("alignment", &self.alignment)
.finish()
}
}
impl<T: Clone> Clone for AlignedVec<T> {
fn clone(&self) -> Self {
let mut new_vec = Self::with_capacity_and_alignment(self.len, self.alignment)
.expect("Clone should not fail if original allocation succeeded");
for item in self.as_slice() {
new_vec
.push(item.clone())
.expect("Push should not fail with pre-allocated capacity");
}
new_vec
}
}
unsafe impl<T: Send> Send for AlignedVec<T> {}
unsafe impl<T: Sync> Sync for AlignedVec<T> {}
pub unsafe fn aligned_alloc(size: usize, alignment: usize) -> *mut u8 {
if size == 0 {
return ptr::null_mut();
}
let layout = match Layout::from_size_align(size, alignment) {
Ok(l) => l,
Err(_) => return ptr::null_mut(),
};
alloc(layout)
}
pub unsafe fn aligned_alloc_zeroed(size: usize, alignment: usize) -> *mut u8 {
if size == 0 {
return ptr::null_mut();
}
let layout = match Layout::from_size_align(size, alignment) {
Ok(l) => l,
Err(_) => return ptr::null_mut(),
};
std::alloc::alloc_zeroed(layout)
}
pub unsafe fn aligned_dealloc(ptr: *mut u8, size: usize, alignment: usize) {
if ptr.is_null() || size == 0 {
return;
}
let layout = Layout::from_size_align_unchecked(size, alignment);
dealloc(ptr, layout);
}
pub fn is_aligned(ptr: *const u8, alignment: usize) -> bool {
(ptr as usize).is_multiple_of(alignment)
}
pub fn cache_line_size() -> usize {
64
}
pub fn optimal_simd_alignment() -> usize {
#[cfg(target_arch = "x86_64")]
{
if is_x86_feature_detected!("avx512f") {
64
} else if is_x86_feature_detected!("avx2") || is_x86_feature_detected!("avx") {
32
} else {
16
}
}
#[cfg(target_arch = "aarch64")]
{
16 }
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{
16 }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_aligned_box_basic() {
let boxed = AlignedBox::new(42u64).expect("test: valid AlignedBox creation");
assert_eq!(*boxed, 42);
assert!(boxed.verify_alignment());
}
#[test]
fn test_aligned_box_alignment() {
let boxed =
AlignedBox::with_alignment(123u64, 64).expect("test: valid AlignedBox with alignment");
let addr = boxed.as_ptr() as usize;
assert_eq!(addr % 64, 0);
assert_eq!(boxed.alignment(), 64);
}
#[test]
fn test_aligned_vec_basic() {
let mut vec = AlignedVec::with_capacity(10).expect("test: valid AlignedVec creation");
vec.push(1.0f64).expect("test: valid push");
vec.push(2.0f64).expect("test: valid push");
vec.push(3.0f64).expect("test: valid push");
assert_eq!(vec.len(), 3);
assert_eq!(vec[0], 1.0);
assert_eq!(vec[1], 2.0);
assert_eq!(vec[2], 3.0);
assert!(vec.verify_alignment());
}
#[test]
fn test_aligned_vec_grow() {
let mut vec = AlignedVec::with_capacity(2).expect("test: valid AlignedVec creation");
for i in 0..10 {
vec.push(i).expect("test: valid push");
}
assert_eq!(vec.len(), 10);
assert!(vec.capacity() >= 10);
assert!(vec.verify_alignment());
for i in 0..10 {
assert_eq!(vec[i], i);
}
}
#[test]
fn test_aligned_vec_pop() {
let mut vec = AlignedVec::with_capacity(5).expect("test: valid AlignedVec creation");
vec.push(1).expect("test: valid push");
vec.push(2).expect("test: valid push");
vec.push(3).expect("test: valid push");
assert_eq!(vec.pop(), Some(3));
assert_eq!(vec.pop(), Some(2));
assert_eq!(vec.len(), 1);
}
#[test]
fn test_aligned_vec_clear() {
let mut vec = AlignedVec::with_capacity(5).expect("test: valid AlignedVec creation");
vec.push(1).expect("test: valid push");
vec.push(2).expect("test: valid push");
vec.clear();
assert_eq!(vec.len(), 0);
assert!(vec.is_empty());
}
#[test]
fn test_raw_alloc() {
unsafe {
let ptr = aligned_alloc(1024, 64);
assert!(!ptr.is_null());
assert!(is_aligned(ptr, 64));
aligned_dealloc(ptr, 1024, 64);
}
}
#[test]
fn test_simd_alignment_detection() {
let alignment = optimal_simd_alignment();
assert!(alignment >= 16);
assert!(alignment.is_power_of_two());
}
}