use crate::*;
use crate::meta::*;
use core::alloc::Layout;
use core::cell::Cell;
use core::fmt::{self, Debug, Formatter};
use core::mem::MaybeUninit;
use core::ptr::NonNull;
pub struct Bump<'a> {
buffer: Cell<&'a mut [MaybeUninit<u8>]>,
#[cfg(debug_assertions)] outstanding_allocs: Cell<usize>,
}
impl<'a> Debug for Bump<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
#[cfg( debug_assertions )] return write!(f, "Bump {{ buffer: [...{} bytes], outstanding_allocs: {} }}", self.available(), self.outstanding_allocs.get());
#[cfg(not(debug_assertions))] return write!(f, "Bump {{ buffer: [...{} bytes], outstanding_allocs: ?? }}", self.available());
}
}
impl<'a> Bump<'a> {
pub fn from_array<const N: usize>(array: &'a mut MaybeUninit<[MaybeUninit<u8>; N]>) -> Self {
let array : &mut [MaybeUninit<u8>; N] = unsafe { array.assume_init_mut() };
Self::new(&mut array[..])
}
pub fn new(buffer: &'a mut [MaybeUninit<u8>]) -> Self {
Self {
buffer: Cell::new(buffer),
#[cfg(debug_assertions)] outstanding_allocs: Cell::new(0),
}
}
fn available(&self) -> usize {
let b = self.buffer.take();
let len = b.len();
self.buffer.set(b);
len
}
}
impl<'a> Drop for Bump<'a> {
fn drop(&mut self) {
#[cfg(debug_assertions)] assert_eq!(0, self.outstanding_allocs.get(), "allocator::simple::Bump has outstanding allocations");
}
}
impl<'a> Meta for Bump<'a> {
type Error = ();
const MAX_ALIGN : Alignment = Alignment::MAX;
const MAX_SIZE : usize = usize::MAX;
const ZST_SUPPORTED : bool = true;
}
impl ZstSupported for Bump<'_> {}
unsafe impl ZstInfalliable for Bump<'_> {}
unsafe impl<'a> fat::Alloc for Bump<'a> {
fn alloc_uninit(&self, layout: Layout) -> Result<crate::AllocNN, Self::Error> {
let align = layout.align();
let size = layout.size();
let _ = Alignment::from(layout); if size == 0 {
#[cfg(debug_assertions)] self.outstanding_allocs.set(self.outstanding_allocs.get() + 1);
return Ok(crate::util::nn::dangling(layout));
}
let buffer = self.buffer.take();
let align_mask = align.wrapping_sub(1);
let misalign = align_mask & (buffer.as_ptr() as usize);
if misalign == 0 {
if buffer.len() < size { self.buffer.set(buffer);
Err(())
} else {
let (alloc, unalloc) = buffer.split_at_mut(size);
#[cfg(debug_assertions)] self.outstanding_allocs.set(self.outstanding_allocs.get() + 1);
self.buffer.set(unalloc);
Ok(unsafe { NonNull::new_unchecked(alloc.as_mut_ptr()) })
}
} else {
let skip = align - misalign;
if skip.saturating_add(size) > buffer.len() {
self.buffer.set(buffer);
Err(())
} else {
let (alloc, unalloc) = buffer[skip..].split_at_mut(size);
#[cfg(debug_assertions)] self.outstanding_allocs.set(self.outstanding_allocs.get() + 1);
self.buffer.set(unalloc);
Ok(unsafe { NonNull::new_unchecked(alloc.as_mut_ptr()) })
}
}
}
}
unsafe impl<'a> fat::Free for Bump<'a> {
unsafe fn free(&self, _ptr: crate::AllocNN, _layout: Layout) {
#[cfg(debug_assertions)] self.outstanding_allocs.set(self.outstanding_allocs.get() - 1);
}
}
unsafe impl<'a> fat::Realloc for Bump<'a> {
}
#[no_implicit_prelude] mod cleanroom {
use crate::impls;
use super::Bump;
impls! {
unsafe impl core::alloc::GlobalAlloc for Bump<'static> => ialloc::fat::Realloc;
unsafe impl['o] core::alloc::GlobalAlloc for &'o Bump<'static> => core::ops::Deref;
}
#[cfg(allocator_api = "1.50")] impls! {
unsafe impl['a] core::alloc::Allocator(unstable 1.50) for Bump<'a> => ialloc::fat::Realloc;
}
}
#[test] fn test_quick() {
use crate::boxed::ABox;
use std::dbg;
let mut buffer : MaybeUninit<[_; 4096]> = MaybeUninit::uninit();
let alloc = Bump::from_array(&mut buffer);
let _u = ABox::try_new_in(1u32, &alloc).unwrap();
let _8_1 = ABox::try_new_in(2u8, &alloc).unwrap();
let _8_2 = ABox::try_new_in(3u8, &alloc).unwrap();
let _8_3 = ABox::try_new_in(4u8, &alloc).unwrap();
let _i = ABox::try_new_in(5i32, &alloc).unwrap();
let _b = ABox::try_new_in(true, &alloc).unwrap();
dbg!(&*_u as *const _);
dbg!(&*_8_1 as *const _);
dbg!(&*_8_2 as *const _);
dbg!(&*_8_3 as *const _);
dbg!(&*_i as *const _);
dbg!(&*_b as *const _);
dbg!(_u);
dbg!(_8_1);
dbg!(_8_2);
dbg!(_8_3);
dbg!(_i);
dbg!(_b);
while let Ok(_) = ABox::try_new_in(1u8, &alloc) {}
}
#[test] fn fat_alignment() { fat::test::alignment(&Bump::from_array(&mut MaybeUninit::new([(); 131072].map(|_| MaybeUninit::<u8>::new(0xFF))))) }
#[test] fn fat_edge_case_sizes() { fat::test::edge_case_sizes(&Bump::from_array(&mut MaybeUninit::new([(); 131072].map(|_| MaybeUninit::<u8>::new(0xFF))))) }
#[test] fn fat_uninit() { unsafe { fat::test::uninit_alloc_unsound(&Bump::from_array(&mut MaybeUninit::new([(); 131072].map(|_| MaybeUninit::<u8>::new(0xFF))))) } }
#[test] fn fat_uninit_realloc() { fat::test::uninit_realloc(&Bump::from_array(&mut MaybeUninit::new([(); 131072].map(|_| MaybeUninit::<u8>::new(0xFF))))) }
#[test] fn fat_zeroed() { fat::test::zeroed_alloc(&Bump::from_array(&mut MaybeUninit::new([(); 131072].map(|_| MaybeUninit::<u8>::new(0xFF))))) }
#[test] fn fat_zeroed_realloc() { fat::test::zeroed_realloc(&Bump::from_array(&mut MaybeUninit::new([(); 131072].map(|_| MaybeUninit::<u8>::new(0xFF))))) }
#[test] fn fat_zst_support() { fat::test::zst_supported_accurate(&Bump::from_array(&mut MaybeUninit::new([(); 131072].map(|_| MaybeUninit::<u8>::new(0xFF))))) }