rafx_base/slab/
raw_slab.rs

1use std::prelude::v1::*;
2
3use super::SlabIndexT;
4use std::hash::{Hash, Hasher};
5use std::marker::PhantomData;
6
7/// A key to a value in a RawSlab
8pub struct RawSlabKey<T: Sized> {
9    /// Raw location within the slab
10    index: SlabIndexT,
11
12    phantom_data: PhantomData<T>,
13}
14
15impl<T: Sized> Clone for RawSlabKey<T> {
16    fn clone(&self) -> RawSlabKey<T> {
17        RawSlabKey {
18            index: self.index,
19            phantom_data: Default::default(),
20        }
21    }
22}
23
24impl<T: Sized> Copy for RawSlabKey<T> {}
25
26impl<T: Sized> PartialEq for RawSlabKey<T> {
27    fn eq(
28        &self,
29        other: &Self,
30    ) -> bool {
31        self.index == other.index
32    }
33}
34
35impl<T: Sized> Eq for RawSlabKey<T> {}
36
37impl<T: Sized> Hash for RawSlabKey<T> {
38    fn hash<H: Hasher>(
39        &self,
40        state: &mut H,
41    ) {
42        self.index.hash(state);
43    }
44}
45
46impl<T: Sized> std::fmt::Debug for RawSlabKey<T> {
47    fn fmt(
48        &self,
49        f: &mut std::fmt::Formatter<'_>,
50    ) -> std::fmt::Result {
51        f.debug_struct("RawSlabKey")
52            .field("index", &self.index)
53            .finish()
54    }
55}
56
57impl<T: Sized> RawSlabKey<T> {
58    pub fn new(index: SlabIndexT) -> Self {
59        RawSlabKey {
60            index,
61            phantom_data: PhantomData,
62        }
63    }
64
65    pub fn index(self) -> SlabIndexT {
66        self.index
67    }
68}
69
70/// A very simple, minimalist slab structure. Consider using one of the other slabs instead as they
71/// are less error prone for many use-cases.
72pub struct RawSlab<T> {
73    /// List of Ts, will be tightly packed
74    storage: Vec<Option<T>>,
75
76    /// List of unused indexes within the storage
77    free_list: Vec<SlabIndexT>,
78}
79
80impl<T> Default for RawSlab<T> {
81    fn default() -> Self {
82        Self::with_capacity(32)
83    }
84}
85
86impl<T> RawSlab<T> {
87    /// Create an empty RawSlab
88    pub fn new() -> Self {
89        Default::default()
90    }
91
92    pub fn clear(&mut self) {
93        self.storage.clear();
94        self.free_list.clear();
95    }
96
97    /// Create an empty but presized RawSlab
98    pub fn with_capacity(capacity: SlabIndexT) -> Self {
99        let mut storage = Vec::with_capacity(capacity as usize);
100        let mut free_list = Vec::with_capacity(capacity as usize);
101
102        // reverse count so index 0 is at the top of the free list
103        for index in (0..capacity).rev() {
104            storage.push(None);
105            free_list.push(index);
106        }
107
108        RawSlab { storage, free_list }
109    }
110
111    /// Allocate a slot within the raw slab.
112    ///
113    /// Allocation can cause vectors to be resized. Use `with_capacity` to avoid this.
114    pub fn allocate(
115        &mut self,
116        value: T,
117    ) -> RawSlabKey<T> {
118        let index = self.free_list.pop();
119
120        if let Some(index) = index {
121            // Reuse a free slot
122            assert!(self.storage[index as usize].is_none());
123            self.storage[index as usize] = Some(value);
124            RawSlabKey::new(index)
125        } else {
126            let index = self.storage.len() as SlabIndexT;
127            self.storage.push(Some(value));
128
129            RawSlabKey::new(index)
130        }
131    }
132
133    pub fn allocate_with_key<F: FnMut(RawSlabKey<T>) -> T>(
134        &mut self,
135        mut f: F,
136    ) -> RawSlabKey<T> {
137        let index = self.free_list.pop();
138
139        if let Some(index) = index {
140            // Reuse a free slot
141            assert!(self.storage[index as usize].is_none());
142            let slab_key = RawSlabKey::new(index);
143            let value = (f)(slab_key);
144            self.storage[index as usize] = Some(value);
145            slab_key
146        } else {
147            let index = self.storage.len() as SlabIndexT;
148            let slab_key = RawSlabKey::new(index);
149            let value = (f)(slab_key);
150            self.storage.push(Some(value));
151            slab_key
152        }
153    }
154
155    /// Free an element in the raw slab. It is fatal to free an element that doesn't exist.
156    pub fn free(
157        &mut self,
158        slab_key: RawSlabKey<T>,
159    ) {
160        assert!(
161            self.storage[slab_key.index as usize].is_some(),
162            "tried to free a none value"
163        );
164        self.storage[slab_key.index as usize] = None;
165        self.free_list.push(slab_key.index);
166    }
167
168    /// Check if an element exists
169    pub fn exists(
170        &self,
171        slab_key: RawSlabKey<T>,
172    ) -> bool {
173        self.storage[slab_key.index as usize].is_some()
174    }
175
176    /// Try to get the given element
177    pub fn get(
178        &self,
179        slab_key: RawSlabKey<T>,
180    ) -> Option<&T> {
181        // Non-mutable return value so we can return a ref to the value in the vec
182
183        self.storage[slab_key.index as usize].as_ref()
184    }
185
186    /// Try to get the given element
187    pub fn get_mut(
188        &mut self,
189        slab_key: RawSlabKey<T>,
190    ) -> Option<&mut T> {
191        // Mutable reference, and we don't want the caller messing with the Option in the vec,
192        // so create a new Option with a mut ref to the value in the vec
193        self.storage[slab_key.index as usize].as_mut()
194    }
195
196    /// Iterate all values
197    pub fn iter(&self) -> impl Iterator<Item = (RawSlabKey<T>, &T)> {
198        self.storage
199            .iter()
200            .enumerate()
201            .filter(|(_, value)| value.is_some())
202            .map(|(index, value)| (RawSlabKey::new(index as u32), value.as_ref().unwrap()))
203    }
204
205    /// Iterate all values
206    pub fn iter_mut(&mut self) -> impl Iterator<Item = (RawSlabKey<T>, &mut T)> {
207        self.storage
208            .iter_mut()
209            .enumerate()
210            .filter(|(_, value)| value.is_some())
211            .map(|(index, value)| (RawSlabKey::new(index as u32), value.as_mut().unwrap()))
212    }
213
214    /// Return count of allocated Ts
215    pub fn allocated_count(&self) -> usize {
216        self.storage.len() - self.free_list.len()
217    }
218
219    pub fn storage_size(&self) -> usize {
220        self.storage.len()
221    }
222}
223
224#[cfg(test)]
225mod tests {
226    use super::*;
227
228    struct TestStruct {
229        value: u32,
230    }
231
232    impl TestStruct {
233        fn new(value: u32) -> Self {
234            TestStruct { value }
235        }
236    }
237
238    // Check that trivial allocate/delete works
239    #[test]
240    fn test_allocate_deallocate_one() {
241        let mut pool = RawSlab::<TestStruct>::new();
242        let value = TestStruct::new(123);
243        let key = pool.allocate(value);
244
245        assert_eq!(1, pool.allocated_count());
246        pool.free(key);
247        assert_eq!(0, pool.allocated_count());
248    }
249
250    #[test]
251    #[should_panic(expected = "tried to free a none value")]
252    fn test_double_free() {
253        let mut pool = RawSlab::<TestStruct>::new();
254        let value = TestStruct::new(123);
255        let key = pool.allocate(value);
256
257        assert_eq!(1, pool.allocated_count());
258        pool.free(key);
259        assert_eq!(0, pool.allocated_count());
260        pool.free(key);
261    }
262
263    // Check that allocation/deallocation in order works
264    #[test]
265    fn test_allocate_deallocate_fifo() {
266        let mut pool = RawSlab::<TestStruct>::new();
267        let mut keys = vec![];
268
269        for i in 0..1000 {
270            let value = TestStruct::new(i);
271            let key = pool.allocate(value);
272            keys.push(key);
273        }
274
275        assert_eq!(1000, pool.allocated_count());
276
277        for k in keys {
278            pool.free(k);
279        }
280
281        assert_eq!(0, pool.allocated_count());
282    }
283
284    #[test]
285    fn test_allocate_deallocate_lifo() {
286        let mut pool = RawSlab::<TestStruct>::new();
287        let mut keys = vec![];
288
289        for i in 0..1000 {
290            let value = TestStruct::new(i);
291            let key = pool.allocate(value);
292            keys.push(key);
293        }
294
295        assert_eq!(1000, pool.allocated_count());
296
297        for i in (0..keys.len()).rev() {
298            pool.free(keys[i]);
299        }
300
301        assert_eq!(0, pool.allocated_count());
302    }
303
304    #[test]
305    fn test_get_success() {
306        let mut pool = RawSlab::<TestStruct>::new();
307        let mut keys = vec![];
308
309        for i in 0..10 {
310            let value = TestStruct::new(i);
311            let key = pool.allocate(value);
312            keys.push(key);
313        }
314
315        assert_eq!(10, pool.allocated_count());
316        assert_eq!(5, pool.get(keys[5]).unwrap().value);
317    }
318
319    #[test]
320    fn test_get_fail_out_of_range() {
321        let mut pool = RawSlab::<TestStruct>::new();
322        let value = TestStruct::new(123);
323        let key = pool.allocate(value);
324        assert_eq!(1, pool.allocated_count());
325
326        assert!(pool.get(key).is_some());
327
328        pool.free(key);
329        assert_eq!(0, pool.allocated_count());
330
331        assert!(pool.get(key).is_none());
332    }
333
334    #[test]
335    fn test_get_mut_success() {
336        let mut pool = RawSlab::<TestStruct>::new();
337        let mut keys = vec![];
338
339        for i in 0..10 {
340            let value = TestStruct::new(i);
341            let key = pool.allocate(value);
342            keys.push(key);
343        }
344
345        assert_eq!(10, pool.allocated_count());
346        assert_eq!(5, pool.get_mut(keys[5]).unwrap().value);
347    }
348
349    #[test]
350    fn test_get_mut_fail_out_of_range() {
351        let mut pool = RawSlab::<TestStruct>::new();
352        let value = TestStruct::new(123);
353        let key = pool.allocate(value);
354        assert_eq!(1, pool.allocated_count());
355
356        assert!(pool.get_mut(key).is_some());
357
358        pool.free(key);
359        assert_eq!(0, pool.allocated_count());
360
361        assert!(pool.get_mut(key).is_none());
362    }
363}