use std::alloc::{Layout, alloc_zeroed, dealloc, handle_alloc_error};
use std::ptr::NonNull;
pub(super) struct AlignedBuffer<T> {
ptr: NonNull<T>,
len: usize,
layout: Layout,
}
impl<T: Copy + Default> AlignedBuffer<T> {
pub(super) fn new_zeroed(len: usize) -> Self {
let size = len * size_of::<T>();
let layout = Layout::from_size_align(size.max(1), 64).expect("valid layout");
let raw = unsafe { alloc_zeroed(layout) };
let ptr = NonNull::new(raw as *mut T).unwrap_or_else(|| handle_alloc_error(layout));
AlignedBuffer { ptr, len, layout }
}
pub(super) fn try_new_zeroed(len: usize) -> Option<Self> {
let size = len.checked_mul(size_of::<T>())?;
let layout = Layout::from_size_align(size.max(1), 64.max(align_of::<T>())).ok()?;
let ptr = NonNull::new(unsafe { alloc_zeroed(layout) } as *mut T)?;
Some(Self { ptr, len, layout })
}
#[allow(dead_code)]
#[inline(always)]
pub(super) fn as_ptr(&self) -> *const T {
self.ptr.as_ptr()
}
#[inline(always)]
pub(super) fn as_slice(&self) -> &[T] {
unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
}
#[inline(always)]
pub(super) fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
}
}
impl<T> Drop for AlignedBuffer<T> {
fn drop(&mut self) {
unsafe { dealloc(self.ptr.as_ptr() as *mut u8, self.layout) }
}
}
impl<T: Copy + Default> Clone for AlignedBuffer<T> {
fn clone(&self) -> Self {
let new_buf = AlignedBuffer::new_zeroed(self.len);
unsafe {
std::ptr::copy_nonoverlapping(self.ptr.as_ptr(), new_buf.ptr.as_ptr(), self.len);
}
new_buf
}
}
impl<T: Copy + Default> std::ops::Deref for AlignedBuffer<T> {
type Target = [T];
#[inline(always)]
fn deref(&self) -> &[T] {
self.as_slice()
}
}
impl<T: Copy + Default> std::ops::DerefMut for AlignedBuffer<T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
impl<T: Copy + Default + std::fmt::Debug> std::fmt::Debug for AlignedBuffer<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"AlignedBuffer<{}>(len={})",
std::any::type_name::<T>(),
self.len
)
}
}
unsafe impl<T: Send + Copy + Default> Send for AlignedBuffer<T> {}
unsafe impl<T: Sync + Copy + Default> Sync for AlignedBuffer<T> {}