#![no_std]
mod entry;
mod iter;
#[cfg(test)]
mod tests;
extern crate alloc;
use self::entry::{Entry, OccupiedEntry, VacantEntry};
pub use self::iter::{IntoIter, Iter, IterMut};
use alloc::vec::Vec;
use core::mem;
use core::num::NonZeroUsize;
use core::ops::{Index, IndexMut};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MultiStash<T> {
free: usize,
len_items: usize,
len_occupied: usize,
entries: Vec<Entry<T>>,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Key(usize);
impl From<usize> for Key {
#[inline]
fn from(index: usize) -> Self {
Self(index)
}
}
impl From<Key> for usize {
#[inline]
fn from(key: Key) -> Self {
key.0
}
}
impl<T> Default for MultiStash<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> MultiStash<T> {
pub fn new() -> Self {
Self {
free: 0,
len_items: 0,
len_occupied: 0,
entries: Vec::new(),
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
free: 0,
len_items: 0,
len_occupied: 0,
entries: Vec::with_capacity(capacity),
}
}
pub fn capacity(&self) -> usize {
self.entries.capacity()
}
pub fn reserve(&mut self, additional: usize) {
self.entries.reserve(additional);
}
pub fn reserve_exact(&mut self, additional: usize) {
self.entries.reserve_exact(additional);
}
fn len_entries(&self) -> usize {
self.entries.len()
}
pub fn len_items(&self) -> usize {
self.len_items
}
fn len_occupied(&self) -> usize {
self.len_occupied
}
pub fn len(&self) -> usize {
self.len_occupied()
}
pub fn is_empty(&self) -> bool {
self.len_occupied() == 0
}
pub fn get(&self, key: Key) -> Option<(usize, &T)> {
match self.entries.get(key.0) {
Some(Entry::Occupied(entry)) => Some((entry.remaining.get(), &entry.item)),
_ => None,
}
}
pub fn get_mut(&mut self, key: Key) -> Option<(usize, &mut T)> {
match self.entries.get_mut(key.0) {
Some(Entry::Occupied(entry)) => Some((entry.remaining.get(), &mut entry.item)),
_ => None,
}
}
pub fn put(&mut self, amount: NonZeroUsize, item: T) -> Key {
let key = Key(self.free);
self.free = if self.free == self.len_entries() {
self.entries
.push(Entry::from(OccupiedEntry::new(item, amount)));
self.free.checked_add(1).unwrap()
} else {
let cell = unsafe { self.entries.get_unchecked_mut(self.free) };
match mem::replace(cell, Entry::from(OccupiedEntry::new(item, amount))) {
Entry::Vacant(entry) => entry.next_free,
_ => unreachable!(
"asserted that the entry at `self.free` ({}) is vacant",
self.free
),
}
};
self.bump_len_items(amount.get());
self.len_occupied += 1;
key
}
fn bump_len_items(&mut self, amount: usize) {
self.len_items = self.len_items.checked_add(amount).unwrap_or_else(|| {
panic!(
"failed to add {} items to MultiStash of length {}",
amount, self.len_items
)
});
}
pub fn clear(&mut self) {
self.free = 0;
self.len_items = 0;
self.len_occupied = 0;
self.entries.clear();
}
pub fn take_all(&mut self, key: Key) -> Option<(usize, T)> {
let index = key.0;
let taken = match self.entries.get_mut(index) {
None => None,
Some(entry) => match mem::replace(entry, Entry::from(VacantEntry::new(self.free))) {
Entry::Vacant(vacant) => {
*entry = Entry::from(VacantEntry::new(vacant.next_free));
None
}
Entry::Occupied(occupied) => {
self.free = index;
let item = occupied.item;
let len_taken = occupied.remaining.get();
self.len_items -= len_taken;
self.len_occupied -= 1;
Some((len_taken, item))
}
},
};
if self.is_empty() {
self.clear()
}
taken
}
pub fn bump(&mut self, key: Key, amount: usize) -> Option<usize> {
let index = key.0;
match self.entries.get_mut(index)? {
Entry::Vacant(_) => None,
Entry::Occupied(entry) => {
let old_amount = entry.remaining;
let new_amount = old_amount.checked_add(amount).unwrap_or_else(|| {
panic!(
"overflow when adding {} to the amount of MultiStash element at {}",
amount, index,
)
});
entry.remaining = new_amount;
self.bump_len_items(amount);
Some(old_amount.get())
}
}
}
pub fn iter(&self) -> Iter<T> {
Iter::new(self)
}
pub fn iter_mut(&mut self) -> IterMut<T> {
IterMut::new(self)
}
}
impl<T: Clone> MultiStash<T> {
pub fn take_one(&mut self, key: Key) -> Option<(usize, T)> {
let index = key.0;
let taken = match self.entries.get_mut(index) {
None => None,
Some(entry) => match mem::replace(entry, Entry::from(VacantEntry::new(self.free))) {
Entry::Vacant(vacant) => {
*entry = Entry::from(VacantEntry::new(vacant.next_free));
None
}
Entry::Occupied(occupied) => {
let item = occupied.item;
self.len_items -= 1;
match NonZeroUsize::new(occupied.remaining.get().wrapping_sub(1)) {
Some(remaining) => {
*entry = Entry::from(OccupiedEntry::new(item.clone(), remaining));
Some((remaining.get(), item))
}
None => {
self.len_occupied -= 1;
self.free = index;
Some((0, item))
}
}
}
},
};
if self.is_empty() {
self.clear()
}
taken
}
}
impl<'a, T> IntoIterator for &'a MultiStash<T> {
type Item = (Key, usize, &'a T);
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T> IntoIterator for &'a mut MultiStash<T> {
type Item = (Key, usize, &'a mut T);
type IntoIter = IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl<T> IntoIterator for MultiStash<T> {
type Item = (Key, usize, T);
type IntoIter = IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
IntoIter::new(self)
}
}
impl<T> Index<Key> for MultiStash<T> {
type Output = T;
fn index(&self, key: Key) -> &Self::Output {
self.get(key)
.map(|(_, item)| item)
.unwrap_or_else(|| panic!("found no item at index {}", key.0))
}
}
impl<T> IndexMut<Key> for MultiStash<T> {
fn index_mut(&mut self, key: Key) -> &mut Self::Output {
self.get_mut(key)
.map(|(_, item)| item)
.unwrap_or_else(|| panic!("found no item at index {}", key.0))
}
}
impl<T> Extend<(NonZeroUsize, T)> for MultiStash<T> {
fn extend<I: IntoIterator<Item = (NonZeroUsize, T)>>(&mut self, iter: I) {
for (amount, item) in iter {
self.put(amount, item);
}
}
}
impl<T> FromIterator<(NonZeroUsize, T)> for MultiStash<T> {
fn from_iter<I: IntoIterator<Item = (NonZeroUsize, T)>>(iter: I) -> Self {
let mut stash = Self::new();
stash.extend(iter);
stash
}
}