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 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 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 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 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 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 for (value, key) in alloced_keys.iter().enumerate() {
194 assert_eq!(gen_alloc.get(key), Some(&value));
195 }
196
197 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 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}