generational_buffer/
generational_buffer.rs1use std::{
2 fmt,
3 marker::PhantomData,
4};
5
6#[derive(Debug)]
11pub struct Handle<T> {
12 index: usize,
13 generation: u32,
14 phantom: PhantomData<T>,
15}
16
17impl<T> Handle<T> {
18 fn new(index: usize, generation: u32) -> Self {
19 Self {
20 index,
21 generation,
22 phantom: PhantomData,
23 }
24 }
25}
26
27pub struct GenerationalBuffer<T> {
32 entries: Vec<T>,
33 max_capacity: usize,
34 next_index: usize,
35 current_generation: u32,
36}
37
38impl<T> GenerationalBuffer<T> {
39 pub fn new(max_capacity: usize) -> Self {
41 Self {
42 entries: Vec::new(),
43 max_capacity,
44 next_index: 0,
45 current_generation: 0,
46 }
47 }
48
49 pub fn capacity(&self) -> usize {
51 self.max_capacity
52 }
53
54 pub fn len(&self) -> usize {
56 self.entries.len()
57 }
58
59 pub fn is_empty(&self) -> bool {
61 self.entries.is_empty()
62 }
63
64 pub fn is_full(&self) -> bool {
66 self.entries.len() == self.max_capacity
67 }
68
69 pub fn push(&mut self, value: T) -> Handle<T> {
73 let index = self.next_index;
74 let generation = self.current_generation;
75
76 if self.entries.len() < self.max_capacity {
77 self.entries.push(value);
79 } else {
80 self.entries[index] = value;
82 }
83
84 let handle = Handle::new(index, generation);
86
87 self.next_index = (self.next_index + 1) % self.max_capacity;
89
90 if self.next_index == 0 {
92 self.current_generation = self.current_generation.wrapping_add(1);
93 }
94
95 handle
96 }
97
98 pub fn get(&self, handle: Handle<T>) -> Option<&T> {
100 if handle.index >= self.entries.len() {
101 return None;
102 }
103
104 let expected_generation = self.calculate_generation_at_index(handle.index);
106
107 if handle.generation == expected_generation {
109 Some(&self.entries[handle.index])
110 } else {
111 None
112 }
113 }
114
115 pub fn get_mut(&mut self, handle: Handle<T>) -> Option<&mut T> {
117 if handle.index >= self.entries.len() {
118 return None;
119 }
120
121 let expected_generation = self.calculate_generation_at_index(handle.index);
123
124 if handle.generation == expected_generation {
126 Some(&mut self.entries[handle.index])
127 } else {
128 None
129 }
130 }
131
132 pub fn is_valid(&self, handle: Handle<T>) -> bool {
134 if handle.index >= self.entries.len() {
135 return false;
136 }
137
138 let expected_generation = self.calculate_generation_at_index(handle.index);
139 handle.generation == expected_generation
140 }
141
142 pub fn iter(&self) -> impl Iterator<Item = (Handle<T>, &T)> {
145 self.entries.iter().enumerate().map(|(i, value)| {
146 let generation = self.calculate_generation_at_index(i);
147 (Handle::new(i, generation), value)
148 })
149 }
150
151 pub fn values(&self) -> impl Iterator<Item = &T> {
153 self.entries.iter()
154 }
155
156 pub fn handles(&self) -> impl Iterator<Item = Handle<T>> + '_ {
158 (0..self.entries.len()).map(move |i| {
159 let generation = self.calculate_generation_at_index(i);
160 Handle::new(i, generation)
161 })
162 }
163
164 fn calculate_generation_at_index(&self, index: usize) -> u32 {
166 if index < self.next_index {
167 self.current_generation
168 } else {
169 self.current_generation.saturating_sub(1)
170 }
171 }
172}
173
174impl<T: fmt::Debug> fmt::Debug for GenerationalBuffer<T> {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 f.debug_struct("GenerationalBuffer")
177 .field("capacity", &self.capacity())
178 .field("len", &self.len())
179 .field("next_index", &self.next_index)
180 .field("current_generation", &self.current_generation)
181 .field("entries", &self.entries)
182 .finish()
183 }
184}
185impl<O> PartialEq for Handle<O> {
186 fn eq(&self, other: &Self) -> bool {
187 self.index == other.index && self.generation == other.generation
188 }
189}
190impl<O> Eq for Handle<O> {}
191impl<O> Clone for Handle<O> {
192 fn clone(&self) -> Self {
193 *self
194 }
195}
196impl<O> Copy for Handle<O> {}
197
198#[cfg(test)]
199mod tests {
200 use super::*;
201
202 #[test]
203 fn test_basic_operations() {
204 let mut buffer = GenerationalBuffer::new(3);
205
206 let h1 = buffer.push(10);
208 let h2 = buffer.push(20);
209 let h3 = buffer.push(30);
210
211 assert_eq!(buffer.get(h1), Some(&10));
213 assert_eq!(buffer.get(h2), Some(&20));
214 assert_eq!(buffer.get(h3), Some(&30));
215 assert_eq!(buffer.len(), 3);
216 assert!(buffer.is_full());
217 }
218
219 #[test]
220 fn test_circular_wrapping() {
221 let mut buffer = GenerationalBuffer::new(2);
222
223 let h1 = buffer.push(10);
225 let h2 = buffer.push(20);
226
227 let h3 = buffer.push(30);
229
230 assert_eq!(buffer.get(h1), None);
232 assert_eq!(buffer.get(h2), Some(&20));
233 assert_eq!(buffer.get(h3), Some(&30));
234 assert!(!buffer.is_valid(h1));
235 assert!(buffer.is_valid(h2));
236 assert!(buffer.is_valid(h3));
237 assert_eq!(buffer.len(), 2);
238
239 let h4 = buffer.push(40); let h5 = buffer.push(50); assert_eq!(buffer.get(h4), Some(&40));
243 assert_eq!(buffer.get(h5), Some(&50));
244 assert!(!buffer.is_valid(h2)); assert!(!buffer.is_valid(h3)); }
247
248 #[test]
249 fn test_generation_calculation() {
250 let mut buffer = GenerationalBuffer::new(3);
251
252 let handles: Vec<_> = (0..10).map(|i| buffer.push(i)).collect();
254
255 for (i, &handle) in handles.iter().enumerate() {
257 if i < 7 {
258 assert!(!buffer.is_valid(handle), "Handle {i} should be invalid");
259 } else {
260 assert!(buffer.is_valid(handle), "Handle {i} should be valid");
261 }
262 }
263 }
264
265 #[test]
266 fn test_iterator() {
267 let mut buffer = GenerationalBuffer::new(3);
268
269 buffer.push(10);
270 buffer.push(20);
271 buffer.push(30);
272 buffer.push(40);
273 buffer.push(50);
274 buffer.push(60);
275 buffer.push(70);
276 buffer.push(80);
277
278 let mut values: Vec<i32> = buffer.values().cloned().collect();
279 values.sort(); assert_eq!(values, vec![60, 70, 80]);
281
282 let handles: Vec<_> = buffer.handles().collect();
283 assert_eq!(handles.len(), 3);
284
285 for handle in handles {
287 assert!(buffer.is_valid(handle));
288 }
289 }
290
291 #[test]
292 fn test_growing_buffer() {
293 let mut buffer = GenerationalBuffer::new(5);
294
295 let h1 = buffer.push(1);
297 let h2 = buffer.push(2);
298 let h3 = buffer.push(3);
299
300 assert_eq!(buffer.len(), 3);
301 assert!(!buffer.is_full());
302
303 assert!(buffer.is_valid(h1));
305 assert!(buffer.is_valid(h2));
306 assert!(buffer.is_valid(h3));
307
308 assert_eq!(buffer.get(h1), Some(&1));
310 assert_eq!(buffer.get(h2), Some(&2));
311 assert_eq!(buffer.get(h3), Some(&3));
312 }
313}