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> {
35 entries: Vec<T>,
36 max_capacity: usize,
37 next_index: usize,
38 current_generation: u32,
39}
40
41impl<T> GenerationalBuffer<T> {
42 pub fn new(max_capacity: usize) -> Self {
44 Self {
45 entries: Vec::new(),
46 max_capacity,
47 next_index: 0,
48 current_generation: 0,
49 }
50 }
51
52 pub fn capacity(&self) -> usize {
54 self.max_capacity
55 }
56
57 pub fn len(&self) -> usize {
59 self.entries.len()
60 }
61
62 pub fn is_empty(&self) -> bool {
64 self.entries.is_empty()
65 }
66
67 pub fn clear(&mut self) {
70 self.entries.clear();
71 self.next_index = 0;
72 self.current_generation += 2;
73 }
74
75 pub fn is_full(&self) -> bool {
77 self.entries.len() == self.max_capacity
78 }
79
80 pub fn push(&mut self, value: T) -> Handle<T> {
84 let index = self.next_index;
85 let generation = self.current_generation;
86
87 if self.entries.len() < self.max_capacity {
88 self.entries.push(value);
90 } else {
91 self.entries[index] = value;
93 }
94
95 let handle = Handle::new(index, generation);
97
98 self.next_index = (self.next_index + 1) % self.max_capacity;
100
101 if self.next_index == 0 {
103 self.current_generation = self.current_generation.wrapping_add(1);
104 }
105
106 handle
107 }
108
109 pub fn get(&self, handle: Handle<T>) -> Option<&T> {
111 if self.is_valid(handle) {
112 Some(&self.entries[handle.index])
113 } else {
114 None
115 }
116 }
117
118 pub fn get_mut(&mut self, handle: Handle<T>) -> Option<&mut T> {
120 if self.is_valid(handle) {
121 Some(&mut self.entries[handle.index])
122 } else {
123 None
124 }
125 }
126
127 pub fn is_valid(&self, handle: Handle<T>) -> bool {
129 if handle.index >= self.entries.len() {
130 return false;
131 }
132 handle.generation == self.calculate_generation_at_index(handle.index)
133 }
134
135 pub fn iter(&self) -> impl Iterator<Item = (Handle<T>, &T)> {
138 self.entries.iter().enumerate().map(|(i, value)| {
139 let generation = self.calculate_generation_at_index(i);
140 (Handle::new(i, generation), value)
141 })
142 }
143
144 pub fn values(&self) -> impl Iterator<Item = &T> {
146 self.entries.iter()
147 }
148
149 pub fn handles(&self) -> impl Iterator<Item = Handle<T>> + '_ {
151 (0..self.entries.len()).map(move |i| {
152 let generation = self.calculate_generation_at_index(i);
153 Handle::new(i, generation)
154 })
155 }
156
157 fn calculate_generation_at_index(&self, index: usize) -> u32 {
159 if index < self.next_index {
160 self.current_generation
161 } else {
162 self.current_generation.saturating_sub(1)
163 }
164 }
165}
166
167impl<T: fmt::Debug> fmt::Debug for GenerationalBuffer<T> {
168 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169 f.debug_struct("GenerationalBuffer")
170 .field("capacity", &self.capacity())
171 .field("len", &self.len())
172 .field("next_index", &self.next_index)
173 .field("current_generation", &self.current_generation)
174 .field("entries", &self.entries)
175 .finish()
176 }
177}
178impl<O> PartialEq for Handle<O> {
179 fn eq(&self, other: &Self) -> bool {
180 self.index == other.index && self.generation == other.generation
181 }
182}
183impl<O> Eq for Handle<O> {}
184impl<O> Clone for Handle<O> {
185 fn clone(&self) -> Self {
186 *self
187 }
188}
189impl<O> Copy for Handle<O> {}
190
191#[cfg(test)]
192mod tests {
193 use super::*;
194
195 #[test]
196 fn test_basic_operations() {
197 let mut buffer = GenerationalBuffer::new(3);
198
199 let h1 = buffer.push(10);
201 let h2 = buffer.push(20);
202 let h3 = buffer.push(30);
203
204 assert_eq!(buffer.get(h1), Some(&10));
206 assert_eq!(buffer.get(h2), Some(&20));
207 assert_eq!(buffer.get(h3), Some(&30));
208 assert_eq!(buffer.len(), 3);
209 assert!(buffer.is_full());
210 }
211
212 #[test]
213 fn test_circular_wrapping() {
214 let mut buffer = GenerationalBuffer::new(2);
215
216 let h1 = buffer.push(10);
218 let h2 = buffer.push(20);
219
220 let h3 = buffer.push(30);
222
223 assert_eq!(buffer.get(h1), None);
225 assert_eq!(buffer.get(h2), Some(&20));
226 assert_eq!(buffer.get(h3), Some(&30));
227 assert!(!buffer.is_valid(h1));
228 assert!(buffer.is_valid(h2));
229 assert!(buffer.is_valid(h3));
230 assert_eq!(buffer.len(), 2);
231
232 let h4 = buffer.push(40); let h5 = buffer.push(50); assert_eq!(buffer.get(h4), Some(&40));
236 assert_eq!(buffer.get(h5), Some(&50));
237 assert!(!buffer.is_valid(h2)); assert!(!buffer.is_valid(h3)); buffer.clear();
242 assert!(buffer.is_empty());
243 assert!(!buffer.is_valid(h4)); let h6 = buffer.push(60); assert_eq!(buffer.get(h6), Some(&60));
246 }
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}