use core::mem::replace;
use crate::iterator::*;
use crate::private::Entry;
pub struct UnrestrictedSlots<IT, const N: usize> {
items: [Entry<IT>; N],
next_free: usize,
count: usize,
}
impl<IT, const N: usize> Default for UnrestrictedSlots<IT, N> {
fn default() -> Self {
Self::new()
}
}
impl<IT, const N: usize> UnrestrictedSlots<IT, N> {
pub fn new() -> Self {
Self {
items: array_init::array_init(|i| {
i.checked_sub(1)
.map(Entry::EmptyNext)
.unwrap_or(Entry::EmptyLast)
}),
next_free: N.saturating_sub(1), count: 0,
}
}
pub fn iter(&self) -> Iter<IT> {
Iter::from_entry_slice(self.items.as_slice())
}
pub fn iter_mut(&mut self) -> IterMut<IT> {
IterMut::from_entry_slice(self.items.as_mut_slice())
}
pub fn capacity(&self) -> usize {
N
}
pub fn count(&self) -> usize {
self.count
}
pub fn is_full(&self) -> bool {
self.count == self.capacity()
}
fn free(&mut self, idx: usize) {
debug_assert!(self.count != 0, "Free called on an empty collection");
self.items[idx] = if self.is_full() {
Entry::EmptyLast
} else {
Entry::EmptyNext(self.next_free)
};
self.next_free = idx; self.count -= 1;
}
fn alloc(&mut self) -> Option<usize> {
if self.is_full() {
None
} else {
let index = self.next_free;
self.next_free = match self.items[index] {
Entry::EmptyNext(n) => n, Entry::EmptyLast => 0, _ => unreachable!("Non-empty item in entry behind free chain"),
};
self.count += 1;
Some(index)
}
}
pub fn store(&mut self, item: IT) -> Result<usize, IT> {
match self.alloc() {
Some(i) => {
self.items[i] = Entry::Used(item);
Ok(i)
}
None => Err(item),
}
}
pub fn take(&mut self, key: usize) -> Option<IT> {
if let Entry::Used(item) = replace(&mut self.items[key], Entry::EmptyLast) {
self.free(key);
Some(item)
} else {
None
}
}
pub fn read<T>(&self, key: usize, function: impl FnOnce(&IT) -> T) -> Option<T> {
if key >= self.capacity() {
None
} else {
match self.items[key] {
Entry::Used(ref item) => Some(function(item)),
_ => None,
}
}
}
pub fn modify<T>(&mut self, key: usize, function: impl FnOnce(&mut IT) -> T) -> Option<T> {
match self.items[key] {
Entry::Used(ref mut item) => Some(function(item)),
_ => None,
}
}
}