use std::alloc::{Layout, alloc, dealloc};
use std::ptr;
pub struct Bump {
ptr: *mut u8,
layout: Layout,
cursor: usize,
}
impl Bump {
pub fn new() -> Self {
Self::with_capacity(4096)
}
pub fn with_capacity(capacity: usize) -> Self {
let capacity = capacity.max(64);
let layout = Layout::from_size_align(capacity, 16).expect("layout");
let ptr = unsafe { alloc(layout) };
assert!(!ptr.is_null(), "OOM allocating arena chunk");
Self {
ptr,
layout,
cursor: 0,
}
}
pub fn alloc_copy<T: Copy>(&mut self, value: T) -> &mut T {
let cursor = self.cursor;
let cap = self.layout.size();
match self.try_alloc_copy(value) {
Some(r) => r,
None => panic!(
"Bump out of capacity: cursor={} layout_size={} requested={}",
cursor,
cap,
std::mem::size_of::<T>(),
),
}
}
pub fn try_alloc_copy<T: Copy>(&mut self, value: T) -> Option<&mut T> {
let layout = Layout::new::<T>();
let p = self.try_alloc_raw(layout)?;
unsafe {
ptr::write(p as *mut T, value);
Some(&mut *(p as *mut T))
}
}
pub fn alloc_raw(&mut self, layout: Layout) -> *mut u8 {
let cursor = self.cursor;
let cap = self.layout.size();
let requested = layout.size();
match self.try_alloc_raw(layout) {
Some(p) => p,
None => panic!(
"Bump out of capacity: cursor={cursor} layout_size={cap} requested={requested}",
),
}
}
pub fn try_alloc_raw(&mut self, layout: Layout) -> Option<*mut u8> {
let size = layout.size();
let align = layout.align();
let base = self.ptr as usize;
let aligned_abs = align_up(base + self.cursor, align);
let aligned = aligned_abs - base;
let end = aligned.checked_add(size)?;
if end > self.layout.size() {
return None;
}
self.cursor = end;
Some(unsafe { self.ptr.add(aligned) })
}
pub fn reset(&mut self) {
self.cursor = 0;
}
pub fn used(&self) -> usize {
self.cursor
}
pub fn capacity(&self) -> usize {
self.layout.size()
}
pub fn total_capacity(&self) -> usize {
self.capacity()
}
}
impl Default for Bump {
fn default() -> Self {
Self::new()
}
}
impl Drop for Bump {
fn drop(&mut self) {
unsafe { dealloc(self.ptr, self.layout) };
}
}
#[inline]
pub(crate) fn align_up(p: usize, align: usize) -> usize {
debug_assert!(align.is_power_of_two(), "alignment must be a power of two");
(p + align - 1) & !(align - 1)
}
#[cfg(feature = "harness")]
pub mod recipe;
#[cfg(any(
feature = "typed",
feature = "growable",
feature = "stats",
feature = "aligned",
feature = "freelist",
))]
pub mod features;
#[cfg(feature = "aligned")]
pub use features::aligned::AlignedBump;
#[cfg(feature = "freelist")]
pub use features::freelist::FreelistBump;
#[cfg(feature = "growable")]
pub use features::growable::GrowableBump;
#[cfg(feature = "stats")]
pub use features::stats::{BumpStats, StatsBump};
#[cfg(feature = "typed")]
pub use features::typed::TypedArena;