use super::alloc::*;
use core::ops::{Index, IndexMut};
pub const NULL: usize = core::usize::MAX;
pub fn block_max_len<E, L>() -> usize {
use core::mem::size_of;
let elem_size = size_of::<E>();
let label_size = size_of::<L>();
if elem_size == 0 {
core::usize::MAX - 1
} else {
(core::usize::MAX - label_size) / elem_size - 1
}
}
#[cfg(test)]
fn check_null_tp<E, L>(arr: &TPArrayBlock<E, L>, message: &'static str) {
assert!(
arr as *const TPArrayBlock<E, L> as usize != NULL && arr.len != NULL,
message
);
}
#[cfg(test)]
fn check_null_fp<E, L>(arr: &FPArrayBlock<E, L>, message: &'static str) {
assert!(
arr.elements.len() != NULL && (&arr.label as *const L as usize) != NULL,
message
);
}
#[repr(C)]
pub struct TPArrayBlock<E, L = ()> {
pub label: L,
len: usize,
elements: E,
}
impl<E, L> TPArrayBlock<E, L> {
pub fn memory_layout(len: usize) -> (usize, usize) {
let l_layout = size_align::<L>();
let d_layout = size_align_array::<E>(len);
size_align_multiple(&[l_layout, size_align::<usize>(), d_layout])
}
pub unsafe fn dealloc<'a>(&'a mut self) {
#[cfg(test)]
check_null_tp(self, "TPArrayBlock::dealloc: Deallocating null pointer!");
let (size, align) = TPArrayBlock::<E, L>::memory_layout(self.len);
deallocate(self, size, align);
}
pub unsafe fn new_ptr_unsafe<'a>(label: L, len: usize) -> &'a mut Self {
let (size, align) = Self::memory_layout(len);
let new_ptr = allocate::<Self>(size, align);
new_ptr.label = label;
new_ptr.len = len;
#[cfg(test)]
check_null_tp(
new_ptr,
"TPArrayBlock::new_ptr_unsafe: Allocated null pointer!",
);
new_ptr
}
pub unsafe fn null_ptr() -> *mut Self {
NULL as *mut Self
}
pub fn is_null(&self) -> bool {
self as *const Self as usize == NULL
}
pub fn new_ptr<'a, F>(label: L, len: usize, mut func: F) -> &'a mut Self
where
F: FnMut(&mut L, usize) -> E,
{
assert!(len <= block_max_len::<E, L>());
let new_ptr = unsafe { Self::new_ptr_unsafe(label, len) };
for i in 0..new_ptr.len {
new_ptr[i] = func(&mut new_ptr.label, i);
}
new_ptr
}
#[inline]
pub fn get<'a>(&'a self, idx: usize) -> &'a E {
#[cfg(test)]
check_null_tp(self, "TPArrayBlock::get: Immutable access of null pointer!");
assert!(idx < self.len);
unsafe { self.unchecked_access(idx) }
}
#[inline]
pub fn get_mut<'a>(&'a mut self, idx: usize) -> &'a mut E {
#[cfg(test)]
check_null_tp(
self,
"TPArrayBlock::get_mut: Mutable access of null pointer!",
);
assert!(idx < self.len);
unsafe { self.unchecked_access(idx) }
}
#[inline]
pub unsafe fn unchecked_access<'a>(&'a self, idx: usize) -> &'a mut E {
#[cfg(test)]
check_null_tp(
self,
"TPArrayBlock::unchecked_access: Memory access on null pointer!",
);
let element = &self.elements as *const E as *mut E;
let element = element.add(idx);
&mut *element
}
#[inline]
pub fn len(&self) -> usize {
#[cfg(test)]
check_null_tp(self, "TPArrayBlock::len: Length check of null pointer!");
self.len
}
}
impl<E, L> TPArrayBlock<E, L>
where
E: Default,
{
#[inline]
pub fn new_ptr_default<'a>(label: L, len: usize) -> &'a mut Self {
let new_ptr = Self::new_ptr(label, len, |_, _| E::default());
new_ptr
}
}
impl<E, L> Index<usize> for TPArrayBlock<E, L> {
type Output = E;
#[inline]
fn index(&self, index: usize) -> &E {
self.get(index)
}
}
impl<E, L> IndexMut<usize> for TPArrayBlock<E, L> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut E {
self.get_mut(index)
}
}
impl<E, L> Clone for &mut TPArrayBlock<E, L>
where
L: Clone,
E: Clone,
{
#[inline]
fn clone(&self) -> Self {
let new_ptr =
TPArrayBlock::new_ptr(self.label.clone(), self.len(), |_, idx| self[idx].clone());
new_ptr
}
}
#[repr(C)]
pub struct FPArrayBlock<E, L = ()> {
pub label: L,
pub elements: [E],
}
impl<E, L> FPArrayBlock<E, L> {
pub unsafe fn new_ptr_unsafe<'a>(label: L, len: usize) -> &'a mut Self {
let l_layout = size_align::<L>();
let d_layout = size_align_array::<E>(len);
let (size, align) = size_align_multiple(&[l_layout, d_layout]);
let new_ptr = allocate::<E>(size, align);
let new_ptr = std::slice::from_raw_parts(new_ptr, len);
let new_ptr = &mut *(new_ptr as *const [E] as *mut [E] as *mut Self);
#[cfg(test)]
check_null_fp(
new_ptr,
"FPArrayBlock::new_ptr_unsafe: Allocated null pointer!",
);
new_ptr.label = label;
new_ptr
}
pub unsafe fn null_ptr() -> *mut Self {
let new_ptr = std::slice::from_raw_parts(NULL as *const E, NULL);
&mut *(new_ptr as *const [E] as *mut [E] as *mut Self)
}
pub fn is_null(&self) -> bool {
self.len() == NULL || (&self.label as *const L as usize) == NULL
}
pub fn new_ptr<'a, F>(label: L, len: usize, mut func: F) -> &'a mut Self
where
F: FnMut(&mut L, usize) -> E,
{
assert!(len <= block_max_len::<E, L>());
let new_ptr = unsafe { Self::new_ptr_unsafe(label, len) };
for i in 0..new_ptr.len() {
new_ptr[i] = func(&mut new_ptr.label, i);
}
new_ptr
}
#[inline]
pub fn get<'a>(&'a self, idx: usize) -> &'a E {
#[cfg(test)]
check_null_fp(self, "FPArrayBlock::get: Immutable access of null pointer!");
assert!(idx < self.len());
&self.elements[idx]
}
#[inline]
pub fn get_mut<'a>(&'a mut self, idx: usize) -> &'a mut E {
#[cfg(test)]
check_null_fp(
self,
"FPArrayBlock::get_mut: Mutable access of null pointer!",
);
assert!(idx < self.len());
&mut self.elements[idx]
}
#[inline]
pub unsafe fn unchecked_access(&self, idx: usize) -> &mut E {
#[cfg(test)]
check_null_fp(
self,
"FPArrayBlock::unchecked_access: Memory access of null pointer!",
);
let mut_self = &mut *(self as *const Self as *mut Self);
mut_self.elements.get_unchecked_mut(idx)
}
#[inline]
pub fn len(&self) -> usize {
#[cfg(test)]
check_null_fp(self, "FPArrayBlock::len: Length check on null pointer!");
self.elements.len()
}
}
impl<E, L> FPArrayBlock<E, L>
where
E: Default,
{
#[inline]
pub fn new_ptr_default<'a>(label: L, len: usize) -> &'a mut Self {
let new_ptr = Self::new_ptr(label, len, |_, _| E::default());
new_ptr
}
}
impl<E, L> Index<usize> for FPArrayBlock<E, L> {
type Output = E;
#[inline]
fn index(&self, index: usize) -> &E {
assert!(index < self.len());
self.get(index)
}
}
impl<E, L> IndexMut<usize> for FPArrayBlock<E, L> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut E {
self.get_mut(index)
}
}
impl<E, L> Clone for &mut FPArrayBlock<E, L>
where
L: Clone,
E: Clone,
{
#[inline]
fn clone(&self) -> Self {
let new_ptr =
FPArrayBlock::new_ptr(self.label.clone(), self.len(), |_, idx| self[idx].clone());
new_ptr
}
}