grafeo_common/memory/
bump.rs1use std::cell::Cell;
8use std::ptr::NonNull;
9
10pub struct BumpAllocator {
33 inner: bumpalo::Bump,
35 allocation_count: Cell<usize>,
37}
38
39impl BumpAllocator {
40 #[must_use]
42 pub fn new() -> Self {
43 Self {
44 inner: bumpalo::Bump::new(),
45 allocation_count: Cell::new(0),
46 }
47 }
48
49 #[must_use]
51 pub fn with_capacity(capacity: usize) -> Self {
52 Self {
53 inner: bumpalo::Bump::with_capacity(capacity),
54 allocation_count: Cell::new(0),
55 }
56 }
57
58 #[inline]
60 pub fn alloc<T>(&self, value: T) -> &mut T {
61 self.allocation_count.set(self.allocation_count.get() + 1);
62 self.inner.alloc(value)
63 }
64
65 #[inline]
67 pub fn alloc_slice_copy<T: Copy>(&self, values: &[T]) -> &mut [T] {
68 self.allocation_count.set(self.allocation_count.get() + 1);
69 self.inner.alloc_slice_copy(values)
70 }
71
72 #[inline]
74 pub fn alloc_slice_clone<T: Clone>(&self, values: &[T]) -> &mut [T] {
75 self.allocation_count.set(self.allocation_count.get() + 1);
76 self.inner.alloc_slice_clone(values)
77 }
78
79 #[inline]
81 pub fn alloc_str(&self, s: &str) -> &mut str {
82 self.allocation_count.set(self.allocation_count.get() + 1);
83 self.inner.alloc_str(s)
84 }
85
86 #[inline]
88 pub fn alloc_layout(&self, layout: std::alloc::Layout) -> NonNull<u8> {
89 self.allocation_count.set(self.allocation_count.get() + 1);
90 self.inner.alloc_layout(layout)
91 }
92
93 #[inline]
97 pub fn reset(&mut self) {
98 self.inner.reset();
99 self.allocation_count.set(0);
100 }
101
102 #[must_use]
104 #[inline]
105 pub fn allocated_bytes(&self) -> usize {
106 self.inner.allocated_bytes()
107 }
108
109 #[must_use]
111 #[inline]
112 pub fn allocation_count(&self) -> usize {
113 self.allocation_count.get()
114 }
115
116 #[must_use]
118 #[inline]
119 pub fn chunk_count(&mut self) -> usize {
120 self.inner.iter_allocated_chunks().count()
121 }
122}
123
124impl Default for BumpAllocator {
125 fn default() -> Self {
126 Self::new()
127 }
128}
129
130pub struct ScopedBump<'a> {
136 bump: &'a mut BumpAllocator,
137 start_bytes: usize,
138}
139
140impl<'a> ScopedBump<'a> {
141 pub fn new(bump: &'a mut BumpAllocator) -> Self {
143 let start_bytes = bump.allocated_bytes();
144 Self { bump, start_bytes }
145 }
146
147 #[inline]
149 pub fn alloc<T>(&self, value: T) -> &mut T {
150 self.bump.alloc(value)
151 }
152
153 #[must_use]
155 pub fn scope_allocated_bytes(&self) -> usize {
156 self.bump.allocated_bytes() - self.start_bytes
157 }
158}
159
160impl Drop for ScopedBump<'_> {
161 fn drop(&mut self) {
162 }
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171
172 #[test]
173 fn test_bump_basic_allocation() {
174 let bump = BumpAllocator::new();
175
176 let a = bump.alloc(42u64);
177 assert_eq!(*a, 42);
178
179 let b = bump.alloc_str("hello");
180 assert_eq!(b, "hello");
181 }
182
183 #[test]
184 fn test_bump_slice_allocation() {
185 let bump = BumpAllocator::new();
186
187 let slice = bump.alloc_slice_copy(&[1, 2, 3, 4, 5]);
188 assert_eq!(slice, &[1, 2, 3, 4, 5]);
189
190 slice[0] = 10;
191 assert_eq!(slice[0], 10);
192 }
193
194 #[test]
195 fn test_bump_string_allocation() {
196 let bump = BumpAllocator::new();
197
198 let s = bump.alloc_str("hello world");
199 assert_eq!(s, "hello world");
200 }
201
202 #[test]
203 fn test_bump_reset() {
204 let mut bump = BumpAllocator::new();
205
206 for _ in 0..100 {
207 bump.alloc(42u64);
208 }
209
210 let bytes_before = bump.allocated_bytes();
211 assert!(bytes_before > 0);
212 assert_eq!(bump.allocation_count(), 100);
213
214 bump.reset();
215
216 assert_eq!(bump.allocation_count(), 0);
218 }
219
220 #[test]
221 fn test_bump_with_capacity() {
222 let bump = BumpAllocator::with_capacity(1024);
223 assert_eq!(bump.allocation_count(), 0);
224
225 for _ in 0..10 {
227 bump.alloc(42u64);
228 }
229
230 assert_eq!(bump.allocation_count(), 10);
231 }
232
233 #[test]
234 fn test_scoped_bump() {
235 let mut bump = BumpAllocator::new();
236
237 bump.alloc(1u64);
238 let outer_allocs = bump.allocation_count();
239
240 {
241 let scope = ScopedBump::new(&mut bump);
242 scope.alloc(2u64);
243 scope.alloc(3u64);
244
245 }
249
250 assert_eq!(bump.allocation_count(), outer_allocs + 2);
252 }
253
254 #[test]
255 fn test_bump_many_small_allocations() {
256 let bump = BumpAllocator::new();
257
258 for i in 0u64..10_000u64 {
259 let v = bump.alloc(i);
260 assert_eq!(*v, i);
261 }
262
263 assert_eq!(bump.allocation_count(), 10_000);
264 }
265}