Skip to main content

oxihuman_core/
object_arena.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! Arena allocator for objects — bump allocates into a typed Vec; reset
6//! reclaims all memory at once without per-object destruction overhead.
7
8/// Generation tag to invalidate stale handles after an arena reset.
9pub type Generation = u32;
10
11/// Handle to an arena-allocated object.
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub struct ArenaHandle {
14    pub index: usize,
15    pub generation: Generation,
16}
17
18/// Arena allocator that bump-allocates objects of type `T`.
19pub struct ObjectArena<T> {
20    data: Vec<T>,
21    generation: Generation,
22}
23
24impl<T> ObjectArena<T> {
25    /// Create an empty arena with a pre-allocated hint.
26    pub fn with_capacity(cap: usize) -> Self {
27        Self {
28            data: Vec::with_capacity(cap),
29            generation: 0,
30        }
31    }
32
33    /// Allocate an object and return its handle.
34    pub fn alloc(&mut self, value: T) -> ArenaHandle {
35        let index = self.data.len();
36        self.data.push(value);
37        ArenaHandle {
38            index,
39            generation: self.generation,
40        }
41    }
42
43    /// Get a reference, validating the generation.
44    pub fn get(&self, handle: ArenaHandle) -> Option<&T> {
45        if handle.generation == self.generation {
46            self.data.get(handle.index)
47        } else {
48            None
49        }
50    }
51
52    /// Number of live objects in the arena.
53    pub fn len(&self) -> usize {
54        self.data.len()
55    }
56
57    /// Returns true if the arena is empty.
58    pub fn is_empty(&self) -> bool {
59        self.data.is_empty()
60    }
61
62    /// Reset the arena, invalidating all existing handles.
63    pub fn reset(&mut self) {
64        self.data.clear();
65        self.generation = self.generation.wrapping_add(1);
66    }
67
68    /// Current generation counter.
69    pub fn generation(&self) -> Generation {
70        self.generation
71    }
72}
73
74/// Create an arena with the given capacity hint.
75pub fn new_object_arena<T>(cap: usize) -> ObjectArena<T> {
76    ObjectArena::with_capacity(cap)
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn test_alloc_and_get() {
85        let mut arena: ObjectArena<i32> = ObjectArena::with_capacity(8);
86        let h = arena.alloc(42);
87        assert_eq!(arena.get(h), Some(&42)); /* round-trip ok */
88    }
89
90    #[test]
91    fn test_reset_invalidates_handles() {
92        let mut arena: ObjectArena<i32> = ObjectArena::with_capacity(8);
93        let h = arena.alloc(1);
94        arena.reset();
95        assert_eq!(arena.get(h), None); /* stale handle rejected */
96    }
97
98    #[test]
99    fn test_len_after_alloc() {
100        let mut arena: ObjectArena<u8> = ObjectArena::with_capacity(4);
101        arena.alloc(1);
102        arena.alloc(2);
103        assert_eq!(arena.len(), 2); /* two objects stored */
104    }
105
106    #[test]
107    fn test_is_empty_initial() {
108        let arena: ObjectArena<i32> = ObjectArena::with_capacity(4);
109        assert!(arena.is_empty()); /* fresh arena is empty */
110    }
111
112    #[test]
113    fn test_is_empty_after_reset() {
114        let mut arena: ObjectArena<i32> = ObjectArena::with_capacity(4);
115        arena.alloc(5);
116        arena.reset();
117        assert!(arena.is_empty()); /* reset clears data */
118    }
119
120    #[test]
121    fn test_generation_increments() {
122        let mut arena: ObjectArena<i32> = ObjectArena::with_capacity(4);
123        let g0 = arena.generation();
124        arena.reset();
125        assert_eq!(arena.generation(), g0 + 1); /* generation advances */
126    }
127
128    #[test]
129    fn test_multiple_allocs() {
130        let mut arena: ObjectArena<f32> = ObjectArena::with_capacity(16);
131        let handles: Vec<_> = (0..8).map(|i| arena.alloc(i as f32)).collect();
132        for (i, h) in handles.iter().enumerate() {
133            assert_eq!(arena.get(*h), Some(&(i as f32))); /* each value correct */
134        }
135    }
136
137    #[test]
138    fn test_new_helper() {
139        let arena = new_object_arena::<u64>(32);
140        assert!(arena.is_empty()); /* helper creates empty arena */
141    }
142
143    #[test]
144    fn test_handle_index() {
145        let mut arena: ObjectArena<i32> = ObjectArena::with_capacity(4);
146        let h = arena.alloc(7);
147        assert_eq!(h.index, 0); /* first alloc at index 0 */
148    }
149}