subms_arena_allocator/
lib.rs1use std::alloc::{Layout, alloc, dealloc};
23use std::ptr;
24
25pub struct Bump {
27 ptr: *mut u8,
28 layout: Layout,
29 cursor: usize,
30}
31
32impl Bump {
33 pub fn new() -> Self {
35 Self::with_capacity(4096)
36 }
37
38 pub fn with_capacity(capacity: usize) -> Self {
41 let capacity = capacity.max(64);
42 let layout = Layout::from_size_align(capacity, 16).expect("layout");
43 let ptr = unsafe { alloc(layout) };
44 assert!(!ptr.is_null(), "OOM allocating arena chunk");
45 Self {
46 ptr,
47 layout,
48 cursor: 0,
49 }
50 }
51
52 pub fn alloc_copy<T: Copy>(&mut self, value: T) -> &mut T {
54 let cursor = self.cursor;
55 let cap = self.layout.size();
56 match self.try_alloc_copy(value) {
57 Some(r) => r,
58 None => panic!(
59 "Bump out of capacity: cursor={} layout_size={} requested={}",
60 cursor,
61 cap,
62 std::mem::size_of::<T>(),
63 ),
64 }
65 }
66
67 pub fn try_alloc_copy<T: Copy>(&mut self, value: T) -> Option<&mut T> {
70 let layout = Layout::new::<T>();
71 let p = self.try_alloc_raw(layout)?;
72 unsafe {
73 ptr::write(p as *mut T, value);
74 Some(&mut *(p as *mut T))
75 }
76 }
77
78 pub fn alloc_raw(&mut self, layout: Layout) -> *mut u8 {
81 let cursor = self.cursor;
82 let cap = self.layout.size();
83 let requested = layout.size();
84 match self.try_alloc_raw(layout) {
85 Some(p) => p,
86 None => panic!(
87 "Bump out of capacity: cursor={cursor} layout_size={cap} requested={requested}",
88 ),
89 }
90 }
91
92 pub fn try_alloc_raw(&mut self, layout: Layout) -> Option<*mut u8> {
94 let size = layout.size();
95 let align = layout.align();
96 let base = self.ptr as usize;
97 let aligned_abs = align_up(base + self.cursor, align);
98 let aligned = aligned_abs - base;
99 let end = aligned.checked_add(size)?;
100 if end > self.layout.size() {
101 return None;
102 }
103 self.cursor = end;
104 Some(unsafe { self.ptr.add(aligned) })
105 }
106
107 pub fn reset(&mut self) {
109 self.cursor = 0;
110 }
111
112 pub fn used(&self) -> usize {
114 self.cursor
115 }
116
117 pub fn capacity(&self) -> usize {
119 self.layout.size()
120 }
121
122 pub fn total_capacity(&self) -> usize {
124 self.capacity()
125 }
126}
127
128impl Default for Bump {
129 fn default() -> Self {
130 Self::new()
131 }
132}
133
134impl Drop for Bump {
135 fn drop(&mut self) {
136 unsafe { dealloc(self.ptr, self.layout) };
137 }
138}
139
140#[inline]
142pub(crate) fn align_up(p: usize, align: usize) -> usize {
143 debug_assert!(align.is_power_of_two(), "alignment must be a power of two");
144 (p + align - 1) & !(align - 1)
145}
146
147#[cfg(feature = "harness")]
148pub mod recipe;
149
150#[cfg(any(
151 feature = "typed",
152 feature = "growable",
153 feature = "stats",
154 feature = "aligned",
155 feature = "freelist",
156))]
157pub mod features;
158
159#[cfg(feature = "aligned")]
160pub use features::aligned::AlignedBump;
161#[cfg(feature = "freelist")]
162pub use features::freelist::FreelistBump;
163#[cfg(feature = "growable")]
164pub use features::growable::GrowableBump;
165#[cfg(feature = "stats")]
166pub use features::stats::{BumpStats, StatsBump};
167#[cfg(feature = "typed")]
168pub use features::typed::TypedArena;