subms_arena_allocator/
lib.rs1use std::alloc::{Layout, alloc, dealloc};
35use std::ptr;
36
37pub struct Bump {
39 ptr: *mut u8,
40 layout: Layout,
41 cursor: usize,
42}
43
44impl Bump {
45 pub fn new() -> Self {
47 Self::with_capacity(4096)
48 }
49
50 pub fn with_capacity(capacity: usize) -> Self {
53 let capacity = capacity.max(64);
54 let layout = Layout::from_size_align(capacity, 16).expect("layout");
55 let ptr = unsafe { alloc(layout) };
56 assert!(!ptr.is_null(), "OOM allocating arena chunk");
57 Self {
58 ptr,
59 layout,
60 cursor: 0,
61 }
62 }
63
64 pub fn alloc_copy<T: Copy>(&mut self, value: T) -> &mut T {
66 let cursor = self.cursor;
67 let cap = self.layout.size();
68 match self.try_alloc_copy(value) {
69 Some(r) => r,
70 None => panic!(
71 "Bump out of capacity: cursor={} layout_size={} requested={}",
72 cursor,
73 cap,
74 std::mem::size_of::<T>(),
75 ),
76 }
77 }
78
79 pub fn try_alloc_copy<T: Copy>(&mut self, value: T) -> Option<&mut T> {
82 let layout = Layout::new::<T>();
83 let p = self.try_alloc_raw(layout)?;
84 unsafe {
85 ptr::write(p as *mut T, value);
86 Some(&mut *(p as *mut T))
87 }
88 }
89
90 pub fn alloc_raw(&mut self, layout: Layout) -> *mut u8 {
93 let cursor = self.cursor;
94 let cap = self.layout.size();
95 let requested = layout.size();
96 match self.try_alloc_raw(layout) {
97 Some(p) => p,
98 None => panic!(
99 "Bump out of capacity: cursor={cursor} layout_size={cap} requested={requested}",
100 ),
101 }
102 }
103
104 pub fn try_alloc_raw(&mut self, layout: Layout) -> Option<*mut u8> {
106 let size = layout.size();
107 let align = layout.align();
108 let base = self.ptr as usize;
109 let aligned_abs = align_up(base + self.cursor, align);
110 let aligned = aligned_abs - base;
111 let end = aligned.checked_add(size)?;
112 if end > self.layout.size() {
113 return None;
114 }
115 self.cursor = end;
116 Some(unsafe { self.ptr.add(aligned) })
117 }
118
119 pub fn reset(&mut self) {
121 self.cursor = 0;
122 }
123
124 pub fn used(&self) -> usize {
126 self.cursor
127 }
128
129 pub fn capacity(&self) -> usize {
131 self.layout.size()
132 }
133
134 pub fn total_capacity(&self) -> usize {
136 self.capacity()
137 }
138}
139
140impl Default for Bump {
141 fn default() -> Self {
142 Self::new()
143 }
144}
145
146impl Drop for Bump {
147 fn drop(&mut self) {
148 unsafe { dealloc(self.ptr, self.layout) };
149 }
150}
151
152#[inline]
154pub(crate) fn align_up(p: usize, align: usize) -> usize {
155 debug_assert!(align.is_power_of_two(), "alignment must be a power of two");
156 (p + align - 1) & !(align - 1)
157}
158
159#[cfg(feature = "harness")]
160pub mod recipe;
161
162#[cfg(any(
163 feature = "typed",
164 feature = "growable",
165 feature = "stats",
166 feature = "aligned",
167))]
168pub mod features;
169
170#[cfg(feature = "aligned")]
171pub use features::aligned::AlignedBump;
172#[cfg(feature = "growable")]
173pub use features::growable::GrowableBump;
174#[cfg(feature = "stats")]
175pub use features::stats::{BumpStats, StatsBump};
176#[cfg(feature = "typed")]
177pub use features::typed::{Slot, TypedArena};
178
179#[cfg(test)]
180#[path = "arena_tests.rs"]
181mod arena_tests;
182
183#[cfg(test)]
184#[path = "sample_app_tests.rs"]
185mod sample_app_tests;