use std::alloc::{Layout, alloc, dealloc};
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
use crate::common::diagnostics::NamErrorCode;
pub unsafe trait Zeroable: Copy {
fn is_zero(&self) -> bool;
}
macro_rules! impl_zeroable_int {
($($t:ty),*) => {
$(
unsafe impl Zeroable for $t {
#[inline(always)]
fn is_zero(&self) -> bool {
*self == 0
}
}
)*
};
}
impl_zeroable_int!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
unsafe impl Zeroable for f32 {
#[inline(always)]
fn is_zero(&self) -> bool {
self.to_bits() == 0
}
}
unsafe impl Zeroable for f64 {
#[inline(always)]
fn is_zero(&self) -> bool {
self.to_bits() == 0
}
}
#[repr(align(64))]
#[derive(Clone, Copy, Debug)]
pub struct Aligned64<T>(pub T);
impl<T> Deref for Aligned64<T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for Aligned64<T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T: Default> Default for Aligned64<T> {
#[inline(always)]
fn default() -> Self {
Aligned64(T::default())
}
}
#[derive(Debug)]
pub struct AlignedVec<T> {
ptr: NonNull<T>,
len: usize,
cap: usize,
}
impl<T> AlignedVec<T> {
pub const ALIGN: usize = 64;
fn alloc_slot(capacity: usize) -> Result<(*mut T, Layout), NamErrorCode> {
if capacity == 0 {
return Ok((NonNull::dangling().as_ptr(), Layout::new::<()>()));
}
let element_size = std::mem::size_of::<T>();
let byte_size = capacity
.checked_mul(element_size)
.ok_or(NamErrorCode::OutOfMemory)?;
let layout = Layout::from_size_align(byte_size, Self::ALIGN)
.map_err(|_| NamErrorCode::OutOfMemory)?;
let ptr = unsafe { alloc(layout) };
if ptr.is_null() {
return Err(NamErrorCode::OutOfMemory);
}
Ok((ptr as *mut T, layout))
}
pub fn new(len: usize, default: T) -> Result<Self, NamErrorCode>
where
T: Copy + Zeroable,
{
let mut vec = Self::with_capacity(len)?;
unsafe {
let ptr = vec.ptr.as_ptr();
if default.is_zero() {
std::ptr::write_bytes(ptr as *mut u8, 0u8, len * std::mem::size_of::<T>());
} else {
for i in 0..len {
ptr.add(i).write(default);
}
}
}
vec.len = len;
Ok(vec)
}
pub fn with_capacity(capacity: usize) -> Result<Self, NamErrorCode> {
let (ptr, _layout) = Self::alloc_slot(capacity)?;
Ok(Self {
ptr: NonNull::new(ptr).unwrap_or(NonNull::dangling()),
len: 0,
cap: capacity,
})
}
pub fn len(&self) -> usize {
self.len
}
pub fn cap(&self) -> usize {
self.cap
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn resize(&mut self, new_len: usize, default: T) -> Result<(), NamErrorCode>
where
T: Copy + Zeroable,
{
if new_len <= self.len {
return Ok(());
}
let mut new_vec = Self::with_capacity(new_len)?;
unsafe {
let old_ptr = self.ptr.as_ptr();
let new_ptr = new_vec.ptr.as_ptr();
std::ptr::copy_nonoverlapping(old_ptr, new_ptr, self.len);
if default.is_zero() {
let fill_start = new_ptr.add(self.len) as *mut u8;
let fill_bytes = (new_len - self.len) * std::mem::size_of::<T>();
std::ptr::write_bytes(fill_start, 0u8, fill_bytes);
} else {
for i in self.len..new_len {
new_ptr.add(i).write(default);
}
}
}
new_vec.len = new_len;
let old = std::mem::replace(self, new_vec);
drop(old);
Ok(())
}
pub fn from_vec(v: Vec<T>) -> Result<Self, NamErrorCode>
where
T: Copy,
{
if v.is_empty() {
return Self::with_capacity(0);
}
let mut aligned = Self::with_capacity(v.len())?;
unsafe {
std::ptr::copy_nonoverlapping(v.as_ptr(), aligned.ptr.as_ptr(), v.len());
}
aligned.len = v.len();
Ok(aligned)
}
}
impl<T> Deref for AlignedVec<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
if self.len == 0 {
&[]
} else {
unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
}
}
}
impl<T> DerefMut for AlignedVec<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
if self.len == 0 {
&mut []
} else {
unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
}
}
}
impl<T> Drop for AlignedVec<T> {
fn drop(&mut self) {
if self.cap > 0 {
if let Ok(layout) =
Layout::from_size_align(self.cap * std::mem::size_of::<T>(), Self::ALIGN)
{
unsafe {
dealloc(self.ptr.as_ptr() as *mut u8, layout);
}
}
}
}
}
impl<T: Copy> Clone for AlignedVec<T> {
fn clone(&self) -> Self {
let (ptr, _layout) = Self::alloc_slot(self.len)
.expect("clone: layout identical to validated original allocation");
let mut new_vec = Self {
ptr: NonNull::new(ptr).unwrap_or(NonNull::dangling()),
len: 0,
cap: self.len,
};
unsafe {
std::ptr::copy_nonoverlapping(self.ptr.as_ptr(), new_vec.ptr.as_ptr(), self.len);
}
new_vec.len = self.len;
new_vec
}
}
unsafe impl<T: Send> Send for AlignedVec<T> {}
unsafe impl<T: Sync> Sync for AlignedVec<T> {}
#[cfg(test)]
#[path = "aligned_test.rs"]
mod tests;