ika/
lib.rs

1//! # welcome to the ika pool
2//!
3//! ```rust,no_run
4//! use ika::Pool;
5//!
6//! fn main() {
7//!    let mut str_pool: Pool<String> = Pool::new(10);
8//!    str_pool.spawn_some(5)
9//!            .drain(..)
10//!            .enumerate()
11//!            .for_each(| (i, r) | {
12//!                r.push_str(&i.to_string());
13//!                r.push_str(" hallo");
14//!            });
15//!
16//!    let ok = str_pool.detach(2);
17//!
18//!    str_pool.attach(2, "wowo".to_owned());
19//! }
20//! ```
21
22
23use std::{
24    slice,
25    fmt,
26};
27
28// TODO
29//   write tests
30//   usage documentation
31//   handle ZSTs
32
33// Saftey
34// the main points of unsafety are:
35//   making sure pool.offsets doesnt have two items that point to the same T in data
36//   making sure pool.offsets contains valid offsets that dont go over data.size()
37//     first solved by only ever swapping offsets
38//     both solved by initing it with 0..size
39//   detach and attach which change indices
40//     attach just adds obj onto the end of data and pust that index wherever in offsets
41//     detach has to move all the offsets above the one that was removed down
42
43/// Immutable pool iterator.
44pub struct Iter<'a, T> {
45    data: &'a Vec<T>,
46    iter: slice::Iter<'a, usize>,
47}
48
49impl<'a, T> Iterator for Iter<'a, T> {
50    type Item = &'a T;
51
52    fn next(&mut self) -> Option<Self::Item> {
53        let offset = self.iter.next()?;
54        unsafe {
55            Some(self.data.get_unchecked(*offset))
56        }
57    }
58}
59
60/// Mutable pool iterator.
61pub struct IterMut<'a, T> {
62    data: &'a mut Vec<T>,
63    iter: slice::Iter<'a, usize>,
64}
65
66impl<'a, T> Iterator for IterMut<'a, T> {
67    type Item = &'a mut T;
68
69    fn next(&mut self) -> Option<Self::Item> {
70        use std::mem;
71
72        let offset = self.iter.next()?;
73        unsafe {
74            Some(mem::transmute(self.data.get_unchecked_mut(*offset)))
75        }
76    }
77}
78
79/// Let's go swimming!
80#[derive(Eq, Clone, Default)]
81pub struct Pool<T> {
82    data: Vec<T>,
83    offsets: Vec<usize>,
84    alive_ct: usize,
85}
86
87impl<T> Pool<T> {
88    /// Instantiate an object.
89    /// Undefined behavior if `self.is_empty()`.  
90    /// Object may have weird, possibly uninitialized, data.  
91    pub unsafe fn spawn_unchecked(&mut self) -> &mut T {
92        let at = self.alive_ct;
93        self.alive_ct += 1;
94        self.get_at_offset_mut(at)
95    }
96
97    /// Instantiate an object.
98    /// Will return None if `self.is_empty()`.  
99    /// Object may have weird, possibly uninitialized, data.  
100    #[inline]
101    pub fn spawn(&mut self) -> Option<&mut T> {
102        if self.is_empty() {
103            None
104        } else {
105            Some(unsafe { self.spawn_unchecked() })
106        }
107    }
108
109    //
110
111    /// Instantiate exactly `count` objects.
112    /// If `count > self.available()`, the resulting vector will be empty.  
113    /// Object may have weird, possibly uninitialized, data.  
114    pub fn spawn_exact(&mut self, count: usize) -> Vec<&mut T> {
115        use std::mem;
116
117        if count > self.available() {
118            Vec::new()
119        } else {
120            let offsets = &self.offsets[self.alive_ct..self.alive_ct + count];
121            self.alive_ct += count;
122
123            let mut ret = Vec::with_capacity(count);
124            for offset in offsets {
125                ret.push(unsafe {
126                    mem::transmute(self.data.get_unchecked_mut(*offset))
127                });
128            }
129            ret
130        }
131    }
132
133    /// Instantiate some objects.
134    /// If `count > self.available()`, the resulting vector will have a length < count, and may be empty.  
135    /// Object may have weird, possibly uninitialized, data.  
136    pub fn spawn_some(&mut self, count: usize) -> Vec<&mut T> {
137        use std::cmp;
138        self.spawn_exact(cmp::min(count, self.available()))
139    }
140
141    //
142
143    /// Kill objects in the pool based on `kill_fn`.
144    /// If `kill_fn` returns true, the object will be recycled.  
145    /// Preserves ordering of the pool.  
146    pub fn reclaim<F: FnMut(&T) -> bool>(&mut self, mut kill_fn: F) {
147        // safe because:
148        //   i goes from 0 to alive_ct
149
150        let len = self.alive_ct;
151        let mut del = 0;
152        for i in 0..len {
153            if kill_fn(unsafe { self.get_at_offset(i) }) {
154                del += 1;
155            } else if del > 0 {
156                self.offsets.swap(i, i - del);
157            }
158        }
159        self.alive_ct -= del;
160    }
161
162    /// Kill objects in the pool based on `kill_fn`.
163    /// If `kill_fn` returns true, the object will be recycled.  
164    /// Doesn't necessarity preserve ordering of the pool.  
165    pub fn reclaim_unstable<F: FnMut(&T) -> bool>(&mut self, mut kill_fn: F) {
166        // safe because:
167        //   alive_ct can never go below zero
168        //   i can never go above alive_ct
169
170        let mut len = self.alive_ct;
171        let mut i = 0;
172        while i < len {
173            if kill_fn(unsafe { self.get_at_offset(i) }) {
174                len -= 1;
175                self.offsets.swap(i, len);
176            }
177            i += 1;
178        }
179        self.alive_ct = len;
180    }
181
182    //
183
184    /// Move an object into the pool.
185    /// Will resize the pool.  
186    pub fn attach(&mut self, at: usize, obj: T) {
187        if at > self.alive_ct {
188            panic!("index out of bounds");
189        }
190
191        self.offsets.insert(at, self.data.len());
192        self.alive_ct += 1;
193        self.data.push(obj);
194    }
195
196    /// Move an object out of the pool by index.
197    /// Will resize the pool.  
198    /// Panics if index is out of bounds.  
199    pub fn detach(&mut self, at: usize) -> T {
200        if at >= self.alive_ct {
201            panic!("index out of bounds");
202        }
203
204        let data_idx = unsafe {
205            self.offset_to_data_idx(at)
206        };
207
208        let ret = self.data.remove(data_idx);
209        self.offsets.remove(at);
210
211        if at != self.alive_ct - 1 {
212            for offset in &mut self.offsets {
213                if *offset > data_idx {
214                    *offset -= 1;
215                }
216            }
217        }
218
219        self.alive_ct -= 1;
220        ret
221    }
222
223    //
224
225    /// Turns an offset into an index into the data vec.  
226    /// Safe as long as `at` is within bounds of `self.offsets`.  
227    #[inline]
228    unsafe fn offset_to_data_idx(&self, at: usize) -> usize {
229        *self.offsets.get_unchecked(at)
230    }
231
232    /// Get a &T from the offset found at `offsets[at]`.
233    /// Safe as long as `at` is within bounds of `self.offsets`.  
234    #[inline]
235    unsafe fn get_at_offset(&self, at: usize) -> &T {
236        self.data.get_unchecked(self.offset_to_data_idx(at))
237    }
238
239    /// Get a &mut T from the offset found at `offsets[at]`.
240    /// Safe as long as `at` is within bounds of `self.offsets`.  
241    #[inline]
242    unsafe fn get_at_offset_mut(&mut self, at: usize) -> &mut T {
243        let idx = self.offset_to_data_idx(at);
244        self.data.get_unchecked_mut(idx)
245    }
246
247    pub fn get(&self, at: usize) -> Option<&T> {
248        if at < self.alive_ct {
249            Some(unsafe { self.get_at_offset(at) })
250        } else {
251            None
252        }
253    }
254
255    pub fn get_mut(&mut self, at: usize) -> Option<&mut T> {
256        if at < self.alive_ct {
257            Some(unsafe { self.get_at_offset_mut(at) })
258        } else {
259            None
260        }
261    }
262
263    //
264
265    pub fn iter(&self) -> Iter<T> {
266        Iter {
267            data: &self.data,
268            iter: (&self.offsets[..self.alive_ct]).iter(),
269        }
270    }
271
272    pub fn iter_mut(&mut self) -> IterMut<T> {
273        IterMut {
274            data: &mut self.data,
275            iter: (&self.offsets[..self.alive_ct]).iter(),
276        }
277    }
278
279    //
280
281    /// Sort pointers to available objects for better cache locality.
282    pub fn sort_the_dead(&mut self) {
283        if self.available() >= 2 {
284            self.offsets[self.alive_ct..].sort_unstable();
285        }
286    }
287
288    /// Returns whether there are available objects in the pool or not.
289    #[inline]
290    pub fn is_empty(&self) -> bool {
291        self.available() == 0
292    }
293
294    /// Number of objects in use in the pool.
295    #[inline]
296    pub fn len(&self) -> usize {
297        self.alive_ct
298    }
299
300    /// Number of free objects in the pool.
301    #[inline]
302    pub fn available(&self) -> usize {
303        self.offsets.len() - self.alive_ct
304    }
305
306    /// Number of total objects in the pool.
307    #[inline]
308    pub fn capacity(&self) -> usize {
309        self.offsets.len()
310    }
311}
312
313impl<T: Default> Pool<T> {
314    /// Create a new pool with a starting size of `size`.
315    /// Objects will be initialized with `T::default()`
316    pub fn new(size: usize) -> Self {
317        let mut data: Vec<T> = Vec::with_capacity(size);
318        for _ in 0..size {
319            data.push(T::default());
320        }
321
322        let mut offsets = Vec::with_capacity(size);
323        for i in 0..size {
324            offsets.push(i);
325        }
326
327        Self {
328            data,
329            offsets,
330            alive_ct: 0,
331        }
332    }
333
334    //
335
336    /// Please instantiate an object.
337    /// Will resize the pool if `self.is_empty()`.  
338    /// Intializes new object with `T::default()`.  
339    #[inline]
340    pub fn please_spawn(&mut self) -> &mut T {
341        if self.is_empty() {
342            self.offsets.push(self.data.len());
343            self.data.push(T::default());
344        }
345        unsafe { self.spawn_unchecked() }
346    }
347
348    //
349
350    /// Instantiate exactly `count` objects.
351    /// If `count > self.available()`, the pool will be resized to account for the difference.  
352    /// Intializes new objects with `T::default()`.  
353    pub fn please_spawn_some(&mut self, count: usize) -> Vec<&mut T> {
354        if count > self.available() {
355            let to_add = count - self.available();
356            self.offsets.reserve(to_add);
357            self.data.reserve(to_add);
358            for _ in 0..to_add {
359                self.offsets.push(self.data.len());
360                self.data.push(T::default());
361            }
362        }
363        self.spawn_exact(count)
364    }
365}
366
367impl<'a, T> IntoIterator for &'a Pool<T> {
368    type Item = &'a T;
369    type IntoIter = Iter<'a, T>;
370
371    fn into_iter(self) -> Self::IntoIter {
372        self.iter()
373    }
374}
375
376impl<'a, T> IntoIterator for &'a mut Pool<T> {
377    type Item = &'a mut T;
378    type IntoIter = IterMut<'a, T>;
379
380    fn into_iter(self) -> Self::IntoIter {
381        self.iter_mut()
382    }
383}
384
385impl<T: fmt::Debug> fmt::Debug for Pool<T> {
386    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
387        let mut lst = f.debug_list();
388        for obj in self.iter() {
389            lst.entry(obj);
390        }
391        lst.finish()
392    }
393}
394
395impl<T: PartialEq> PartialEq for Pool<T> {
396    fn eq(&self, other: &Self) -> bool {
397        let are_alive_equal =
398            self.iter().zip(other.iter())
399                .all(| (s, o) | {
400                    s == o
401                });
402        // TODO does capacity need to be equal for two pools to be equal?
403        self.len() == other.len() && are_alive_equal
404    }
405}