allocvec/
lib.rs

1#![no_std]
2
3extern crate alloc;
4
5use alloc::vec::Vec;
6use core::mem::replace;
7use core::ops::{Index, IndexMut};
8
9/// Simple wrapper for Vec that handles allocating / deallocating
10/// slots inside the vector, optimized for frequent indexing and
11/// frequent allocations / de-allocations.
12///
13/// The index obtained through allocation is guaranteed to remain the same
14/// and won't be reused until deallocated
15#[derive(Debug, Clone)]
16pub struct AllocVec<T> {
17    first: usize,
18    inner: Vec<AllocState<T>>
19}
20
21impl<T> AllocVec<T> {
22    /// Creates a new `AllocVec` backed by an empty `Vec`
23    #[inline]
24    pub const fn new() -> Self {
25        Self {
26            first: 0,
27            inner: Vec::new()
28        }
29    }
30
31    /// Creates a new `AllocVec` backed by a `Vec` with the given capacity
32    #[inline]
33    pub fn with_capacity(capacity: usize) -> Self {
34        Self {
35            first: 0,
36            inner: Vec::with_capacity(capacity)
37        }
38    }
39
40    /// Returns an immutable reference to an element at the given position
41    ///
42    /// # Arguments
43    /// * `index` - The index of the element
44    ///
45    /// # Returns
46    /// * Some if the element is allocated at the index
47    /// * None otherwise
48    #[inline]
49    pub fn get(&self, index: usize) -> Option<&T> {
50        self.inner
51            .get(index)
52            .and_then(|x| match x {
53                AllocState::Unallocated(_) => None,
54                AllocState::Allocated(elem) => Some(elem)
55            })
56    }
57
58    /// Returns a mutable reference to an element at the given position
59    ///
60    /// # Arguments
61    /// * `index` - The index of the element
62    ///
63    /// # Returns
64    /// * Some if the element is allocated at the index
65    /// * None otherwise
66    #[inline]
67    pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
68        self.inner
69            .get_mut(index)
70            .and_then(|x| match x {
71                AllocState::Unallocated(_) => None,
72                AllocState::Allocated(elem) => Some(elem)
73            })
74    }
75
76    /// Constructs a new vector containing all the elements of this
77    /// `AllocVec` that are allocated
78    #[inline]
79    pub fn into_vec(self) -> Vec<T> {
80        self.inner
81            .into_iter()
82            .map(|x| match x {
83                AllocState::Unallocated(_) => None,
84                AllocState::Allocated(elem) => Some(elem),
85            })
86            .flatten()
87            .collect()
88    }
89
90    /// Allocates a space and populates it with `item`. No guarantees are made about
91    /// the value of the returned index, except that it will remain valid
92    /// until deallocated.
93    ///
94    /// # Arguments
95    /// * `item` - The item to allocate
96    ///
97    /// # Returns
98    /// * The index of the newly allocated item
99    #[inline]
100    pub fn alloc(&mut self, item: T) -> usize {
101        self.alloc_cyclic(move |_| item)
102    }
103
104    /// Allocates a space and populates it with an item given by the closure `f`,
105    /// which will receive the allocation index as a parameter. Useful for items that
106    /// need to contain information about the index they are allocated in
107    ///
108    /// # Arguments
109    /// * `f` - A closure that will receive the index and return the item to populate with
110    ///
111    /// # Returns
112    /// * The index of the newly allocated space, equal to the index the closure sees
113    #[inline]
114    pub fn alloc_cyclic<F>(&mut self, f: F) -> usize
115    where F: FnOnce(usize) -> T
116    {
117        let free_slot = self.inner.get(self.first).and_then(|x| {
118            match x {
119                AllocState::Unallocated(next) => Some(replace(&mut self.first, *next)),
120                AllocState::Allocated(_) => None
121            }
122        });
123
124        match free_slot {
125            Some(index) => {
126                self.inner.insert(index, AllocState::Allocated(f(index)));
127                index
128            },
129            None => {
130                let index = self.inner.len();
131                self.first = index + 1;
132                self.inner.push(AllocState::Allocated(f(index)));
133                index
134            }
135        }
136    }
137
138    /// Deallocates the space at the given index if it is allocated.
139    ///
140    /// # Arguments
141    /// * `index` - The index of the space to deallocate
142    ///
143    /// # Returns
144    /// * `Some` if the space at the given index was allocated
145    /// * `None` otherwise
146    #[inline]
147    pub fn dealloc(&mut self, index: usize) -> Option<T> {
148        self.inner.get_mut(index).and_then(|state| {
149            match state {
150                AllocState::Unallocated(_) => None,
151                AllocState::Allocated(_) => {
152                    let old_first = replace(&mut self.first, index);
153                    let old_state = replace(state, AllocState::Unallocated(old_first));
154                    match old_state {
155                        AllocState::Unallocated(_) => unreachable!(),
156                        AllocState::Allocated(old) => Some(old)
157                    }
158                }
159            }
160        })
161    }
162
163    /// Replaces the element in the space at `index`, with `item`.
164    ///
165    /// # Arguments
166    /// * `index` - The index of the space whose item to replace
167    /// * `item` - The item to replace with
168    ///
169    /// # Returns
170    /// * `Ok<T>` if the space was allocated, where `T` is the previous value. After this method
171    /// returns `Ok` the space at `index` is to be considered populated with `item`.
172    /// * `Err` containing `item` if the space was unallocated.
173    #[inline]
174    pub fn realloc(&mut self, index: usize, item: T) -> Result<T, T> {
175        match self.inner.get_mut(index) {
176            Some(state) => {
177                match state {
178                    AllocState::Unallocated(_) => Err(item),
179                    AllocState::Allocated(old) => {
180                        let old = replace(old, item);
181                        Ok(old)
182                    }
183                }
184            },
185            None => Err(item)
186        }
187    }
188
189    /// # Arguments
190    /// * `index` - The index of the space to check
191    ///
192    /// # Returns
193    /// * Whether an element is allocated at the given index
194    #[inline]
195    pub fn is_allocated(&self, index: usize) -> bool {
196        self.inner
197            .get(index)
198            .is_some_and(|x| match x {
199                AllocState::Unallocated(_) => false,
200                AllocState::Allocated(_) => true
201            })
202    }
203
204    /// # Returns
205    /// * The total number of allocated elements
206    #[inline]
207    pub fn len(&self) -> usize {
208        self.inner.iter().filter(|x| match x {
209            AllocState::Unallocated(_) => false,
210            AllocState::Allocated(_) => true
211        }).count()
212    }
213
214    /// # Returns
215    /// * True if there are no allocated elements
216    #[inline]
217    pub fn is_empty(&self) -> bool {
218        self.len() == 0
219    }
220
221    /// # Returns
222    /// * The length of the underlying `Vec`
223    #[inline]
224    pub fn vec_len(&self) -> usize {
225        self.inner.len()
226    }
227
228    /// # Returns
229    /// * The capacity of the underlying `Vec`
230    #[inline]
231    pub fn capacity(&self) -> usize {
232        self.inner.capacity()
233    }
234
235    /// Returns an immutable iterator over the populated spaces that acts in a way similar to
236    /// `.iter().enumerate()` except the index actually represents an allocation
237    #[inline]
238    pub fn enumerate(&self) -> impl Iterator<Item = (usize, &T)> + '_ {
239        self.inner.iter()
240            .enumerate()
241            .filter(|(_, x)| if let AllocState::Allocated(_) = x { true } else { false })
242            .map(|(i, x)| if let AllocState::Allocated(x) = x { (i, x) } else { unreachable!() })
243    }
244
245    /// Returns a mutable iterator over the populated spaces that acts in a way similar to
246    /// `.iter_mut().enumerate()` except the index actually represents an allocation
247    #[inline]
248    pub fn enumerate_mut(&mut self) -> impl Iterator<Item = (usize, &mut T)> + '_ {
249        self.inner.iter_mut()
250            .enumerate()
251            .filter(|(_, x)| if let AllocState::Allocated(_) = x { true } else { false })
252            .map(|(i, x)| if let AllocState::Allocated(x) = x { (i, x) } else { unreachable!() })
253    }
254
255    /// Returns an immutable iterator over the populated spaces
256    #[inline]
257    pub fn iter(&self) -> impl Iterator<Item = &T> + '_ {
258        self.inner.iter()
259            .filter(|x| if let AllocState::Allocated(_) = x { true } else { false })
260            .map(|x| if let AllocState::Allocated(x) = x { x } else { unreachable!() })
261    }
262
263    /// Returns a mutable iterator over the populated spaces
264    #[inline]
265    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> + '_ {
266        self.inner.iter_mut()
267            .filter(|x| if let AllocState::Allocated(_) = x { true } else { false })
268            .map(|x| if let AllocState::Allocated(x) = x { x } else { unreachable!() })
269    }
270
271    /// Clears the allocvec, removing all values and resetting the internal linked list.
272    ///
273    /// Allocations will begin at index `0` again after this.
274    #[inline]
275    pub fn clear(&mut self) {
276        self.first = 0;
277        self.inner.clear();
278    }
279}
280
281impl<T: Eq> AllocVec<T> {
282    /// Iterates through the vector searching for a slot that's populated with
283    /// an item that is equal to the provided `value`.
284    ///
285    /// Requires `T` to implement [`Eq`]
286    #[inline]
287    pub fn contains(&self, value: &T) -> bool {
288        for item in self.inner.iter() {
289            if let AllocState::Allocated(value_) = item {
290                if value_ == value {
291                    return true;
292                }
293            }
294        }
295        false
296    }
297}
298
299impl<T> Index<usize> for AllocVec<T> {
300    type Output = T;
301    #[inline]
302    fn index(&self, index: usize) -> &Self::Output {
303        match self.inner[index] {
304            AllocState::Allocated(ref val) => val,
305            _ => panic!("Tried to index unallocated value")
306        }
307    }
308}
309
310impl <T> IndexMut<usize> for AllocVec<T> {
311    #[inline]
312    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
313        match self.inner[index] {
314            AllocState::Allocated(ref mut val) => val,
315            _ => panic!("Tried to index unallocated value")
316        }
317    }
318}
319
320impl<T> From<Vec<T>> for AllocVec<T> {
321    #[inline]
322    fn from(value: Vec<T>) -> Self {
323        let mut inner = Vec::with_capacity(value.len());
324        for item in value {
325            inner.push(AllocState::Allocated(item));
326        }
327        Self {
328            first: 0,
329            inner
330        }
331    }
332}
333
334#[derive(Debug, Clone, Copy)]
335enum AllocState<T> {
336    Unallocated(usize),
337    Allocated(T)
338}
339
340#[test]
341fn alloc_vec_new() {
342    let vec: AllocVec<i32> = AllocVec::new();
343    assert_eq!(vec.vec_len(), 0);
344    assert_eq!(vec.capacity(), 0);
345}
346
347#[test]
348fn alloc_vec_with_capacity() {
349    let vec: AllocVec<i32> = AllocVec::with_capacity(15);
350    assert_eq!(vec.vec_len(), 0);
351    assert!(vec.capacity() >= 15);
352}
353
354#[test]
355fn alloc_vec_alloc_access_dealloc() {
356    let mut vec: AllocVec<i32> = AllocVec::new();
357    let (idx1, idx2, idx3) = (vec.alloc(24), vec.alloc(98), vec.alloc(12));
358
359    {
360        let (get1, get2, get3) = (vec.get(idx1), vec.get(idx2), vec.get(idx3));
361        assert!(get1.is_some());
362        assert!(get2.is_some());
363        assert!(get3.is_some());
364    }
365
366    assert_eq!(vec[idx1], 24);
367    assert_eq!(vec[idx2], 98);
368    assert_eq!(vec[idx3], 12);
369
370    vec.dealloc(idx2);
371    assert!(vec.get(idx1).is_some());
372    assert!(vec.get(idx2).is_none());
373    assert!(vec.get(idx3).is_some());
374
375    vec.dealloc(idx1);
376    assert!(vec.get(idx1).is_none());
377    assert!(vec.get(idx2).is_none());
378    assert!(vec.get(idx3).is_some());
379
380    vec.dealloc(idx3);
381    assert!(vec.get(idx1).is_none());
382    assert!(vec.get(idx2).is_none());
383    assert!(vec.get(idx3).is_none());
384}
385
386#[test]
387fn alloc_vec_reallocation() {
388    let mut vec: AllocVec<i32> = AllocVec::new();
389    let (idx1, mut idx2, idx3) = (vec.alloc(456), vec.alloc(10), vec.alloc(14));
390
391    assert_eq!(vec[idx1], 456);
392    assert_eq!(vec[idx2], 10);
393    assert_eq!(vec[idx3], 14);
394
395    vec.dealloc(idx2);
396    idx2 = vec.alloc(145);
397    assert_eq!(vec[idx2], 145);
398}
399
400#[test]
401fn alloc_vec_mut() {
402    let mut vec: AllocVec<i32> = AllocVec::new();
403    let idx = vec.alloc(15);
404
405    assert_eq!(vec[idx], 15);
406    vec[idx] = 20;
407    assert_eq!(vec[idx], 20);
408}
409
410#[test]
411fn alloc_vec_iter() {
412    let mut vec: AllocVec<i32> = AllocVec::new();
413    let idx1 = vec.alloc(15);
414    let idx2 = vec.alloc(90);
415    let idx3 = vec.alloc(75);
416    let idx4 = vec.alloc(42);
417
418    vec.dealloc(idx2);
419    let _ = vec.realloc(idx3, 7);
420
421    let collect: Vec<i32> = vec.iter().map(|x| *x).collect();
422    assert_eq!(collect[0], 15);
423    assert_eq!(collect[1], 7);
424    assert_eq!(collect[2], 42);
425
426    let collect: Vec<(usize, i32)> = vec.enumerate().map(|(i, x)| (i, *x)).collect();
427    assert_eq!(collect[0], (idx1, 15));
428    assert_eq!(collect[1], (idx3, 7));
429    assert_eq!(collect[2], (idx4, 42));
430}
431
432#[test]
433fn alloc_vec_getters() {
434    let mut vec: AllocVec<i32> = AllocVec::new();
435    let idx1 = vec.alloc(15);
436    let idx2 = vec.alloc(90);
437    let idx3 = vec.alloc(75);
438    let idx4 = vec.alloc(42);
439
440    vec.dealloc(idx2);
441    let _ = vec.realloc(idx3, 8);
442
443    assert!(vec.is_allocated(idx1));
444    assert!(!vec.is_allocated(idx2));
445    assert!(vec.is_allocated(idx3));
446    assert!(vec.is_allocated(idx4));
447}
448
449#[test]
450fn alloc_vec_cyclic() {
451    let mut vec: AllocVec<i32> = AllocVec::new();
452    let mut closure_idx = None;
453    let idx = vec.alloc_cyclic(|idx| {
454        closure_idx = Some(idx);
455        42
456    });
457
458    assert_eq!(idx, closure_idx.unwrap());
459}