Skip to main content

he3d_core/
arena.rs

1use alloc::vec::Vec;
2use core::marker::PhantomData;
3
4/// A stable generational handle into an [`Arena<T>`].
5/// 指向 [`Arena<T>`] 的稳定代际句柄。
6///
7/// An `Id` is two packed integers (slot index + generation) and never stores a reference, so it can outlive the arena without dangling.
8/// `Id` 由两个打包的整数(槽位索引 + 代际)组成,且从不存储引用,因此可以比 arena 存活更久而不会悬垂。
9/// Once a slot is removed, its generation advances, invalidating all previously issued `Id`s.
10/// 一旦槽位被移除,其代际就会递增,从而使所有先前发出的 `Id` 失效。
11///
12/// The `T` parameter is phantom: it exists only to make IDs of different arenas distinct types at compile time.
13/// `T` 参数是幻影的:它仅用于让不同 arena 的 ID 在编译期成为不同的类型。
14/// Trait impls are written by hand so that `Id<T>` is always `Copy`/`Eq`/`Hash` regardless of `T`.
15/// 特质实现均为手写,以便无论 `T` 为何,`Id<T>` 始终是 `Copy`/`Eq`/`Hash`。
16pub struct Id<T> {
17   index: u32,
18   generation: u32,
19   _marker: PhantomData<fn() -> T>,
20}
21
22impl<T> Id<T> {
23   #[inline]
24   pub fn index(self) -> u32 {
25      self.index
26   }
27
28   #[inline]
29   pub fn generation(self) -> u32 {
30      self.generation
31   }
32}
33
34impl<T> Clone for Id<T> {
35   #[inline]
36   fn clone(&self) -> Self {
37      *self
38   }
39}
40
41impl<T> Copy for Id<T> {}
42
43impl<T> PartialEq for Id<T> {
44   #[inline]
45   fn eq(&self, other: &Self) -> bool {
46      self.index == other.index && self.generation == other.generation
47   }
48}
49
50impl<T> Eq for Id<T> {}
51
52impl<T> PartialOrd for Id<T> {
53   #[inline]
54   fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
55      Some(self.cmp(other))
56   }
57}
58
59impl<T> Ord for Id<T> {
60   #[inline]
61   fn cmp(&self, other: &Self) -> core::cmp::Ordering {
62      (self.index, self.generation).cmp(&(other.index, other.generation))
63   }
64}
65
66impl<T> core::hash::Hash for Id<T> {
67   #[inline]
68   fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
69      core::hash::Hash::hash(&self.index, state);
70      core::hash::Hash::hash(&self.generation, state);
71   }
72}
73
74impl<T> core::fmt::Debug for Id<T> {
75   fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
76      write!(f, "Id({}@g{})", self.index, self.generation)
77   }
78}
79
80#[derive(Clone, Debug)]
81struct Slot<T> {
82   generation: u32,
83   value: Option<T>,
84}
85
86/// A generational arena: dense storage with reuse of freed slots and stale-handle detection.
87/// 代际 arena:密集存储,支持空闲槽位复用与过期句柄检测。
88///
89/// This is the ownership primitive behind meshes, textures, and render objects.
90/// 这是网格、纹理和渲染对象背后的所有权原语。
91/// It is intentionally a small self-contained type so it can be swapped for an external slot map without touching call sites.
92/// 它刻意做成一个小而自包含的类型,以便可以在不改动调用方的情况下替换为外部的槽位映射。
93#[derive(Clone, Debug)]
94pub struct Arena<T> {
95   slots: Vec<Slot<T>>,
96   free: Vec<u32>,
97   len: usize,
98}
99
100impl<T> Arena<T> {
101   pub fn new() -> Self {
102      Self {
103         slots: Vec::new(),
104         free: Vec::new(),
105         len: 0,
106      }
107   }
108
109   pub fn with_capacity(capacity: usize) -> Self {
110      Self {
111         slots: Vec::with_capacity(capacity),
112         free: Vec::new(),
113         len: 0,
114      }
115   }
116
117   /// Insert a value and return its handle.
118   /// 插入一个值并返回其句柄。
119   pub fn insert(&mut self, value: T) -> Id<T> {
120      self.len += 1;
121      if let Some(index) = self.free.pop() {
122         let slot = &mut self.slots[index as usize];
123         slot.generation = slot.generation.wrapping_add(1);
124         slot.value = Some(value);
125         return Id {
126            index,
127            generation: slot.generation,
128            _marker: PhantomData,
129         };
130      }
131
132      let index = u32::try_from(self.slots.len()).expect("arena index space exhausted");
133      self.slots.push(Slot {
134         generation: 0,
135         value: Some(value),
136      });
137      Id {
138         index,
139         generation: 0,
140         _marker: PhantomData,
141      }
142   }
143
144   pub fn get(&self, id: Id<T>) -> Option<&T> {
145      let slot = self.slots.get(id.index as usize)?;
146      if slot.generation != id.generation {
147         return None;
148      }
149      slot.value.as_ref()
150   }
151
152   pub fn get_mut(&mut self, id: Id<T>) -> Option<&mut T> {
153      let slot = self.slots.get_mut(id.index as usize)?;
154      if slot.generation != id.generation {
155         return None;
156      }
157      slot.value.as_mut()
158   }
159
160   pub fn contains(&self, id: Id<T>) -> bool {
161      self.get(id).is_some()
162   }
163
164   /// Remove a value, invalidating the handle.
165   /// 移除一个值,并使该句柄失效。
166   pub fn remove(&mut self, id: Id<T>) -> Option<T> {
167      let slot = self.slots.get_mut(id.index as usize)?;
168      if slot.generation != id.generation {
169         return None;
170      }
171      let value = slot.value.take()?;
172      slot.generation = slot.generation.wrapping_add(1);
173      self.free.push(id.index);
174      self.len -= 1;
175      Some(value)
176   }
177
178   pub fn len(&self) -> usize {
179      self.len
180   }
181
182   pub fn is_empty(&self) -> bool {
183      self.len == 0
184   }
185
186   /// Iterate over all live `(id, value)` pairs in slot order.
187   /// 按槽位顺序遍历所有存活的 `(id, value)` 对。
188   pub fn iter(&self) -> impl Iterator<Item = (Id<T>, &T)> {
189      self.slots.iter().enumerate().filter_map(|(index, slot)| {
190         let value = slot.value.as_ref()?;
191         let index = u32::try_from(index).ok()?;
192         Some((
193            Id {
194               index,
195               generation: slot.generation,
196               _marker: PhantomData,
197            },
198            value,
199         ))
200      })
201   }
202}
203
204impl<T> Default for Arena<T> {
205   fn default() -> Self {
206      Self::new()
207   }
208}
209
210#[cfg(test)]
211mod tests {
212   use alloc::vec::Vec;
213
214   use super::Arena;
215
216   #[test]
217   fn insert_and_get() {
218      let mut arena = Arena::new();
219      let id = arena.insert(42u32);
220      assert_eq!(arena.get(id), Some(&42));
221      assert!(arena.contains(id));
222      assert_eq!(arena.len(), 1);
223   }
224
225   #[test]
226   fn removed_id_becomes_stale() {
227      let mut arena = Arena::new();
228      let id = arena.insert(7u32);
229      assert_eq!(arena.remove(id), Some(7));
230      assert!(!arena.contains(id));
231      assert_eq!(arena.get(id), None);
232      assert!(arena.is_empty());
233   }
234
235   #[test]
236   fn reused_slot_invalidates_previous_handle() {
237      let mut arena = Arena::new();
238      let first = arena.insert(1u32);
239      arena.remove(first);
240      let second = arena.insert(2u32);
241      // Same slot index, but the generation advanced.
242      // 槽位索引相同,但代际已经递增。
243      assert_eq!(first.index(), second.index());
244      assert_ne!(first, second);
245      assert_eq!(arena.get(first), None);
246      assert_eq!(arena.get(second), Some(&2));
247   }
248
249   #[test]
250   fn iter_yields_live_pairs() {
251      let mut arena = Arena::new();
252      let a = arena.insert("a");
253      let b = arena.insert("b");
254      let c = arena.insert("c");
255      arena.remove(b);
256      let mut seen: Vec<&str> = arena.iter().map(|(_, v)| *v).collect();
257      seen.sort_unstable();
258      assert_eq!(seen, ["a", "c"]);
259      assert!(arena.contains(a) && arena.contains(c));
260   }
261}