use crate::CapacityError;
use crate::CAPACITY;
use core::mem::MaybeUninit;
const PADS: usize = ((CAPACITY - 1) / 8) + 1;
pub struct PackedSlab<T> {
buffer: [MaybeUninit<T>; CAPACITY],
pads: [u8; PADS],
}
impl<T> PackedSlab<T> {
pub fn new() -> Self {
Self {
buffer: unsafe { MaybeUninit::<[MaybeUninit<T>; CAPACITY]>::uninit().assume_init() },
pads: [0u8; PADS],
}
}
fn find_uninitialized_and_claim(&mut self) -> Option<usize> {
for (pad_i, pad) in self.pads.iter_mut().enumerate() {
if !*pad != 0u8 {
let bit_i = (!*pad).trailing_zeros();
let res = pad_i * 8 + bit_i as usize;
*pad |= 1 << bit_i;
return Some(res);
}
}
None
}
pub fn insert(&mut self, x: T) -> Result<(usize, &mut T), CapacityError> {
if let Some(i) = self.find_uninitialized_and_claim() {
let ptr = self.buffer[i].as_mut_ptr();
unsafe {
ptr.write(x);
Ok((i, &mut *ptr))
}
} else {
Err(CapacityError)
}
}
fn idx(i: usize) -> (usize, usize) {
(i / 8, i % 8)
}
pub fn exists(&self, i: usize) -> bool {
let (pad_i, bit_i) = Self::idx(i);
self.pads[pad_i] & 1 << bit_i != 0
}
pub fn get_mut(&mut self, i: usize) -> Option<&mut T> {
if i > CAPACITY {
return None;
}
if self.exists(i) {
Some(unsafe { &mut *self.buffer[i].as_mut_ptr() })
} else {
None
}
}
#[allow(unused)]
pub fn get_ref(&self, i: usize) -> Option<&T> {
if i > CAPACITY {
return None;
}
if self.exists(i) {
Some(unsafe { &*self.buffer[i].as_ptr() })
} else {
None
}
}
pub unsafe fn get_ref_unchecked(&self, i: usize) -> &T {
&*self.buffer[i].as_ptr()
}
#[allow(unused)]
pub unsafe fn get_mut_unchecked(&mut self, i: usize) -> &mut T {
&mut *self.buffer[i].as_mut_ptr()
}
pub fn remove(&mut self, i: usize) -> Option<()> {
if i > CAPACITY {
return None;
}
let (pad_i, bit_i) = Self::idx(i);
if self.pads[pad_i] & 1 << bit_i != 0 {
drop(unsafe { &mut *self.buffer[i].as_mut_ptr() });
self.pads[pad_i] &= !(1 << bit_i);
Some(())
} else {
None
}
}
}