1use std::alloc::{alloc, dealloc, Layout};
7use std::cell::RefCell;
8use std::ptr;
9
10pub struct Arena {
15 chunks: RefCell<Vec<Chunk>>,
16 chunk_size: usize,
17}
18
19struct Chunk {
20 data: *mut u8,
21 capacity: usize,
22 used: usize,
23}
24
25impl Arena {
26 pub fn new(chunk_size: usize) -> Self {
28 Self {
29 chunks: RefCell::new(Vec::new()),
30 chunk_size,
31 }
32 }
33
34 pub fn with_default_chunk_size() -> Self {
36 Self::new(1024 * 1024) }
38
39 pub fn alloc_vec<T>(&self, count: usize) -> ArenaVec<T> {
41 let size = count * std::mem::size_of::<T>();
42 let align = std::mem::align_of::<T>();
43
44 let ptr = self.alloc_raw(size, align);
45
46 ArenaVec {
47 ptr: ptr as *mut T,
48 len: 0,
49 capacity: count,
50 _phantom: std::marker::PhantomData,
51 }
52 }
53
54 fn alloc_raw(&self, size: usize, align: usize) -> *mut u8 {
56 let mut chunks = self.chunks.borrow_mut();
57
58 if let Some(chunk) = chunks.last_mut() {
60 let current = chunk.used;
62 let aligned = (current + align - 1) & !(align - 1);
63 let needed = aligned + size;
64
65 if needed <= chunk.capacity {
66 chunk.used = needed;
67 return unsafe { chunk.data.add(aligned) };
68 }
69 }
70
71 let chunk_size = self.chunk_size.max(size + align);
73 let layout = Layout::from_size_align(chunk_size, 64).unwrap();
74 let data = unsafe { alloc(layout) };
75
76 let aligned = align;
77 let chunk = Chunk {
78 data,
79 capacity: chunk_size,
80 used: aligned + size,
81 };
82
83 let ptr = unsafe { data.add(aligned) };
84 chunks.push(chunk);
85
86 ptr
87 }
88
89 pub fn reset(&self) {
91 let mut chunks = self.chunks.borrow_mut();
92 for chunk in chunks.iter_mut() {
93 chunk.used = 0;
94 }
95 }
96
97 pub fn allocated_bytes(&self) -> usize {
99 let chunks = self.chunks.borrow();
100 chunks.iter().map(|c| c.capacity).sum()
101 }
102
103 pub fn used_bytes(&self) -> usize {
105 let chunks = self.chunks.borrow();
106 chunks.iter().map(|c| c.used).sum()
107 }
108}
109
110impl Drop for Arena {
111 fn drop(&mut self) {
112 let chunks = self.chunks.borrow();
113 for chunk in chunks.iter() {
114 let layout = Layout::from_size_align(chunk.capacity, 64).unwrap();
115 unsafe {
116 dealloc(chunk.data, layout);
117 }
118 }
119 }
120}
121
122pub struct ArenaVec<T> {
124 ptr: *mut T,
125 len: usize,
126 capacity: usize,
127 _phantom: std::marker::PhantomData<T>,
128}
129
130impl<T> ArenaVec<T> {
131 pub fn push(&mut self, value: T) {
133 assert!(self.len < self.capacity, "ArenaVec capacity exceeded");
134 unsafe {
135 ptr::write(self.ptr.add(self.len), value);
136 }
137 self.len += 1;
138 }
139
140 pub fn len(&self) -> usize {
142 self.len
143 }
144
145 pub fn is_empty(&self) -> bool {
147 self.len == 0
148 }
149
150 pub fn capacity(&self) -> usize {
152 self.capacity
153 }
154
155 pub fn as_slice(&self) -> &[T] {
157 unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
158 }
159
160 pub fn as_mut_slice(&mut self) -> &mut [T] {
162 unsafe { std::slice::from_raw_parts_mut(self.ptr, self.len) }
163 }
164}
165
166impl<T> std::ops::Deref for ArenaVec<T> {
167 type Target = [T];
168
169 fn deref(&self) -> &[T] {
170 self.as_slice()
171 }
172}
173
174impl<T> std::ops::DerefMut for ArenaVec<T> {
175 fn deref_mut(&mut self) -> &mut [T] {
176 self.as_mut_slice()
177 }
178}
179
180thread_local! {
182 static THREAD_ARENA: RefCell<Arena> = RefCell::new(Arena::with_default_chunk_size());
183}
184
185#[cfg(test)]
197mod tests {
198 use super::*;
199
200 #[test]
201 fn test_arena_alloc() {
202 let arena = Arena::new(1024);
203
204 let mut vec1 = arena.alloc_vec::<f32>(10);
205 vec1.push(1.0);
206 vec1.push(2.0);
207 vec1.push(3.0);
208
209 assert_eq!(vec1.len(), 3);
210 assert_eq!(vec1[0], 1.0);
211 assert_eq!(vec1[1], 2.0);
212 assert_eq!(vec1[2], 3.0);
213 }
214
215 #[test]
216 fn test_arena_multiple_allocs() {
217 let arena = Arena::new(1024);
218
219 let vec1 = arena.alloc_vec::<u32>(100);
220 let vec2 = arena.alloc_vec::<u64>(50);
221 let vec3 = arena.alloc_vec::<f32>(200);
222
223 assert_eq!(vec1.capacity(), 100);
224 assert_eq!(vec2.capacity(), 50);
225 assert_eq!(vec3.capacity(), 200);
226 }
227
228 #[test]
229 fn test_arena_reset() {
230 let arena = Arena::new(1024);
231
232 {
233 let _vec1 = arena.alloc_vec::<f32>(100);
234 let _vec2 = arena.alloc_vec::<f32>(100);
235 }
236
237 let used_before = arena.used_bytes();
238 arena.reset();
239 let used_after = arena.used_bytes();
240
241 assert!(used_after < used_before);
242 }
243}