gen_inds/
vec_based.rs

1use crate::Error;
2use simple_error::bail;
3
4#[derive(Clone, Copy, Debug)]
5pub struct GenIndex {
6    index: usize,
7    generation: u32,
8}
9
10#[derive(Debug)]
11struct GenIndexEntry<T> {
12    key: GenIndex,
13    value: Option<T>,
14}
15
16pub struct GenIndexAllocator<T> {
17    entries: Vec<GenIndexEntry<T>>,
18    free_indices: Vec<usize>,
19}
20
21impl<T> GenIndexAllocator<T> {
22    pub fn new() -> Self {
23        Self::with_capacity(100)
24    }
25
26    pub fn with_capacity(capacity: usize) -> Self {
27        Self {
28            entries: Vec::with_capacity(capacity),
29            // We assume that in most use cases, not all indices will be freed at the same time
30            free_indices: Vec::with_capacity(capacity / 4),
31        }
32    }
33
34    pub fn allocate(&mut self, value: T) -> Result<GenIndex, Error> {
35        match self.free_indices.pop() {
36            None => {
37                let new_key = GenIndex {
38                    index: self.entries.len(),
39                    generation: 0,
40                };
41                self.entries.push(GenIndexEntry {
42                    key: new_key,
43                    value: Some(value),
44                });
45                Ok(new_key)
46            }
47            Some(free_idx) => match self.entries.get_mut(free_idx) {
48                None => bail!(
49                    "GenIndexAllocator::allocate: Could not find free index that should exist"
50                ),
51                Some(entry) => {
52                    entry.key.generation += 1;
53                    entry.value.replace(value);
54                    Ok(entry.key)
55                }
56            },
57        }
58    }
59
60    pub fn deallocate(&mut self, key: &GenIndex) -> Result<Option<T>, Error> {
61        match self.entries.get_mut(key.index) {
62            None => bail!("GenIndexAllocator::deallocate: Index not found"),
63            Some(entry) => {
64                if entry.key.generation != key.generation {
65                    bail!("GenIndexAllocator::deallocate: Wrong generation");
66                }
67
68                let value = entry.value.take();
69                self.free_indices.push(key.index);
70                Ok(value)
71            }
72        }
73    }
74
75    pub fn get(&self, key: &GenIndex) -> Option<&T> {
76        match self.entries.get(key.index) {
77            None => None,
78            Some(entry) => {
79                if entry.key.generation != key.generation {
80                    return None;
81                }
82
83                (entry.value).as_ref()
84            }
85        }
86    }
87
88    pub fn get_mut(&mut self, key: &GenIndex) -> Option<&mut T> {
89        match self.entries.get_mut(key.index) {
90            None => None,
91            Some(entry) => {
92                if entry.key.generation != key.generation {
93                    return None;
94                }
95
96                (entry.value).as_mut()
97            }
98        }
99    }
100
101    pub fn set(&mut self, key: &GenIndex, value: T) -> Result<T, Error> {
102        match self.entries.get_mut(key.index) {
103            None => bail!("GenIndexAllocator::set: Entry for key not found"),
104            Some(entry) => {
105                if entry.key.generation != key.generation {
106                    bail!("GenIndexAllocator::set: Entry exists but generation does not match");
107                }
108
109                entry
110                    .value
111                    .replace(value)
112                    .ok_or_else(|| {
113                        simple_error::SimpleError::new(
114                            "GenIndexAllocator::set: Entry to overwrite is empty but should not be",
115                        )
116                    })
117                    .map_err(|e| e.into())
118            }
119        }
120    }
121}
122
123impl<T> Default for GenIndexAllocator<T> {
124    fn default() -> Self {
125        Self::new()
126    }
127}
128
129#[cfg(test)]
130mod test {
131    use super::*;
132
133    #[test]
134    fn test_create_with_capacity() -> Result<(), Error> {
135        let capacity = 200;
136        let gen_alloc = GenIndexAllocator::<i32>::with_capacity(capacity);
137        assert_eq!(gen_alloc.entries.capacity(), capacity);
138        Ok(())
139    }
140
141    #[test]
142    fn test_allocate_and_get() -> Result<(), Error> {
143        let mut gen_alloc = GenIndexAllocator::with_capacity(10);
144
145        // Create value and check it
146        let value1 = 1i32;
147        let key1 = gen_alloc.allocate(value1)?;
148        assert_eq!(gen_alloc.entries.len(), 1);
149        assert_eq!(gen_alloc.get(&key1), Some(&value1));
150
151        Ok(())
152    }
153
154    #[test]
155    fn test_allocate_and_set() -> Result<(), Error> {
156        let mut gen_alloc = GenIndexAllocator::with_capacity(10);
157
158        // Create value and check it
159        let value1 = 1i32;
160        let key1 = gen_alloc.allocate(value1)?;
161        assert_eq!(gen_alloc.entries.len(), 1);
162        assert_eq!(gen_alloc.get(&key1), Some(&value1));
163
164        // Create value and check it
165        let value2 = 2i32;
166        let key2 = gen_alloc.allocate(value2)?;
167        assert_eq!(gen_alloc.entries.len(), 2);
168        assert_eq!(gen_alloc.get(&key2), Some(&value2));
169
170        // Set first key to different value - the second value should be unchanged
171        let new_value1 = 99i32;
172        gen_alloc.set(&key1, new_value1)?;
173        assert_eq!(gen_alloc.entries.len(), 2);
174        assert_eq!(gen_alloc.get(&key1), Some(&new_value1));
175        assert_eq!(gen_alloc.get(&key2), Some(&value2));
176
177        Ok(())
178    }
179
180    #[test]
181    fn test_reuse_free_indices() -> Result<(), Error> {
182        let capacity = 5;
183        let mut gen_alloc = GenIndexAllocator::with_capacity(capacity);
184        assert_eq!(gen_alloc.entries.len(), 0);
185        assert_eq!(gen_alloc.entries.capacity(), capacity);
186
187        let mut alloced_keys: Vec<_> = (0..capacity)
188            .into_iter()
189            .map(|value| gen_alloc.allocate(value).expect("Should allocate"))
190            .collect();
191
192        // We created the values in order - check that each key points to the right value
193        for (value, key) in alloced_keys.iter().enumerate() {
194            assert_eq!(gen_alloc.get(key), Some(&value));
195        }
196
197        // Split the keys and free some of them
198        let num_keys_to_free = 2;
199        let to_free = alloced_keys.split_off(capacity - num_keys_to_free);
200
201        for key in to_free.iter() {
202            gen_alloc.deallocate(key)?;
203        }
204
205        assert_eq!(
206            gen_alloc.entries.len(),
207            capacity,
208            "We do not remove entries so the length should be unchanged"
209        );
210        assert_eq!(
211            gen_alloc.entries.capacity(),
212            capacity,
213            "We do not exceed capacity so it should be unchanged"
214        );
215
216        // Reuse indices, the capacity should be unchanged but old keys should get invalid
217        let reused_entries_keys: Vec<_> = (0..num_keys_to_free)
218            .into_iter()
219            .map(|value| gen_alloc.allocate(value).expect("Should allocate"))
220            .collect();
221
222        assert_eq!(
223            gen_alloc.entries.len(),
224            capacity,
225            "We do not remove entries so the length should be unchanged"
226        );
227        assert_eq!(
228            gen_alloc.entries.capacity(),
229            capacity,
230            "We do not exceed capacity so it should be unchanged"
231        );
232
233        for key in to_free.iter() {
234            assert_eq!(
235                gen_alloc.get(key),
236                None,
237                "This key should be invalid because the generation does not match"
238            );
239        }
240
241        for (value, key) in reused_entries_keys.iter().enumerate() {
242            assert_eq!(gen_alloc.get(key), Some(&value));
243        }
244
245        Ok(())
246    }
247}