Skip to main content

logicsim/data_structures/
slab.rs

1use std::fmt::{self, Display, Formatter};
2
3/// Transparent type that represents an index into a [Slab].
4///
5/// used to discourage accessing the [Slab] at arbitrary indexes.
6#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
7#[repr(transparent)]
8pub struct SlabIndex(pub(super) usize);
9impl SlabIndex {
10    /// Returns the inner [usize].
11    ///
12    /// Annoyingly long names discourage use and make you really think about what you are doing.
13    pub fn i_actually_really_know_what_i_am_doing_and_i_want_the_inner_usize(&self) -> usize {
14        self.0
15    }
16    /// Returns a new [SlabIndex] created from the provided [usize].
17    /// Annoyingly long names discourage use and make you really think about what you are doing.
18    pub fn i_actually_really_know_what_i_am_doing_and_i_want_to_construct_from_usize(
19        i: usize,
20    ) -> Self {
21        Self(i)
22    }
23}
24impl Display for SlabIndex {
25    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
26        write!(f, "{}", self.0)
27    }
28}
29
30/// Simple slab allocator. Stores items of the same type and can reuse removed indexes.
31///
32/// # Example
33///
34/// ```
35/// # use logicsim::data_structures::Slab;
36/// let mut s = Slab::new();
37///
38/// let index = s.insert(5);
39/// assert_eq!(s.get(index), Some(&5));
40///
41/// assert_eq!(s.remove(index), Some(5));
42///
43/// assert_eq!(s.get(index), None);
44/// ```
45#[derive(Debug, Clone)]
46pub struct Slab<T: Sized> {
47    data: Vec<Option<T>>,
48    removed_indexes: Vec<SlabIndex>,
49}
50#[allow(dead_code)]
51impl<T: Sized> Slab<T> {
52    /// Returns an empty [Slab].
53    pub fn new() -> Self {
54        Self {
55            data: Vec::new(),
56            removed_indexes: Default::default(),
57        }
58    }
59
60    /// Inserts an item into the slab and returns its index.
61    ///
62    /// Will reuse an empty index if one is available.
63    pub fn insert(&mut self, item: T) -> SlabIndex {
64        if let Some(index) = self.removed_indexes.pop() {
65            self.data[index.0] = Some(item);
66            index
67        } else {
68            let index = SlabIndex(self.data.len());
69            self.data.push(Some(item));
70            index
71        }
72    }
73
74    /// Returns a mutable reference to the item at `index`.
75    ///
76    /// Returns [None] if `index` has been removed.
77    pub fn get_mut(&mut self, index: SlabIndex) -> Option<&mut T> {
78        if let Some(item) = self.data.get_mut(index.0) {
79            return item.as_mut();
80        }
81        None
82    }
83
84    /// Return a reference to the item at `index`.
85    ///
86    /// Returns [None] if `index` has been removed.
87    pub fn get(&self, index: SlabIndex) -> Option<&T> {
88        if let Some(item) = self.data.get(index.0) {
89            return item.as_ref();
90        }
91        None
92    }
93
94    /// Removes an item from the Slab and returns it.
95    ///
96    /// Returns [None] if `index` has been removed.
97    /// `index` will be reused on the next call to [Slab::insert].
98    pub fn remove(&mut self, index: SlabIndex) -> Option<T> {
99        if let Some(position) = self.data.get_mut(index.0) {
100            if position.is_none() {
101                return None;
102            }
103            self.removed_indexes.push(index);
104            return position.take();
105        }
106        None
107    }
108
109    /// Returns the number of items in the slab.
110    ///
111    /// This is different from the number of allocated slots in the slab, see [Slab::total_len]
112    pub fn len(&self) -> usize {
113        self.data.len() - self.removed_indexes.len()
114    }
115
116    /// Returns true if the number of items in the slab is 0.
117    ///
118    /// This is different from the number of allocated slots in the slab, see [Slab::total_len]
119    pub fn is_empty(&self) -> bool {
120        self.len() == 0
121    }
122
123    /// Returns the number of allocated slots in the slab, some of them could be empty.
124    pub fn total_len(&self) -> usize {
125        self.data.len()
126    }
127
128    /// Returns an iterator over pairs of ```(SlabIndex, [&T])```.
129    pub fn iter(&self) -> Iter<T> {
130        Iter {
131            iter: self.data.iter().enumerate(),
132        }
133    }
134
135    /// Returns the item at index without performing bounds checking or checking if the slot contains initialized data.
136    ///
137    /// # Safety
138    /// This function is safe if `index` < [Slab::total_len()]
139    /// and the item at `index` has not been removed.
140    /// Will panic in debug mode if the invariants are broken.
141    ///
142    /// Annoyingly long names discourage use and make you really think about what you are doing.
143    pub unsafe fn get_very_unsafely(&self, index: SlabIndex) -> &T {
144        debug_assert!(
145            index.0 < self.data.len(),
146            "Tried to access index out of bounds, len:{}, index:{}",
147            self.data.len(),
148            index
149        );
150        debug_assert!(
151            !self.removed_indexes.contains(&index),
152            "Tried to access removed index:{}",
153            index
154        );
155        &self.data.get_unchecked(index.0).as_ref().unwrap()
156    }
157}
158
159/// [IntoIterator] for [Slab]
160pub struct IntoIter<T> {
161    slab: Slab<T>,
162    i: SlabIndex,
163}
164impl<T> IntoIterator for Slab<T> {
165    type IntoIter = IntoIter<T>;
166    type Item = (SlabIndex, T);
167    fn into_iter(self) -> Self::IntoIter {
168        IntoIter {
169            slab: self,
170            i: SlabIndex(0),
171        }
172    }
173}
174impl<T> Iterator for IntoIter<T> {
175    type Item = (SlabIndex, T);
176    fn next(&mut self) -> Option<Self::Item> {
177        loop {
178            if self.i.0 == self.slab.data.len() {
179                return None;
180            }
181            let item = self.slab.data[self.i.0].take();
182
183            if item.is_none() {
184                self.i.0 += 1;
185                continue;
186            }
187            // This is safe because we check if the item is an empty space.
188            let item = Some((self.i, item.unwrap()));
189            self.i.0 += 1;
190            return item;
191        }
192    }
193}
194
195/// [Iterator] for [Slab]
196pub struct Iter<'a, T> {
197    iter: std::iter::Enumerate<std::slice::Iter<'a, Option<T>>>,
198}
199impl<'a, T> Iterator for Iter<'a, T> {
200    type Item = (SlabIndex, &'a T);
201    fn next(&mut self) -> Option<Self::Item> {
202        loop {
203            let (i, item) = self.iter.next()?;
204            let si = SlabIndex(i);
205
206            if item.is_none() {
207                continue;
208            }
209
210            // This is safe because we check if the item is an empty space.
211            return Some((si, item.as_ref().unwrap()));
212        }
213    }
214}
215
216impl<T> Default for Slab<T> {
217    fn default() -> Self {
218        Self::new()
219    }
220}
221
222#[cfg(test)]
223mod tests {
224    use super::*;
225
226    #[test]
227    fn test_insert_get() {
228        let mut s: Slab<_> = Default::default();
229
230        assert_eq!(s.get(SlabIndex(0)), None);
231
232        let index = s.insert(1);
233        assert_eq!(*s.get(index).unwrap(), 1);
234        assert_eq!(s.get(SlabIndex(1)), None);
235
236        s.remove(index);
237        assert_eq!(s.get(index), None);
238    }
239
240    #[test]
241    fn test_get_mut() {
242        let mut s: Slab<_> = Default::default();
243
244        assert_eq!(s.get_mut(SlabIndex(0)), None);
245
246        let index = s.insert(1);
247        assert_eq!(*s.get_mut(index).unwrap(), 1);
248        assert_eq!(s.get_mut(SlabIndex(1)), None);
249
250        s.remove(index);
251        assert_eq!(s.get_mut(index), None);
252    }
253
254    #[test]
255    fn test_remove() {
256        let mut s = Slab::new();
257
258        assert_eq!(s.remove(SlabIndex(0)), None);
259
260        let index = s.insert(1);
261        assert_eq!(s.remove(index), Some(1));
262
263        let new_index = s.insert(2);
264        assert_eq!(index, new_index);
265        assert_eq!(s.remove(new_index), Some(2));
266    }
267
268    #[test]
269    fn test_len() {
270        let mut s = Slab::new();
271
272        assert_eq!(s.len(), 0);
273        assert_eq!(s.is_empty(), true);
274        assert_eq!(s.total_len(), 0);
275
276        let index = s.insert(1);
277        assert_eq!(s.len(), 1);
278        assert_eq!(s.is_empty(), false);
279        assert_eq!(s.total_len(), 1);
280
281        s.remove(index);
282        assert_eq!(s.len(), 0);
283        assert_eq!(s.is_empty(), true);
284        assert_eq!(s.total_len(), 1);
285    }
286
287    #[test]
288    fn test_iter() {
289        let mut s = Slab::new();
290        for i in 0..10 {
291            s.insert(i);
292        }
293        for i in (1..10).step_by(2) {
294            s.remove(SlabIndex(i));
295        }
296        for (i, n) in s.iter() {
297            assert_eq!(i.0, *n)
298        }
299    }
300
301    #[test]
302    fn test_into_iter() {
303        let mut s = Slab::new();
304        for i in 0..10 {
305            s.insert(i);
306        }
307        for i in (0..10).step_by(2) {
308            s.remove(SlabIndex(i));
309        }
310        for (i, n) in s.into_iter() {
311            assert_eq!(i.0, n)
312        }
313    }
314
315    #[test]
316    fn test_clone() {
317        let mut s = Slab::new();
318        for i in 0..10 {
319            s.insert(i);
320        }
321        for i in (0..10).step_by(2) {
322            s.remove(SlabIndex(i));
323        }
324        let ss = s.clone();
325        for ((i1, n1), (i2, n2)) in s.into_iter().zip(ss) {
326            assert_eq!(i1, i2);
327            assert_eq!(n1, n2);
328        }
329    }
330    #[test]
331    fn test_get_very_unsafely() {
332        let mut s = Slab::new();
333
334        let index = s.insert(1);
335        let other_index = s.insert(2);
336
337        s.remove(index);
338        unsafe { assert_eq!(*s.get_very_unsafely(other_index), 2) };
339    }
340
341    #[test]
342    #[cfg(debug_assertions)]
343    #[should_panic(expected = "Tried to access index out of bounds, len:0, index:0")]
344    fn test_get_very_unsafely_panics_out_of_bounds() {
345        let s = Slab::<u8>::new();
346
347        unsafe { assert_eq!(*s.get_very_unsafely(SlabIndex(0)), 2) };
348    }
349
350    #[test]
351    #[cfg(debug_assertions)]
352    #[should_panic(expected = "Tried to access removed index:1")]
353    fn test_get_very_unsafely_panics_removed_index() {
354        let mut s = Slab::<u8>::new();
355
356        s.insert(3);
357        let index = s.insert(2);
358        s.insert(4);
359
360        s.remove(index);
361
362        unsafe { assert_eq!(*s.get_very_unsafely(index), 2) };
363    }
364}