generational_buffer/
generational_buffer.rs1use std::fmt;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub struct Handle {
6 index: usize,
7 generation: u32,
8}
9
10impl Handle {
11 fn new(index: usize, generation: u32) -> Self {
12 Self { index, generation }
13 }
14}
15
16pub struct GenerationalBuffer<T> {
21 entries: Vec<T>,
22 max_capacity: usize,
23 next_index: usize,
24 current_generation: u32,
25}
26
27impl<T> GenerationalBuffer<T> {
28 pub fn new(max_capacity: usize) -> Self {
30 Self {
31 entries: Vec::new(),
32 max_capacity,
33 next_index: 0,
34 current_generation: 0,
35 }
36 }
37
38 pub fn capacity(&self) -> usize {
40 self.max_capacity
41 }
42
43 pub fn len(&self) -> usize {
45 self.entries.len()
46 }
47
48 pub fn is_empty(&self) -> bool {
50 self.entries.is_empty()
51 }
52
53 pub fn is_full(&self) -> bool {
55 self.entries.len() == self.max_capacity
56 }
57
58 pub fn push(&mut self, value: T) -> Handle {
60 let index = self.next_index;
61 let generation = self.current_generation;
62
63 if self.entries.len() < self.max_capacity {
64 self.entries.push(value);
66 } else {
67 self.entries[index] = value;
69 }
70
71 let handle = Handle::new(index, generation);
73
74 self.next_index = (self.next_index + 1) % self.max_capacity;
76
77 if self.next_index == 0 {
79 self.current_generation = self.current_generation.wrapping_add(1);
80 }
81
82 handle
83 }
84
85 pub fn get(&self, handle: Handle) -> Option<&T> {
87 if handle.index >= self.entries.len() {
88 return None;
89 }
90
91 let expected_generation = self.calculate_generation_at_index(handle.index);
93
94 if handle.generation == expected_generation {
96 Some(&self.entries[handle.index])
97 } else {
98 None
99 }
100 }
101
102 pub fn get_mut(&mut self, handle: Handle) -> Option<&mut T> {
104 if handle.index >= self.entries.len() {
105 return None;
106 }
107
108 let expected_generation = self.calculate_generation_at_index(handle.index);
110
111 if handle.generation == expected_generation {
113 Some(&mut self.entries[handle.index])
114 } else {
115 None
116 }
117 }
118
119 pub fn is_valid(&self, handle: Handle) -> bool {
121 if handle.index >= self.entries.len() {
122 return false;
123 }
124
125 let expected_generation = self.calculate_generation_at_index(handle.index);
126 handle.generation == expected_generation
127 }
128
129 pub fn iter(&self) -> impl Iterator<Item = (Handle, &T)> {
132 self.entries.iter().enumerate().map(|(i, value)| {
133 let generation = self.calculate_generation_at_index(i);
134 (Handle::new(i, generation), value)
135 })
136 }
137
138 pub fn values(&self) -> impl Iterator<Item = &T> {
140 self.entries.iter()
141 }
142
143 pub fn handles(&self) -> impl Iterator<Item = Handle> + '_ {
145 (0..self.entries.len()).map(move |i| {
146 let generation = self.calculate_generation_at_index(i);
147 Handle::new(i, generation)
148 })
149 }
150
151 pub fn clear(&mut self) {
153 self.entries.clear();
154 self.next_index = 0;
155 self.current_generation = 0;
156 }
157
158 fn calculate_generation_at_index(&self, index: usize) -> u32 {
160 if index < self.next_index {
161 self.current_generation
162 } else {
163 self.current_generation.saturating_sub(1)
164 }
165 }
166}
167
168impl<T: fmt::Debug> fmt::Debug for GenerationalBuffer<T> {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 f.debug_struct("GenerationalBuffer")
171 .field("capacity", &self.capacity())
172 .field("len", &self.len())
173 .field("next_index", &self.next_index)
174 .field("current_generation", &self.current_generation)
175 .field("entries", &self.entries)
176 .finish()
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183
184 #[test]
185 fn test_basic_operations() {
186 let mut buffer = GenerationalBuffer::new(3);
187
188 let h1 = buffer.push(10);
190 let h2 = buffer.push(20);
191 let h3 = buffer.push(30);
192
193 assert_eq!(buffer.get(h1), Some(&10));
195 assert_eq!(buffer.get(h2), Some(&20));
196 assert_eq!(buffer.get(h3), Some(&30));
197 assert_eq!(buffer.len(), 3);
198 assert!(buffer.is_full());
199 }
200
201 #[test]
202 fn test_circular_wrapping() {
203 let mut buffer = GenerationalBuffer::new(2);
204
205 let h1 = buffer.push(10);
207 let h2 = buffer.push(20);
208
209 let h3 = buffer.push(30);
211
212 assert_eq!(buffer.get(h1), None);
214 assert_eq!(buffer.get(h2), Some(&20));
215 assert_eq!(buffer.get(h3), Some(&30));
216 assert!(!buffer.is_valid(h1));
217 assert!(buffer.is_valid(h2));
218 assert!(buffer.is_valid(h3));
219 assert_eq!(buffer.len(), 2);
220
221 let h4 = buffer.push(40); let h5 = buffer.push(50); assert_eq!(buffer.get(h4), Some(&40));
225 assert_eq!(buffer.get(h5), Some(&50));
226 assert!(!buffer.is_valid(h2)); assert!(!buffer.is_valid(h3)); }
229
230 #[test]
231 fn test_generation_calculation() {
232 let mut buffer = GenerationalBuffer::new(3);
233
234 let handles: Vec<_> = (0..10).map(|i| buffer.push(i)).collect();
236
237 for (i, &handle) in handles.iter().enumerate() {
239 if i < 7 {
240 assert!(!buffer.is_valid(handle), "Handle {} should be invalid", i);
241 } else {
242 assert!(buffer.is_valid(handle), "Handle {} should be valid", i);
243 }
244 }
245 }
246
247 #[test]
248 fn test_iterator() {
249 let mut buffer = GenerationalBuffer::new(3);
250
251 buffer.push(10);
252 buffer.push(20);
253 buffer.push(30);
254 buffer.push(40);
255 buffer.push(50);
256 buffer.push(60);
257 buffer.push(70);
258 buffer.push(80);
259
260 let mut values: Vec<i32> = buffer.values().cloned().collect();
261 values.sort(); assert_eq!(values, vec![60, 70, 80]);
263
264 let handles: Vec<_> = buffer.handles().collect();
265 assert_eq!(handles.len(), 3);
266
267 for handle in handles {
269 assert!(buffer.is_valid(handle));
270 }
271 }
272
273 #[test]
274 fn test_growing_buffer() {
275 let mut buffer = GenerationalBuffer::new(5);
276
277 let h1 = buffer.push(1);
279 let h2 = buffer.push(2);
280 let h3 = buffer.push(3);
281
282 assert_eq!(buffer.len(), 3);
283 assert!(!buffer.is_full());
284
285 assert!(buffer.is_valid(h1));
287 assert!(buffer.is_valid(h2));
288 assert!(buffer.is_valid(h3));
289
290 assert_eq!(buffer.get(h1), Some(&1));
292 assert_eq!(buffer.get(h2), Some(&2));
293 assert_eq!(buffer.get(h3), Some(&3));
294 }
295}