use std::{
alloc::{self, GlobalAlloc, System},
ptr::NonNull,
};
use super::{Arena, ChunkFooter, utils::is_pointer_aligned_to};
impl<const MIN_ALIGN: usize> Arena<MIN_ALIGN> {
pub fn reset(&mut self) {
#[cfg(all(feature = "track_allocations", not(feature = "disable_track_allocations")))]
self.stats.reset();
unsafe {
let Some(current_footer_ptr) = self.current_chunk_footer_ptr.get() else {
return;
};
let prev_footer_ptr =
current_footer_ptr.as_ref().previous_chunk_footer_ptr.replace(None);
dealloc_chunk_list(prev_footer_ptr);
debug_assert!(
is_pointer_aligned_to(current_footer_ptr, MIN_ALIGN),
"bump pointer {current_footer_ptr:#p} should be aligned to the minimum alignment of {MIN_ALIGN:#x}"
);
self.cursor_ptr.set(current_footer_ptr.cast::<u8>());
debug_assert!(
current_footer_ptr.as_ref().previous_chunk_footer_ptr.get().is_none(),
"We should only have a single chunk"
);
debug_assert_eq!(
self.cursor_ptr.get(),
current_footer_ptr.cast::<u8>(),
"Our chunk's bump cursor should be reset to the start of its allocation"
);
}
}
}
impl<const MIN_ALIGN: usize> Drop for Arena<MIN_ALIGN> {
fn drop(&mut self) {
unsafe {
dealloc_chunk_list(self.current_chunk_footer_ptr.get());
}
}
}
#[inline]
unsafe fn dealloc_chunk_list(footer_ptr: Option<NonNull<ChunkFooter>>) {
let mut next_footer_ptr = footer_ptr;
while let Some(footer_ptr) = next_footer_ptr {
{
next_footer_ptr = unsafe { footer_ptr.as_ref() }.previous_chunk_footer_ptr.get();
}
unsafe { dealloc_arena_chunk(footer_ptr) };
}
}
pub unsafe fn dealloc_arena_chunk(footer_ptr: NonNull<ChunkFooter>) {
let (backing_alloc_ptr, layout, is_fixed_size) = {
let footer = unsafe { footer_ptr.as_ref() };
(footer.backing_alloc_ptr.as_ptr(), footer.layout, footer.is_fixed_size)
};
if is_fixed_size {
unsafe { System.dealloc(backing_alloc_ptr, layout) };
} else {
unsafe { alloc::dealloc(backing_alloc_ptr, layout) };
}
}