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}