multi_stash/
lib.rs

1#![no_std]
2
3mod entry;
4mod iter;
5
6#[cfg(test)]
7mod tests;
8
9extern crate alloc;
10
11use self::entry::{Entry, OccupiedEntry, VacantEntry};
12pub use self::iter::{IntoIter, Iter, IterMut};
13use alloc::vec::Vec;
14use core::mem;
15use core::num::NonZeroUsize;
16use core::ops::{Index, IndexMut};
17
18/// A vector-like data structure that is able to reuse slots for new elements.
19///
20/// Specifically allows for (armortized) O(1) instructions for:
21///
22/// - [`MultiStash::put`]
23/// - [`MultiStash::take_one`]
24/// - [`MultiStash::take_all`]
25/// - [`MultiStash::get`]
26/// - [`MultiStash::get_mut`]
27#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
28pub struct MultiStash<T> {
29    /// The next vacant or free slot to allocate.
30    free: usize,
31    /// The number of items stored in the [`MultiStash`].
32    ///
33    /// # Note
34    ///
35    /// Each [`Entry::Occupied`] might store multiple items.
36    len_items: usize,
37    /// The number of occupied entries in the [`MultiStash`].
38    ///
39    /// # Note
40    ///
41    /// Each [`Entry::Occupied`] might store multiple items.
42    len_occupied: usize,
43    /// The entries of the [`MultiStash`].
44    entries: Vec<Entry<T>>,
45}
46
47/// Allows to access elements stored in a [`MultiStash`].
48#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
49pub struct Key(usize);
50
51impl From<usize> for Key {
52    #[inline]
53    fn from(index: usize) -> Self {
54        Self(index)
55    }
56}
57
58impl From<Key> for usize {
59    #[inline]
60    fn from(key: Key) -> Self {
61        key.0
62    }
63}
64
65impl<T> Default for MultiStash<T> {
66    fn default() -> Self {
67        Self::new()
68    }
69}
70
71impl<T> MultiStash<T> {
72    /// Construct a new, empty [`MultiStash`].
73    ///
74    /// The [`MultiStash`] will not allocate until items are put into it.
75    pub fn new() -> Self {
76        Self {
77            free: 0,
78            len_items: 0,
79            len_occupied: 0,
80            entries: Vec::new(),
81        }
82    }
83
84    /// Constructs a new, empty [`MultiStash`] with at least the specified capacity.
85    ///
86    /// The [`MultiStash`] will be able to hold at least `capacity` elements without reallocating.
87    /// This method is allowed to allocate for more elements than `capacity`.
88    /// If `capacity` is 0, the [`MultiStash`] will not allocate.
89    ///
90    /// It is important to note that although the returned [`MultiStash`] has the minimum
91    /// *capacity* specified, the [`MultiStash`] will have a zero length.
92    /// For an explanation of the difference between length and capacity, see *[Capacity and reallocation]*.
93    ///
94    /// If it is important to know the exact allocated capacity of a [`MultiStash`],
95    /// always use the [`capacity`] method after construction.
96    ///
97    /// # Panics
98    ///
99    /// Panics if the new capacity exceeds `isize::MAX` bytes.
100    ///
101    /// [Capacity and reallocation]: https://doc.rust-lang.org/std/vec/struct.Vec.html#capacity-and-reallocation
102    /// [`capacity`]: MultiStash::capacity
103    pub fn with_capacity(capacity: usize) -> Self {
104        Self {
105            free: 0,
106            len_items: 0,
107            len_occupied: 0,
108            entries: Vec::with_capacity(capacity),
109        }
110    }
111
112    /// Returns the total number of elements the [`MultiStash`] can hold without reallocating.
113    pub fn capacity(&self) -> usize {
114        self.entries.capacity()
115    }
116
117    /// Reserves capacity for at least `additional` more elements to be inserted
118    /// in the given [`MultiStash`]. The collection may reserve more space to
119    /// speculatively avoid frequent reallocations. After calling `reserve`,
120    /// capacity will be greater than or equal to `self.len() + additional`.
121    /// Does nothing if capacity is already sufficient.
122    ///
123    /// # Panics
124    ///
125    /// Panics if the new capacity exceeds `isize::MAX` bytes.
126    pub fn reserve(&mut self, additional: usize) {
127        self.entries.reserve(additional);
128    }
129
130    /// Reserves the minimum capacity for at least `additional` more elements to
131    /// be inserted in the given [`MultiStash`]. Unlike [`reserve`], this will not
132    /// deliberately over-allocate to speculatively avoid frequent allocations.
133    /// After calling `reserve_exact`, capacity will be greater than or equal to
134    /// `self.len() + additional`. Does nothing if the capacity is already
135    /// sufficient.
136    ///
137    /// Note that the allocator may give the collection more space than it
138    /// requests. Therefore, capacity can not be relied upon to be precisely
139    /// minimal. Prefer [`reserve`] if future insertions are expected.
140    ///
141    /// [`reserve`]: MultiStash::reserve
142    ///
143    /// # Panics
144    ///
145    /// Panics if the new capacity exceeds `isize::MAX` bytes.
146    pub fn reserve_exact(&mut self, additional: usize) {
147        self.entries.reserve_exact(additional);
148    }
149
150    /// Returns the number of vacant or occupied [`Entry`] in the [`MultiStash`].
151    fn len_entries(&self) -> usize {
152        self.entries.len()
153    }
154
155    /// Returns the number of items in the [`MultiStash`].
156    ///
157    /// # Note
158    ///
159    /// A single element might store multiple items.
160    pub fn len_items(&self) -> usize {
161        self.len_items
162    }
163
164    /// Returns the number of elements in the [`MultiStash`].
165    ///
166    /// # Note
167    ///
168    /// A single element might store multiple items.
169    fn len_occupied(&self) -> usize {
170        self.len_occupied
171    }
172
173    /// Returns the number of elements in the [`MultiStash`].
174    ///
175    /// # Note
176    ///
177    /// A single element might store multiple items.
178    pub fn len(&self) -> usize {
179        self.len_occupied()
180    }
181
182    /// Returns `true` if the [`MultiStash`] contains no elements.
183    pub fn is_empty(&self) -> bool {
184        self.len_occupied() == 0
185    }
186
187    /// Returns a reference to an element at the `key` if any.
188    pub fn get(&self, key: Key) -> Option<(usize, &T)> {
189        match self.entries.get(key.0) {
190            Some(Entry::Occupied(entry)) => Some((entry.remaining.get(), &entry.item)),
191            _ => None,
192        }
193    }
194
195    /// Returns a mutable reference to an element at the `key` if any.
196    pub fn get_mut(&mut self, key: Key) -> Option<(usize, &mut T)> {
197        match self.entries.get_mut(key.0) {
198            Some(Entry::Occupied(entry)) => Some((entry.remaining.get(), &mut entry.item)),
199            _ => None,
200        }
201    }
202
203    /// Puts an `amount` of `item` into the [`MultiStash`].
204    ///
205    /// # Panics
206    ///
207    /// Panics if the new capacity exceeds `isize::MAX` bytes.
208    pub fn put(&mut self, amount: NonZeroUsize, item: T) -> Key {
209        let key = Key(self.free);
210        self.free = if self.free == self.len_entries() {
211            self.entries
212                .push(Entry::from(OccupiedEntry::new(item, amount)));
213            self.free.checked_add(1).unwrap()
214        } else {
215            // # Safety: It is an invariant of `MultiStash` that `self.free` only ever stores
216            //           indices to populated entries in `self.items` if `self.free != self.len_entries()`.
217            let cell = unsafe { self.entries.get_unchecked_mut(self.free) };
218            match mem::replace(cell, Entry::from(OccupiedEntry::new(item, amount))) {
219                Entry::Vacant(entry) => entry.next_free,
220                _ => unreachable!(
221                    "asserted that the entry at `self.free` ({}) is vacant",
222                    self.free
223                ),
224            }
225        };
226        self.bump_len_items(amount.get());
227        self.len_occupied += 1;
228        key
229    }
230
231    /// Bumps the number of items in the [`MultiStash`] by `amount`.
232    ///
233    /// # Panics
234    ///
235    /// If the number of items in the [`MultiStash`] overflows.
236    fn bump_len_items(&mut self, amount: usize) {
237        self.len_items = self.len_items.checked_add(amount).unwrap_or_else(|| {
238            panic!(
239                "failed to add {} items to MultiStash of length {}",
240                amount, self.len_items
241            )
242        });
243    }
244
245    /// Clears the [`MultiStash`], removing all elements.
246    ///
247    /// Note that this method has no effect on the allocated capacity of the vector.
248    pub fn clear(&mut self) {
249        self.free = 0;
250        self.len_items = 0;
251        self.len_occupied = 0;
252        self.entries.clear();
253    }
254
255    /// Removes and returns the `element` at `key` and its amount of remaining items.
256    ///
257    /// Returns `None` if `key` refers to a vacant entry or is out of bounds.
258    pub fn take_all(&mut self, key: Key) -> Option<(usize, T)> {
259        let index = key.0;
260        let taken = match self.entries.get_mut(index) {
261            None => None,
262            Some(entry) => match mem::replace(entry, Entry::from(VacantEntry::new(self.free))) {
263                Entry::Vacant(vacant) => {
264                    *entry = Entry::from(VacantEntry::new(vacant.next_free));
265                    None
266                }
267                Entry::Occupied(occupied) => {
268                    self.free = index;
269                    let item = occupied.item;
270                    let len_taken = occupied.remaining.get();
271                    self.len_items -= len_taken;
272                    self.len_occupied -= 1;
273                    Some((len_taken, item))
274                }
275            },
276        };
277        if self.is_empty() {
278            self.clear()
279        }
280        taken
281    }
282
283    /// Bumps the amount of items of the element at `key` if any.
284    ///
285    /// Returns `None` if not element is found at the `key`.
286    ///
287    /// # Panics
288    ///
289    /// Panics if `amount` of the element at `key` overflows.
290    pub fn bump(&mut self, key: Key, amount: usize) -> Option<usize> {
291        let index = key.0;
292        match self.entries.get_mut(index)? {
293            Entry::Vacant(_) => None,
294            Entry::Occupied(entry) => {
295                let old_amount = entry.remaining;
296                let new_amount = old_amount.checked_add(amount).unwrap_or_else(|| {
297                    panic!(
298                        "overflow when adding {} to the amount of MultiStash element at {}",
299                        amount, index,
300                    )
301                });
302                entry.remaining = new_amount;
303                self.bump_len_items(amount);
304                Some(old_amount.get())
305            }
306        }
307    }
308
309    /// Returns an iterator over the elements of the [`MultiStash`].
310    ///
311    /// The iterator yields all elements, their keys and remaining items from start to end.
312    pub fn iter(&self) -> Iter<T> {
313        Iter::new(self)
314    }
315
316    /// Returns an iterator over the elements of the [`MultiStash`].
317    ///
318    /// The iterator yields mutable references to all elements, their keys and remaining items from start to end.
319    pub fn iter_mut(&mut self) -> IterMut<T> {
320        IterMut::new(self)
321    }
322}
323
324impl<T: Clone> MultiStash<T> {
325    /// Returns a single item of the `element` at `key`
326    /// and the amount of remaining items after this operation.
327    ///
328    /// Remove the `element` if no items are left after this operation.
329    /// Returns `None` if `key` refers to a vacant entry or is out of bounds.
330    pub fn take_one(&mut self, key: Key) -> Option<(usize, T)> {
331        let index = key.0;
332        let taken = match self.entries.get_mut(index) {
333            None => None,
334            Some(entry) => match mem::replace(entry, Entry::from(VacantEntry::new(self.free))) {
335                Entry::Vacant(vacant) => {
336                    *entry = Entry::from(VacantEntry::new(vacant.next_free));
337                    None
338                }
339                Entry::Occupied(occupied) => {
340                    let item = occupied.item;
341                    self.len_items -= 1;
342                    match NonZeroUsize::new(occupied.remaining.get().wrapping_sub(1)) {
343                        Some(remaining) => {
344                            *entry = Entry::from(OccupiedEntry::new(item.clone(), remaining));
345                            Some((remaining.get(), item))
346                        }
347                        None => {
348                            self.len_occupied -= 1;
349                            self.free = index;
350                            Some((0, item))
351                        }
352                    }
353                }
354            },
355        };
356        if self.is_empty() {
357            self.clear()
358        }
359        taken
360    }
361}
362
363impl<'a, T> IntoIterator for &'a MultiStash<T> {
364    type Item = (Key, usize, &'a T);
365    type IntoIter = Iter<'a, T>;
366
367    fn into_iter(self) -> Self::IntoIter {
368        self.iter()
369    }
370}
371
372impl<'a, T> IntoIterator for &'a mut MultiStash<T> {
373    type Item = (Key, usize, &'a mut T);
374    type IntoIter = IterMut<'a, T>;
375
376    fn into_iter(self) -> Self::IntoIter {
377        self.iter_mut()
378    }
379}
380
381impl<T> IntoIterator for MultiStash<T> {
382    type Item = (Key, usize, T);
383    type IntoIter = IntoIter<T>;
384
385    fn into_iter(self) -> Self::IntoIter {
386        IntoIter::new(self)
387    }
388}
389
390impl<T> Index<Key> for MultiStash<T> {
391    type Output = T;
392
393    fn index(&self, key: Key) -> &Self::Output {
394        self.get(key)
395            .map(|(_, item)| item)
396            .unwrap_or_else(|| panic!("found no item at index {}", key.0))
397    }
398}
399
400impl<T> IndexMut<Key> for MultiStash<T> {
401    fn index_mut(&mut self, key: Key) -> &mut Self::Output {
402        self.get_mut(key)
403            .map(|(_, item)| item)
404            .unwrap_or_else(|| panic!("found no item at index {}", key.0))
405    }
406}
407
408impl<T> Extend<(NonZeroUsize, T)> for MultiStash<T> {
409    fn extend<I: IntoIterator<Item = (NonZeroUsize, T)>>(&mut self, iter: I) {
410        for (amount, item) in iter {
411            self.put(amount, item);
412        }
413    }
414}
415
416impl<T> FromIterator<(NonZeroUsize, T)> for MultiStash<T> {
417    fn from_iter<I: IntoIterator<Item = (NonZeroUsize, T)>>(iter: I) -> Self {
418        let mut stash = Self::new();
419        stash.extend(iter);
420        stash
421    }
422}