Skip to main content

mgf/
pool.rs

1// Copyright 2017 Matthew Plant. This file is part of MGF.
2//
3// MGF is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published by
5// the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// MGF is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11// GNU Lesser General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with MGF. If not, see <http://www.gnu.org/licenses/>.
15
16use std::mem;
17use std::slice;
18use std::iter::{Enumerate, FilterMap};
19use std::ops::{Index, IndexMut};
20use std::vec::Vec;
21
22use serde::{Serialize, Deserialize};
23
24/// Internal storage type used by Pool.
25#[derive(Serialize, Deserialize)]
26pub enum PoolEntry<T> {
27    FreeListEnd,
28    FreeListPtr {
29        next_free: usize,
30    },
31    Occupied(T)
32}
33
34/// Growable array type that allows items to be removed and inserted without
35/// changing the indices of other entries.
36#[derive(Serialize, Deserialize)]
37pub struct Pool<T> {
38    len: usize,
39    free_list: Option<usize>,
40    entries: Vec<PoolEntry<T>>,
41}
42
43impl<T> Pool<T> {
44    /// Create an empty Pool.
45    pub fn new() -> Self {
46        Pool {
47            len: 0,
48            free_list: None,
49            entries: Vec::new(),
50        }
51    }
52
53    /// Create an empty Pool large enough to fix cap items.
54    pub fn with_capacity(cap: usize) -> Self {
55        Pool {
56            len: 0,
57            free_list: None,
58            entries: Vec::with_capacity(cap),
59        }
60    }
61
62    /// Determines if the Pool is empty.
63    pub fn empty(&self) -> bool {
64        self.len == 0
65    }
66
67    /// Returns the number of occupied slots in the pool.
68    pub fn len(&self) -> usize {
69        self.len
70    }
71
72    /// Removes all entries from the pool.
73    pub fn clear(&mut self) {
74        self.len = 0;
75        self.free_list = None;
76        self.entries.clear();
77    }
78
79    /// Push a new item to the pool. Attempts to use spots left empty from
80    /// removed items before performing a heap allocation.
81    pub fn push(&mut self, item: T) -> usize {
82        self.len += 1;
83        if let Some(free_item) = self.free_list {
84            self.free_list = match self.entries[free_item] {
85                PoolEntry::FreeListEnd => None,
86                PoolEntry::FreeListPtr{ next_free } => Some(next_free),
87                _ => unreachable!(),
88            };
89            self.entries[free_item] = PoolEntry::Occupied(item);
90            free_item
91        } else {
92            let i = self.entries.len();
93            self.entries.push(PoolEntry::Occupied(item));
94            i
95        }
96    }
97
98    /// Marks an index as empty and adds it to the free list, allowing the
99    /// spot to be reclaimed later.
100    pub fn remove(&mut self, i: usize) -> T {
101        let new_entry = if let Some(free_item) = self.free_list {
102                PoolEntry::FreeListPtr{ next_free: free_item } 
103        } else {
104                PoolEntry::FreeListEnd
105        };
106        self.free_list = Some(i);
107        if let PoolEntry::Occupied(item) = mem::replace(&mut self.entries[i], new_entry) {
108            self.len -= 1;
109            item
110        } else {
111            panic!("index {} is not occupied", i);
112        }
113    }
114
115    /// Returns the next available id for reuse if one exists.
116    pub fn next_free(&self) -> Option<usize> {
117        if let Some(free) = self.free_list {
118            Some(free)
119        } else {
120            None
121        }
122    }
123    
124    pub fn iter<'a>(&'a self) -> impl Iterator<Item=(usize, &'a T)> {
125        self.into_iter()
126    }
127
128    pub fn iter_mut<'a>(&'a mut self) -> impl Iterator<Item=(usize, &'a mut T)> { 
129        self.into_iter()
130    }
131
132    /// Returns a reference to an object at the given index and None if it is
133    /// unoccupied.
134    pub fn get<'a>(&'a self, i: usize) -> Option<&'a T> {
135        if let Some(PoolEntry::Occupied(ref item)) = self.entries.get(i) {
136            Some(&item)
137        } else {
138            None
139        }
140    }
141
142    /// Returns a mutable reference to an object at the given index and None if
143    /// it is unoccupied.
144    pub fn get_mut<'a>(&'a mut self, i: usize) -> Option<&'a mut T> {
145        if let Some(PoolEntry::Occupied(ref mut item)) = self.entries.get_mut(i) {
146            Some(item)
147        } else {
148            None
149        }
150    }
151}
152        
153impl<T> Index<usize> for Pool<T> {
154    type Output = T;
155
156    fn index(&self, i: usize) -> &T {
157        if let PoolEntry::Occupied(ref item) = self.entries[i] {
158            item
159        } else {
160            panic!("index {} is not occupied", i)
161        }
162    }
163}
164
165impl<T> IndexMut<usize> for Pool<T> {
166    fn index_mut(&mut self, i: usize) -> &mut T {
167        if let PoolEntry::Occupied(ref mut item) = self.entries[i] {
168            item
169        } else {
170            panic!("index {} is not occupied", i)
171        }
172    }
173}
174
175impl<T> Clone for PoolEntry<T>
176where
177    T: Clone
178{
179    fn clone(&self) -> Self {
180        use self::PoolEntry::*;
181        match self {
182            &FreeListEnd => FreeListEnd,
183            &FreeListPtr{ next_free } => FreeListPtr{ next_free },
184            &Occupied(ref item) => Occupied(item.clone()),
185        }
186    }
187}
188
189impl<T> Clone for Pool<T>
190where
191    T: Clone
192{
193    fn clone(&self) -> Self {
194        Pool {
195            len: self.len,
196            free_list: self.free_list,
197            entries: self.entries.clone(),
198        }
199    }
200}
201
202impl<L, T> From<L> for Pool<T>
203where
204    L: IntoIterator<Item = T>
205{
206    fn from(iter: L) -> Pool<T> {
207        let mut pool = Pool::new();
208        for item in iter.into_iter() {
209            pool.push(item);
210        }
211        pool
212    }
213}
214
215fn filter_pool<'a, T>((i, item): (usize, &'a PoolEntry<T>)) -> Option<(usize, &'a T)> {
216    if let &PoolEntry::Occupied(ref item) = item {
217        Some((i, item))
218    } else {
219        None
220    }
221}
222
223impl<'a, T> IntoIterator for &'a Pool<T> {
224    type Item = (usize, &'a T);
225    type IntoIter = FilterMap<Enumerate<slice::Iter<'a, PoolEntry<T>>>, fn((usize, &PoolEntry<T>)) -> Option<(usize, &T)>>;
226
227    fn into_iter(self) -> Self::IntoIter {
228        self.entries.iter().enumerate().filter_map(filter_pool)
229    }
230}
231
232fn filter_pool_mut<'a, T>((i, item): (usize, &'a mut PoolEntry<T>)) -> Option<(usize, &'a mut T)> {
233    if let &mut PoolEntry::Occupied(ref mut item) = item {
234        Some((i, item))
235    } else {
236        None
237    }
238}
239
240impl<'a, T> IntoIterator for &'a mut Pool<T> {
241    type Item = (usize, &'a mut T);
242    type IntoIter = FilterMap<Enumerate<slice::IterMut<'a, PoolEntry<T>>>, fn((usize, &mut PoolEntry<T>)) -> Option<(usize, &mut T)>>;
243
244    fn into_iter(self) -> Self::IntoIter {
245        self.entries.iter_mut().enumerate().filter_map(filter_pool_mut)
246    }
247}
248
249#[cfg(test)]
250mod tests {
251    mod pool {
252        use crate::pool::*;
253 
254        #[test]
255        fn test_manual_code() {
256            let mut pool: Pool<usize> = Pool::new();
257
258            let id0 = pool.push(0);
259            let id1 = pool.push(1);
260            let id2 = pool.push(2);
261            let id3 = pool.push(3);
262
263            assert_eq!(id0, 0);
264            assert_eq!(id3, 3);
265
266            pool.remove(id1);
267            pool.remove(id2);
268
269            assert_eq!(pool[id0], 0);
270            assert_eq!(pool[id3], 3);
271
272            assert_eq!(pool.iter().map(|(_i, &u)|{u}).collect::<Vec<usize>>(), vec![0, 3]);
273        }
274
275        #[test]
276        fn test_pool() {
277            // Test inserting 8 items
278            {
279                let mut pool: Pool<usize> = Pool::new();
280                for i in 0..8 {
281                    pool.push(i);
282                }
283                let ids = [ 0, 1, 2, 3, 4, 5, 6, 7 ];
284                for (i, item) in pool.iter().enumerate() {
285                    assert_eq!(*item.1, ids[i]);
286                }
287                // Remove every other item
288                for i in 0..4 {
289                    pool.remove(i * 2);
290                }
291                let ids = [ 1, 3, 5, 7 ];
292                for (i, item) in pool.iter().enumerate() {
293                    assert_eq!(*item.1, ids[i]);
294                }
295                {
296                    let _removed = pool.remove(1);
297                    let ids = [ 3, 5, 7 ];
298                    for (i, item) in pool.iter().enumerate() {
299                        assert_eq!(*item.1, ids[i]);
300                    }
301                }
302            }
303            // Test inserting 16 items
304            {
305                let mut pool: Pool<usize> = Pool::new();
306                for i in 0..16 {
307                    pool.push(i);
308                }
309                let ids = [ 0, 1, 2, 3, 4, 5, 6, 7,
310                            8, 9, 10, 11, 12, 13, 14, 15 ];
311                for (i, item) in pool.iter().enumerate() {
312                    assert_eq!(*item.1, ids[i]);
313                }
314                // Remove every other item
315                for i in 0..8 {
316                    pool.remove(i * 2);
317                }
318                let ids = [ 1, 3, 5, 7, 9, 11, 13, 15 ];
319                for (i, item) in pool.iter().enumerate() {
320                    assert_eq!(*item.1, ids[i]);
321                }
322                {
323                    let _removed = pool.remove(1);
324                    let ids = [ 3, 5, 7, 9, 11, 13, 15 ];
325                    for (i, item) in pool.iter().enumerate() {
326                        assert_eq!(*item.1, ids[i]);
327                    }
328                }
329            }
330            // Test inserting 16 items and removing the first 8.
331            {
332
333                let mut pool: Pool<usize> = Pool::new();
334                for i in 0..16 {
335                    pool.push(i);
336                }
337                let ids = [ 0, 1, 2, 3, 4, 5, 6, 7,
338                            8, 9, 10, 11, 12, 13, 14, 15 ];
339                for (i, item) in pool.iter().enumerate() {
340                    assert_eq!(*item.1, ids[i]);
341                }
342                for i in 0..8 {
343                    pool.remove(i);
344                }
345                let ids = [ 8, 9, 10, 11, 12, 13, 14, 15 ];
346                for (i, item) in pool.iter().enumerate() {
347                    assert_eq!(*item.1, ids[i]);
348                }
349                {
350                    let _removed = pool.remove(8);
351                    let ids = [ 9, 10, 11, 12, 13, 14, 15 ];
352                    for (i, item) in pool.iter().enumerate() {
353                        assert_eq!(*item.1, ids[i]);
354                    }
355                }
356            }
357            // Test inserting 24 items and removing the middle 8.
358            {
359
360                let mut pool: Pool<usize> = Pool::new();
361                for i in 0..24 {
362                    pool.push(i);
363                }
364                let ids = [ 0, 1, 2, 3, 4, 5, 6, 7,
365                            8, 9, 10, 11, 12, 13, 14, 15,
366                            16, 17, 18, 19, 20, 21, 22, 23 ];
367                for (i, item) in pool.iter().enumerate() {
368                    assert_eq!(*item.1, ids[i]);
369                }
370                for i in 8..16 {
371                    pool.remove(i);
372                }
373                let ids = [ 0, 1, 2, 3, 4, 5, 6, 7, 
374                            16, 17, 18, 19, 20, 21, 22, 23 ];
375                for (i, item) in pool.iter().enumerate() {
376                    assert_eq!(*item.1, ids[i]);
377                }
378                {
379                    let _removed1 = pool.remove(23);
380                    let _removed2 = pool.remove(18);
381                    let _removed2 = pool.remove(19);
382                    let ids = [ 0, 1, 2, 3, 4, 5, 6, 7,
383                                16, 17, 20, 21, 22 ];
384                    for (i, item) in pool.iter().enumerate() {
385                        assert_eq!(*item.1, ids[i]);
386                    }
387                }
388            }
389        }
390    }
391}