use crate::*;
use crate::align::alignn::_align_impl::ValidAlignLessThan1GiB;
use crate::meta::*;
use core::cell::*;
use core::fmt::{self, Debug, Formatter};
use core::mem::MaybeUninit;
use core::ptr::NonNull;
pub struct FixedPoolLinearProbe<const A: usize, const B: usize, const N: usize> where [(); A] : ValidAlignLessThan1GiB {
buffer: [Element<A, B>; N],
state: [Cell<State>; N], next: Cell<usize>,
}
impl<const A: usize, const B: usize, const N: usize> FixedPoolLinearProbe<A, B, N> where [(); A] : ValidAlignLessThan1GiB {
pub fn new() -> Self {
Self {
#[allow(clippy::uninit_assumed_init)] buffer: unsafe { MaybeUninit::uninit().assume_init() },
state: [(); N].map(|_| Cell::new(State::Free)), next: Cell::new(0),
}
}
unsafe fn live_or_dead_index_of(&self, ptr: AllocNN) -> usize {
let index = unsafe { ptr.as_ptr().cast::<Element<A, B>>().offset_from(self.buffer.as_ptr()) } as usize;
if cfg!(debug_assertions) && index >= self.state.len() { bug::ub::invalid_ptr_for_allocator(ptr) }
index
}
unsafe fn state_of(&self, ptr: AllocNN) -> &Cell<State> {
let index = unsafe { self.live_or_dead_index_of(ptr) };
let state = unsafe { self.state.get_unchecked(index) };
state
}
}
impl<const A: usize, const B: usize, const N: usize> Default for FixedPoolLinearProbe<A, B, N> where [(); A] : ValidAlignLessThan1GiB {
fn default() -> Self { Self::new() }
}
impl<const A: usize, const B: usize, const N: usize> Debug for FixedPoolLinearProbe<A, B, N> where [(); A] : ValidAlignLessThan1GiB {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "FixedBool<{A}, {B}, {N}> {{ ... }}") }
}
impl<const A: usize, const B: usize, const N: usize> Meta for &'_ FixedPoolLinearProbe<A, B, N> where [(); A] : ValidAlignLessThan1GiB {
type Error = ();
const MAX_ALIGN : Alignment = Alignment::constant(A);
const MAX_SIZE : usize = B;
const ZST_SUPPORTED : bool = true;
}
impl<const A: usize, const B: usize, const N: usize> ZstSupported for &'_ FixedPoolLinearProbe<A, B, N> where [(); A] : ValidAlignLessThan1GiB {}
unsafe impl<const A: usize, const B: usize, const N: usize> thin::Alloc for &'_ FixedPoolLinearProbe<A, B, N> where [(); A] : ValidAlignLessThan1GiB {
fn alloc_uninit(&self, size: usize) -> Result<AllocNN, Self::Error> {
if size > B { return Err(()) }
let start = self.next.get();
let mut pos = start;
for states in [&self.state[..], &self.state[..start]] {
while let Some(state) = states.get(pos) {
match state.get() {
State::Free => { state.set(State::Allocated);
self.next.set(pos+1);
return NonNull::new(self.buffer[pos].get().cast()).ok_or(())
},
State::Allocated => pos += 1,
}
}
pos = 0; }
Err(())
}
}
unsafe impl<const A: usize, const B: usize, const N: usize> thin::Free for &'_ FixedPoolLinearProbe<A, B, N> where [(); A] : ValidAlignLessThan1GiB {
unsafe fn free(&self, ptr: AllocNN) {
let state = unsafe { self.state_of(ptr) };
if cfg!(debug_assertions) && state.get() == State::Free { bug::ub::freed_ptr_for_allocator(ptr) }
state.set(State::Free);
}
}
unsafe impl<const A: usize, const B: usize, const N: usize> thin::Realloc for &'_ FixedPoolLinearProbe<A, B, N> where [(); A] : ValidAlignLessThan1GiB {
const CAN_REALLOC_ZEROED : bool = false;
unsafe fn realloc_uninit(&self, ptr: AllocNN, new_size: usize) -> Result<AllocNN, Self::Error> {
if cfg!(debug_assertions) && unsafe { self.state_of(ptr) }.get() == State::Free { bug::ub::freed_ptr_for_allocator(ptr) } if new_size > B { return Err(()) } Ok(ptr) }
unsafe fn realloc_zeroed(&self, ptr: AllocNN, new_size: usize) -> Result<AllocNN, Self::Error> {
let _ = (ptr, new_size);
Err(())
}
}
#[no_implicit_prelude] mod cleanroom {
use crate::impls;
use super::{FixedPoolLinearProbe, ValidAlignLessThan1GiB};
impls! {
unsafe impl['a, const A: usize, const B: usize, const N: usize] ialloc::fat::Alloc for &'a FixedPoolLinearProbe<A, B, N> where [[(); A] : ValidAlignLessThan1GiB] => ialloc::thin::Alloc;
unsafe impl['a, const A: usize, const B: usize, const N: usize] ialloc::fat::Realloc for &'a FixedPoolLinearProbe<A, B, N> where [[(); A] : ValidAlignLessThan1GiB] => ialloc::thin::Realloc;
unsafe impl['a, const A: usize, const B: usize, const N: usize] ialloc::fat::Free for &'a FixedPoolLinearProbe<A, B, N> where [[(); A] : ValidAlignLessThan1GiB] => ialloc::thin::Free;
}
}
type Element<const A : usize, const B : usize> = UnsafeCell<MaybeUninit<AlignN<A, [u8; B]>>>;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(u8)] enum State { #[default] Free = 0, Allocated }
#[test] fn test_quick() {
use crate::boxed::ABox;
let pool = FixedPoolLinearProbe::<4, 4, 1024>::new();
let mut next = 0_u32;
for _ in 0 .. 10 {
assert!(ABox::try_new_in([0u8; 8], &pool).is_err(), "element too big to fit in pool");
let _integers = [(); 1024].map(|_| {
next += 1;
ABox::try_new_in(next, &pool).unwrap()
});
assert!(ABox::try_new_in(0u32, &pool).is_err(), "pool out of elements");
let _ = &_integers[0];
#[cfg(feature = "std")] std::dbg!(&_integers[0]);
}
}
#[test] fn thin_alignment() { thin::test::alignment(&FixedPoolLinearProbe::<4, 4, 1024>::new()) }
#[test] fn thin_edge_case_sizes() { thin::test::edge_case_sizes(&FixedPoolLinearProbe::<4, 4, 1024>::new()) }
#[test] fn thin_nullable() { thin::test::nullable(&FixedPoolLinearProbe::<4, 4, 1024>::new()) }
#[test] fn thin_uninit() { unsafe { thin::test::uninit_alloc_unsound(&FixedPoolLinearProbe::<4, 4, 128>::new()) } }
#[test] fn thin_uninit_realloc() { thin::test::uninit_realloc(&FixedPoolLinearProbe::<4, 4, 128>::new()) }
#[test] fn thin_zeroed() { thin::test::zeroed_alloc(&FixedPoolLinearProbe::<4, 4, 128>::new()) }
#[test] fn thin_zeroed_realloc() { thin::test::zeroed_realloc(&FixedPoolLinearProbe::<4, 4, 128>::new()) }
#[test] fn thin_zst_support() { thin::test::zst_supported_accurate(&FixedPoolLinearProbe::<4, 4, 1024>::new()) }
#[test] fn fat_alignment() { fat::test::alignment(&FixedPoolLinearProbe::<4, 4, 1024>::new()) }
#[test] fn fat_edge_case_sizes() { fat::test::edge_case_sizes(&FixedPoolLinearProbe::<4, 4, 1024>::new()) }
#[test] fn fat_uninit() { unsafe { fat::test::uninit_alloc_unsound(&FixedPoolLinearProbe::<4, 4, 128>::new()) } }
#[test] fn fat_uninit_realloc() { fat::test::uninit_realloc(&FixedPoolLinearProbe::<4, 4, 128>::new()) }
#[test] fn fat_zeroed() { fat::test::zeroed_alloc(&FixedPoolLinearProbe::<4, 4, 128>::new()) }
#[test] fn fat_zeroed_realloc() { fat::test::zeroed_realloc(&FixedPoolLinearProbe::<4, 4, 128>::new()) }
#[test] fn fat_zst_support() { fat::test::zst_supported_accurate(&FixedPoolLinearProbe::<4, 4, 1024>::new()) }