generational_cache/arena/
mod.rs1use crate::vector::Vector;
24use core::{
25 fmt::{self, Debug, Display},
26 marker::PhantomData,
27};
28
29#[derive(Clone, Copy, PartialEq, Eq, Debug)]
31pub struct Index {
32 pub generation: u64,
34
35 pub idx: usize,
37}
38
39#[derive(Clone, Copy, PartialEq, Eq, Debug)]
41pub enum Entry<T> {
42 Occupied { value: T, generation: u64 },
44
45 Free { next_free_idx: Option<usize> },
47
48 Unmapped,
50}
51
52impl<T> Default for Entry<T> {
53 fn default() -> Self {
54 Self::Unmapped
55 }
56}
57
58pub struct Arena<V, T> {
87 entries_vec: V,
88 generation: u64,
89 free_list_head: Option<usize>,
90
91 len: usize,
92 capacity: usize,
93
94 _phantom_type: PhantomData<T>,
95}
96
97#[derive(Debug)]
99pub enum ArenaError<VE> {
100 OutOfMemory,
102
103 InvalidIdx,
105
106 VectorError(VE),
109}
110
111impl<VE> Display for ArenaError<VE>
112where
113 VE: Debug,
114{
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 write!(f, "{self:?}")
117 }
118}
119
120impl<V, T> Arena<V, T>
122where
123 V: Vector<Entry<T>>,
124{
125 pub fn reserve(&mut self, additional: usize) -> Result<(), ArenaError<V::Error>> {
127 let reserve_start = self.entries_vec.len();
128 let old_head = self.free_list_head;
129
130 self.entries_vec
131 .reserve(additional)
132 .map_err(ArenaError::VectorError)?;
133
134 for i in 0..additional {
135 let free_idx = i + reserve_start;
136
137 let next_free_idx = if i < additional - 1 {
138 Some(free_idx + 1)
139 } else {
140 old_head
141 };
142
143 let free_entry = Entry::Free { next_free_idx };
144 self.entries_vec
145 .push(free_entry)
146 .map_err(ArenaError::VectorError)?;
147 }
148
149 self.free_list_head = Some(reserve_start);
150
151 self.capacity += additional;
152
153 Ok(())
154 }
155
156 pub fn clear(&mut self) -> Result<(), ArenaError<V::Error>> {
158 self.free_list_head = Some(0);
159 self.generation = 0;
160 self.len = 0;
161
162 self.entries_vec.clear();
163
164 let capacity = self.capacity();
165
166 for i in 0..capacity {
167 let next_free_idx = i + 1;
168 let next_free_idx = if next_free_idx < capacity {
169 Some(next_free_idx)
170 } else {
171 None
172 };
173
174 let free_entry = Entry::Free { next_free_idx };
175 self.entries_vec
176 .push(free_entry)
177 .map_err(ArenaError::VectorError)?;
178 }
179
180 Ok(())
181 }
182
183 pub fn with_vector(vector: V) -> Self {
186 let capacity = vector.capacity();
187
188 let mut arena = Self {
189 entries_vec: vector,
190 generation: 0,
191 free_list_head: Some(0),
192 len: 0,
193 capacity,
194 _phantom_type: PhantomData,
195 };
196
197 arena.clear().unwrap();
198
199 arena
200 }
201
202 pub fn insert(&mut self, item: T) -> Result<Index, ArenaError<V::Error>> {
204 let old_free = self.free_list_head.ok_or(ArenaError::OutOfMemory)?;
205
206 self.free_list_head = self
207 .entries_vec
208 .get(old_free)
209 .map(|x| match x {
210 Entry::Free { next_free_idx } => *next_free_idx,
211 _ => None,
212 })
213 .ok_or(ArenaError::InvalidIdx)?;
214
215 let entry = Entry::Occupied {
216 value: item,
217 generation: self.generation,
218 };
219
220 *self
221 .entries_vec
222 .get_mut(old_free)
223 .ok_or(ArenaError::InvalidIdx)? = entry;
224 self.generation += 1;
225
226 self.len += 1;
227
228 Ok(Index {
229 generation: self.generation - 1,
230 idx: old_free,
231 })
232 }
233
234 pub fn remove(&mut self, index: &Index) -> Option<T> {
237 match self.entries_vec.get(index.idx) {
238 Some(Entry::Occupied {
239 value: _,
240 generation,
241 }) if &index.generation == generation => {
242 let new_free_list_head_entry = Entry::<T>::Free {
243 next_free_idx: self.free_list_head,
244 };
245
246 let old_entry = core::mem::replace(
247 self.entries_vec.get_mut(index.idx)?,
248 new_free_list_head_entry,
249 );
250
251 self.free_list_head = Some(index.idx);
252
253 self.len -= 1;
254
255 Some(old_entry)
256 }
257 _ => None,
258 }
259 .and_then(|x| match x {
260 Entry::Occupied {
261 value,
262 generation: _,
263 } => Some(value),
264 _ => None,
265 })
266 }
267
268 pub fn get_mut(&mut self, index: &Index) -> Option<&mut T> {
270 match self.entries_vec.get_mut(index.idx) {
271 Some(Entry::Occupied { value, generation }) if &index.generation == generation => {
272 Some(value)
273 }
274 _ => None,
275 }
276 }
277
278 pub fn get(&self, index: &Index) -> Option<&T> {
280 match self.entries_vec.get(index.idx) {
281 Some(Entry::Occupied { value, generation }) if &index.generation == generation => {
282 Some(value)
283 }
284 _ => None,
285 }
286 }
287
288 pub fn capacity(&self) -> usize {
290 self.capacity
291 }
292
293 pub fn is_empty(&self) -> bool {
295 self.len == 0
296 }
297
298 pub fn len(&self) -> usize {
300 self.len
301 }
302}
303
304#[doc(hidden)]
305pub mod tests {
306 use super::{Arena, Entry, Index, Vector};
307 use core::{cmp::PartialEq, fmt::Debug};
308
309 pub fn _test_arena_free_entries_init<T, V>(mut arena: Arena<V, T>)
310 where
311 V: Vector<Entry<T>>,
312 T: Debug + PartialEq,
313 {
314 arena.clear().unwrap();
315
316 assert_eq!(arena.free_list_head, Some(0));
317
318 let capacity = arena.capacity();
319
320 for i in 0..capacity {
321 let entry = &arena.entries_vec[i];
322
323 if i == capacity - 1 {
324 assert_eq!(
325 entry,
326 &Entry::Free {
327 next_free_idx: None
328 }
329 )
330 } else {
331 assert_eq!(
332 entry,
333 &Entry::Free {
334 next_free_idx: Some(i + 1)
335 }
336 )
337 };
338 }
339 }
340
341 pub fn _test_arena_reserve<T, V>(mut arena: Arena<V, T>)
342 where
343 V: Vector<Entry<T>>,
344 T: Debug + PartialEq,
345 {
346 arena.clear().unwrap();
347
348 let old_capacity = arena.capacity();
349
350 const ADDITIONAL: usize = 5;
351
352 let result = arena.reserve(ADDITIONAL);
353
354 if result.is_err() {
355 return;
356 }
357
358 assert_eq!(arena.free_list_head, Some(old_capacity));
359
360 let capacity = arena.capacity();
361
362 for i in 0..capacity {
363 let entry = &arena.entries_vec[i];
364
365 if i == capacity - 1 {
366 assert_eq!(
367 entry,
368 &Entry::Free {
369 next_free_idx: Some(0)
370 }
371 )
372 } else if i == old_capacity - 1 {
373 assert_eq!(
374 entry,
375 &Entry::Free {
376 next_free_idx: None
377 }
378 )
379 } else {
380 assert_eq!(
381 entry,
382 &Entry::Free {
383 next_free_idx: Some(i + 1)
384 }
385 )
386 };
387 }
388 }
389
390 pub fn _test_arena_insert<V>(mut arena: Arena<V, i32>)
391 where
392 V: Vector<Entry<i32>>,
393 {
394 assert!(
395 arena.capacity() >= 2,
396 "Test not valid for arena with capacity < 2"
397 );
398
399 arena.clear().unwrap();
400
401 let index_0 = arena.insert(0);
402 assert_eq!(
403 index_0.as_ref().unwrap(),
404 &Index {
405 generation: 0,
406 idx: 0
407 }
408 );
409
410 let index_1 = arena.insert(1);
411 assert_eq!(
412 index_1.as_ref().unwrap(),
413 &Index {
414 generation: 1,
415 idx: 1
416 }
417 );
418
419 let index_0_val = index_0.as_ref().unwrap();
420 let item_0 = arena.get(index_0_val);
421 assert_eq!(item_0, Some(&0));
422
423 let index_1_val = index_1.unwrap();
424 let item_1 = arena.get(&index_1_val);
425 assert_eq!(item_1, Some(&1));
426
427 let item_0 = arena.get_mut(index_0_val);
428 assert_eq!(item_0, Some(&mut 0));
429 let item_0 = item_0.unwrap();
430 *item_0 = 25;
431
432 let item_0 = arena.get(index_0_val);
433 assert_eq!(item_0, Some(&25));
434
435 let item_1 = arena.get_mut(&index_1_val);
436 assert_eq!(item_1, Some(&mut 1));
437 let item_1 = item_1.unwrap();
438 *item_1 = -78;
439
440 let item_1 = arena.get(&index_1_val);
441 assert_eq!(item_1, Some(&-78));
442
443 let last_len = arena.len();
444
445 let remaining = arena.capacity() - last_len;
446
447 for i in 0..remaining {
448 let possible_idx = last_len + i;
449
450 assert_eq!(
451 arena.insert(0).unwrap(),
452 Index {
453 generation: possible_idx as u64,
454 idx: possible_idx
455 }
456 )
457 }
458
459 const ADDITIONAL: usize = 5;
460
461 let result = arena.reserve(ADDITIONAL);
462
463 if result.is_ok() {
464 for _ in 0..ADDITIONAL {
465 arena.insert(0).unwrap();
466 }
467 }
468
469 arena.clear().unwrap();
470
471 assert!(arena.is_empty());
472 }
473
474 pub fn _test_arena_remove<V>(mut arena: Arena<V, i32>)
475 where
476 V: Vector<Entry<i32>>,
477 {
478 assert!(
479 arena.capacity() >= 2,
480 "Test not valid for arena with capacity < 2"
481 );
482
483 arena.clear().unwrap();
484
485 assert_eq!(arena.free_list_head.unwrap(), 0);
486
487 let index = arena.insert(0).unwrap();
488 assert_eq!(arena.get(&index), Some(&0));
489 assert_eq!(
490 index,
491 Index {
492 generation: 0,
493 idx: 0
494 }
495 );
496
497 assert_eq!(arena.free_list_head.unwrap(), 1);
498
499 assert_eq!(arena.remove(&index).unwrap(), 0);
500 assert_eq!(arena.get(&index), None);
501
502 assert_eq!(arena.free_list_head.unwrap(), 0);
503
504 let index = arena.insert(0).unwrap();
505 assert_eq!(arena.get(&index), Some(&0));
506 assert_eq!(
507 index,
508 Index {
509 generation: 1,
510 idx: 0
511 }
512 );
513
514 assert_eq!(arena.free_list_head.unwrap(), 1);
515
516 let last_arena_len = arena.len();
517 let remaining = arena.capacity() - last_arena_len;
518
519 let current_generation = index.generation + 1;
520
521 for i in 0..remaining {
522 let index = arena.insert(i as i32).unwrap();
523 assert_eq!(
524 index,
525 Index {
526 generation: current_generation + i as u64,
527 idx: last_arena_len + i
528 }
529 );
530 }
531
532 let mut i = 1;
534 let mut removed_count = 0;
535 while i < arena.capacity() {
536 arena
537 .remove(&Index {
538 generation: i as u64 + 1,
539 idx: i,
540 })
541 .unwrap();
542
543 i += 2;
544 removed_count += 1;
545 }
546
547 let mut free_position_count = 0;
549 let mut free_idx = arena.free_list_head;
550
551 while let Some(next_free) = free_idx {
552 assert_eq!(next_free & 1, 1);
553 free_idx = match arena.entries_vec[next_free] {
554 Entry::Free { next_free_idx } => next_free_idx,
555 _ => None,
556 };
557 free_position_count += 1;
558 }
559
560 assert_eq!(removed_count, free_position_count);
561
562 arena.clear().unwrap();
563
564 assert!(arena.is_empty());
565 }
566}