generational_buffer/
generational_buffer.rs1use std::{
2 fmt,
3 hash::Hash,
4 marker::PhantomData,
5};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub struct Handle<T> {
10 index: usize,
11 generation: u32,
12 phantom: PhantomData<T>,
13}
14
15impl<T> Handle<T> {
16 fn new(index: usize, generation: u32) -> Self {
17 Self {
18 index,
19 generation,
20 phantom: PhantomData,
21 }
22 }
23}
24
25pub struct GenerationalBuffer<T> {
30 entries: Vec<T>,
31 max_capacity: usize,
32 next_index: usize,
33 current_generation: u32,
34}
35
36impl<T> GenerationalBuffer<T> {
37 pub fn new(max_capacity: usize) -> Self {
39 Self {
40 entries: Vec::new(),
41 max_capacity,
42 next_index: 0,
43 current_generation: 0,
44 }
45 }
46
47 pub fn capacity(&self) -> usize {
49 self.max_capacity
50 }
51
52 pub fn len(&self) -> usize {
54 self.entries.len()
55 }
56
57 pub fn is_empty(&self) -> bool {
59 self.entries.is_empty()
60 }
61
62 pub fn is_full(&self) -> bool {
64 self.entries.len() == self.max_capacity
65 }
66
67 pub fn push(&mut self, value: T) -> Handle<T> {
69 let index = self.next_index;
70 let generation = self.current_generation;
71
72 if self.entries.len() < self.max_capacity {
73 self.entries.push(value);
75 } else {
76 self.entries[index] = value;
78 }
79
80 let handle = Handle::new(index, generation);
82
83 self.next_index = (self.next_index + 1) % self.max_capacity;
85
86 if self.next_index == 0 {
88 self.current_generation = self.current_generation.wrapping_add(1);
89 }
90
91 handle
92 }
93
94 pub fn get(&self, handle: Handle<T>) -> Option<&T> {
96 if handle.index >= self.entries.len() {
97 return None;
98 }
99
100 let expected_generation = self.calculate_generation_at_index(handle.index);
102
103 if handle.generation == expected_generation {
105 Some(&self.entries[handle.index])
106 } else {
107 None
108 }
109 }
110
111 pub fn get_mut(&mut self, handle: Handle<T>) -> Option<&mut T> {
113 if handle.index >= self.entries.len() {
114 return None;
115 }
116
117 let expected_generation = self.calculate_generation_at_index(handle.index);
119
120 if handle.generation == expected_generation {
122 Some(&mut self.entries[handle.index])
123 } else {
124 None
125 }
126 }
127
128 pub fn is_valid(&self, handle: Handle<T>) -> bool {
130 if handle.index >= self.entries.len() {
131 return false;
132 }
133
134 let expected_generation = self.calculate_generation_at_index(handle.index);
135 handle.generation == expected_generation
136 }
137
138 pub fn iter(&self) -> impl Iterator<Item = (Handle<T>, &T)> {
141 self.entries.iter().enumerate().map(|(i, value)| {
142 let generation = self.calculate_generation_at_index(i);
143 (Handle::new(i, generation), value)
144 })
145 }
146
147 pub fn values(&self) -> impl Iterator<Item = &T> {
149 self.entries.iter()
150 }
151
152 pub fn handles(&self) -> impl Iterator<Item = Handle<T>> + '_ {
154 (0..self.entries.len()).map(move |i| {
155 let generation = self.calculate_generation_at_index(i);
156 Handle::new(i, generation)
157 })
158 }
159
160 pub fn clear(&mut self) {
162 self.entries.clear();
163 self.next_index = 0;
164 self.current_generation = 0;
165 }
166
167 fn calculate_generation_at_index(&self, index: usize) -> u32 {
169 if index < self.next_index {
170 self.current_generation
171 } else {
172 self.current_generation.saturating_sub(1)
173 }
174 }
175}
176
177impl<T: fmt::Debug> fmt::Debug for GenerationalBuffer<T> {
178 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179 f.debug_struct("GenerationalBuffer")
180 .field("capacity", &self.capacity())
181 .field("len", &self.len())
182 .field("next_index", &self.next_index)
183 .field("current_generation", &self.current_generation)
184 .field("entries", &self.entries)
185 .finish()
186 }
187}
188
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193
194 #[test]
195 fn test_basic_operations() {
196 let mut buffer = GenerationalBuffer::new(3);
197
198 let h1 = buffer.push(10);
200 let h2 = buffer.push(20);
201 let h3 = buffer.push(30);
202
203 assert_eq!(buffer.get(h1), Some(&10));
205 assert_eq!(buffer.get(h2), Some(&20));
206 assert_eq!(buffer.get(h3), Some(&30));
207 assert_eq!(buffer.len(), 3);
208 assert!(buffer.is_full());
209 }
210
211 #[test]
212 fn test_circular_wrapping() {
213 let mut buffer = GenerationalBuffer::new(2);
214
215 let h1 = buffer.push(10);
217 let h2 = buffer.push(20);
218
219 let h3 = buffer.push(30);
221
222 assert_eq!(buffer.get(h1), None);
224 assert_eq!(buffer.get(h2), Some(&20));
225 assert_eq!(buffer.get(h3), Some(&30));
226 assert!(!buffer.is_valid(h1));
227 assert!(buffer.is_valid(h2));
228 assert!(buffer.is_valid(h3));
229 assert_eq!(buffer.len(), 2);
230
231 let h4 = buffer.push(40); let h5 = buffer.push(50); assert_eq!(buffer.get(h4), Some(&40));
235 assert_eq!(buffer.get(h5), Some(&50));
236 assert!(!buffer.is_valid(h2)); assert!(!buffer.is_valid(h3)); }
239
240 #[test]
241 fn test_generation_calculation() {
242 let mut buffer = GenerationalBuffer::new(3);
243
244 let handles: Vec<_> = (0..10).map(|i| buffer.push(i)).collect();
246
247 for (i, &handle) in handles.iter().enumerate() {
249 if i < 7 {
250 assert!(!buffer.is_valid(handle), "Handle {i} should be invalid");
251 } else {
252 assert!(buffer.is_valid(handle), "Handle {i} should be valid");
253 }
254 }
255 }
256
257 #[test]
258 fn test_iterator() {
259 let mut buffer = GenerationalBuffer::new(3);
260
261 buffer.push(10);
262 buffer.push(20);
263 buffer.push(30);
264 buffer.push(40);
265 buffer.push(50);
266 buffer.push(60);
267 buffer.push(70);
268 buffer.push(80);
269
270 let mut values: Vec<i32> = buffer.values().cloned().collect();
271 values.sort(); assert_eq!(values, vec![60, 70, 80]);
273
274 let handles: Vec<_> = buffer.handles().collect();
275 assert_eq!(handles.len(), 3);
276
277 for handle in handles {
279 assert!(buffer.is_valid(handle));
280 }
281 }
282
283 #[test]
284 fn test_growing_buffer() {
285 let mut buffer = GenerationalBuffer::new(5);
286
287 let h1 = buffer.push(1);
289 let h2 = buffer.push(2);
290 let h3 = buffer.push(3);
291
292 assert_eq!(buffer.len(), 3);
293 assert!(!buffer.is_full());
294
295 assert!(buffer.is_valid(h1));
297 assert!(buffer.is_valid(h2));
298 assert!(buffer.is_valid(h3));
299
300 assert_eq!(buffer.get(h1), Some(&1));
302 assert_eq!(buffer.get(h2), Some(&2));
303 assert_eq!(buffer.get(h3), Some(&3));
304 }
305}