#![doc = include_str!("../README.md")]
#![warn(rustdoc::broken_intra_doc_links)]
#![warn(missing_docs)]
#![warn(clippy::pedantic)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::cast_possible_truncation)]
use std::iter::Iterator;
#[cfg(all(feature = "slot_u64", not(feature = "slot_usize")))]
pub type Slot = u64;
#[cfg(feature = "slot_usize")]
pub type Slot = usize;
#[cfg(not(any(
all(feature = "slot_u64", not(feature = "slot_usize")),
feature = "slot_usize"
)))]
pub type Slot = u32;
const NUL: Slot = Slot::MAX;
#[derive(Debug)]
pub struct Slab<D: Sized> {
vec_next: Vec<Slot>,
vec_prev: Vec<Slot>,
free_head: Slot,
head: Slot,
tail: Slot,
len: usize,
data: Vec<Option<D>>,
#[cfg(not(feature = "releasefast"))]
bitmap: Vec<u8>,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum Error {
TooLarge,
Full,
InvalidSlot,
Empty,
}
impl std::error::Error for Error {}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
match self {
Error::TooLarge => write!(f, "Capacity is too large for the slot type"),
Error::Full => write!(f, "Slab is full and cannot accept more elements"),
Error::InvalidSlot => write!(f, "Invalid slot or slot doesn't contain an element"),
Error::Empty => write!(f, "Slab is empty"),
}
}
}
impl<D: Sized> Slab<D> {
pub fn with_capacity(capacity: usize) -> Result<Self, Error> {
if capacity as Slot == NUL {
return Err(Error::TooLarge);
}
let mut vec_next = Vec::with_capacity(capacity);
for i in 0..(capacity - 1) {
vec_next.push(i as Slot + 1);
}
vec_next.push(NUL);
let mut vec_prev = Vec::with_capacity(capacity);
vec_prev.push(NUL);
for i in 1..capacity {
vec_prev.push(i as Slot - 1);
}
let mut data = Vec::with_capacity(capacity);
for _ in 0..capacity {
data.push(None);
}
#[cfg(not(feature = "releasefast"))]
let bitmap_size = (capacity + 7) / 8;
Ok(Self {
vec_next,
vec_prev,
free_head: 0,
head: NUL,
tail: NUL,
len: 0,
data,
#[cfg(not(feature = "releasefast"))]
bitmap: vec![0u8; bitmap_size],
})
}
#[inline]
#[must_use]
pub fn capacity(&self) -> usize {
self.data.capacity()
}
#[inline]
#[must_use]
pub fn len(&self) -> usize {
self.len
}
#[inline]
#[must_use]
pub fn free(&self) -> usize {
self.capacity() - self.len()
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
#[must_use]
pub fn is_full(&self) -> bool {
self.free_head == NUL
}
pub fn get(&self, slot: Slot) -> Result<&D, Error> {
let index = slot as usize;
if index >= self.capacity() {
return Err(Error::InvalidSlot);
}
#[cfg(not(feature = "releasefast"))]
{
if !self.bitmap_get(slot) {
return Err(Error::InvalidSlot);
}
}
match &self.data[index] {
Some(value) => Ok(value),
None => Err(Error::InvalidSlot),
}
}
pub fn get_mut(&mut self, slot: Slot) -> Result<&mut D, Error> {
let index = slot as usize;
if index >= self.capacity() {
return Err(Error::InvalidSlot);
}
#[cfg(not(feature = "releasefast"))]
{
if !self.bitmap_get(slot) {
return Err(Error::InvalidSlot);
}
}
match &mut self.data[index] {
Some(value) => Ok(value),
None => Err(Error::InvalidSlot),
}
}
pub fn push_front(&mut self, value: D) -> Result<Slot, Error> {
let free_slot = self.free_head;
if free_slot == NUL {
return Err(Error::Full);
}
let free_index = free_slot as usize;
let prev = self.vec_prev[free_index];
let next = self.vec_next[free_index];
if prev != NUL {
debug_assert_eq!(self.vec_next[prev as usize], free_slot);
self.vec_next[prev as usize] = next;
}
if next != NUL {
if !self.is_empty() {
debug_assert_eq!(self.vec_prev[next as usize], free_slot);
}
self.vec_prev[next as usize] = prev;
}
if self.head != NUL {
self.vec_prev[self.head as usize] = free_slot;
}
self.free_head = next;
self.vec_next[free_index] = self.head;
self.vec_prev[free_index] = NUL;
if self.head == NUL {
self.tail = free_slot;
}
self.head = free_slot;
self.data[free_index] = Some(value);
self.len += 1;
debug_assert!(self.len <= self.capacity());
#[cfg(not(feature = "releasefast"))]
{
self.bitmap_set(free_slot);
}
Ok(free_slot)
}
pub fn remove(&mut self, slot: Slot) -> Result<(), Error> {
let index = slot as usize;
if index >= self.capacity() {
return Err(Error::InvalidSlot);
}
#[cfg(not(feature = "releasefast"))]
{
if !self.bitmap_get(slot) {
return Err(Error::InvalidSlot);
}
}
if self.data[index].is_none() {
return Err(Error::InvalidSlot);
}
self.data[index] = None;
let prev = self.vec_prev[index];
let next = self.vec_next[index];
if prev != NUL {
debug_assert_eq!(self.vec_next[prev as usize], slot);
self.vec_next[prev as usize] = next;
}
if next != NUL {
if !self.is_empty() {
debug_assert_eq!(self.vec_prev[next as usize], slot);
}
self.vec_prev[next as usize] = prev;
}
if self.tail == slot {
self.tail = prev;
}
if self.head == slot {
self.head = next;
}
self.vec_prev[index] = NUL;
self.vec_next[index] = self.free_head;
if self.free_head != NUL {
self.vec_prev[self.free_head as usize] = slot;
}
self.free_head = slot;
debug_assert!(self.len > 0);
self.len -= 1;
#[cfg(not(feature = "releasefast"))]
{
self.bitmap_unset(slot);
}
Ok(())
}
pub fn pop_back(&mut self) -> Option<D> {
let slot = self.tail;
if slot == NUL {
return None;
}
let index = slot as usize;
let value = self.data[index].take()?;
let prev = self.vec_prev[index];
debug_assert_eq!(self.vec_next[index], NUL);
if prev != NUL {
debug_assert_eq!(self.vec_next[prev as usize], slot);
self.vec_next[prev as usize] = NUL;
}
self.tail = prev;
if self.head == slot {
self.head = NUL;
}
self.vec_prev[index] = NUL;
self.vec_next[index] = self.free_head;
if self.free_head != NUL {
self.vec_prev[self.free_head as usize] = slot;
}
self.free_head = slot;
debug_assert!(self.len > 0);
self.len -= 1;
#[cfg(not(feature = "releasefast"))]
{
self.bitmap_unset(slot);
}
Some(value)
}
#[must_use]
pub fn iter(&self) -> SlabIterator<D> {
SlabIterator {
list: self,
slot: None,
}
}
#[cfg(not(feature = "releasefast"))]
#[must_use]
pub fn contains_slot(&self, slot: Slot) -> bool {
if (slot as usize) >= self.capacity() {
return false;
}
self.bitmap_get(slot)
}
#[cfg(not(feature = "releasefast"))]
#[inline]
fn bitmap_get(&self, slot: Slot) -> bool {
(self.bitmap[(slot as usize) / 8] & (1 << ((slot as usize) & 7))) != 0
}
#[cfg(not(feature = "releasefast"))]
#[inline]
fn bitmap_set(&mut self, slot: Slot) {
self.bitmap[(slot as usize) / 8] |= 1 << ((slot as usize) & 7);
}
#[cfg(not(feature = "releasefast"))]
#[inline]
fn bitmap_unset(&mut self, slot: Slot) {
self.bitmap[(slot as usize) / 8] &= !(1 << ((slot as usize) & 7));
}
pub fn clear(&mut self) {
let mut slot = self.head;
while slot != NUL {
let next = self.vec_next[slot as usize];
self.data[slot as usize] = None;
#[cfg(not(feature = "releasefast"))]
{
self.bitmap_unset(slot);
}
slot = next;
}
let capacity = self.capacity();
for i in 0..(capacity - 1) {
self.vec_next[i] = (i + 1) as Slot;
}
self.vec_next[capacity - 1] = NUL;
self.vec_prev[0] = NUL;
for i in 1..capacity {
self.vec_prev[i] = (i - 1) as Slot;
}
self.free_head = 0;
self.head = NUL;
self.tail = NUL;
self.len = 0;
}
}
impl<D> Default for Slab<D> {
fn default() -> Self {
Self::with_capacity(16).expect("Default capacity should always be valid")
}
}
impl<D> core::ops::Index<Slot> for Slab<D> {
type Output = D;
fn index(&self, slot: Slot) -> &Self::Output {
self.get(slot).expect("Invalid slot index")
}
}
impl<D> core::ops::IndexMut<Slot> for Slab<D> {
fn index_mut(&mut self, slot: Slot) -> &mut Self::Output {
self.get_mut(slot).expect("Invalid slot index")
}
}
#[derive(Debug)]
pub struct SlabIterator<'a, D> {
list: &'a Slab<D>,
slot: Option<Slot>,
}
impl<'a, D> Iterator for SlabIterator<'a, D> {
type Item = &'a D;
fn next(&mut self) -> Option<Self::Item> {
let slot = self.slot.unwrap_or(self.list.head);
if slot == NUL {
return None;
}
let index = slot as usize;
let res = self.list.data[index].as_ref()?;
self.slot = Some(self.list.vec_next[index]);
Some(res)
}
}
impl<D> ExactSizeIterator for SlabIterator<'_, D> {
fn len(&self) -> usize {
self.list.len()
}
}
impl<'a, D> DoubleEndedIterator for SlabIterator<'a, D> {
fn next_back(&mut self) -> Option<&'a D> {
let slot = self.slot.unwrap_or(self.list.tail);
if slot == NUL {
return None;
}
let index = slot as usize;
let res = self.list.data[index].as_ref()?;
self.slot = Some(self.list.vec_prev[index]);
Some(res)
}
}
impl<'a, D> IntoIterator for &'a Slab<D> {
type IntoIter = SlabIterator<'a, D>;
type Item = &'a D;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<D: Clone> FromIterator<D> for Slab<D> {
fn from_iter<I: IntoIterator<Item = D>>(iter: I) -> Self {
let iter = iter.into_iter();
let (min, max_size) = iter.size_hint();
let capacity = max_size.unwrap_or(min);
let mut slab = Self::with_capacity(capacity).expect("Iterator too large for slab capacity");
let mut vec: Vec<D> = iter.collect();
while let Some(item) = vec.pop() {
if slab.push_front(item.clone()).is_err() {
let new_capacity = slab.capacity() * 2;
let mut new_slab = Self::with_capacity(new_capacity)
.expect("Iterator too large for slab capacity");
while let Some(old_item) = slab.pop_back() {
new_slab
.push_front(old_item)
.expect("New slab should have enough capacity");
}
new_slab
.push_front(item)
.expect("New slab should have enough capacity");
slab = new_slab;
}
}
slab
}
}
impl<D: Clone> Extend<D> for Slab<D> {
fn extend<I: IntoIterator<Item = D>>(&mut self, iter: I) {
for item in iter {
self.push_front(item).expect("Slab full during extend");
}
}
}
#[test]
fn test() {
let mut slab = Slab::with_capacity(3).unwrap();
let a = slab.push_front(Box::new(1)).unwrap();
let b = slab.push_front(Box::new(2)).unwrap();
slab.push_front(Box::new(3)).unwrap();
assert_eq!(slab.len(), 3);
assert!(slab.push_front(Box::new(4)).is_err());
slab.remove(a).unwrap();
slab.remove(b).unwrap();
assert_eq!(slab.len(), 1);
let cv = slab.pop_back().unwrap();
assert_eq!(*cv, 3);
}
#[test]
fn test2() {
use std::collections::VecDeque;
use rand::prelude::*;
let mut rng = rand::rng();
let capacity = rng.random_range(1..=50);
let mut slab = Slab::with_capacity(capacity).unwrap();
let mut c: u64 = 0;
let mut expected_len: usize = 0;
let mut deque = VecDeque::with_capacity(capacity);
for _ in 0..1_000_000 {
let x = rng.random_range(0..=3);
match x {
0 => match slab.push_front(c) {
Err(_) => {
assert!(slab.is_full());
assert_eq!(slab.free(), 0);
}
Ok(idx) => {
deque.push_front(idx);
expected_len += 1;
assert!(expected_len <= capacity);
assert_eq!(slab.free(), capacity - expected_len);
}
},
1 => match slab.pop_back() {
None => {
assert!(slab.is_empty());
assert_eq!(slab.free(), capacity);
}
Some(_x) => {
deque.pop_back().unwrap();
expected_len -= 1;
assert_eq!(slab.free(), capacity - expected_len);
if expected_len == 0 {
assert!(slab.is_empty());
}
}
},
2 => {
if slab.is_empty() {
continue;
}
let deque_len = deque.len();
if deque_len == 0 {
continue;
}
let r = rng.random_range(0..deque_len);
let idx = deque.remove(r).unwrap();
slab.remove(idx).unwrap();
expected_len -= 1;
assert_eq!(slab.free(), capacity - expected_len);
}
3 => {
if deque.is_empty() {
continue;
}
let r = rng.random_range(0..deque.len());
let slot = deque[r];
let idx = deque.iter().position(|&x| x == slot).unwrap();
deque.remove(idx);
slab.remove(slot).unwrap();
expected_len -= 1;
assert_eq!(slab.free(), capacity - expected_len);
}
_ => unreachable!(),
}
assert_eq!(slab.len(), expected_len);
c += 1;
}
}
#[test]
fn test_default() {
let slab: Slab<i32> = Slab::default();
assert_eq!(slab.capacity(), 16);
assert_eq!(slab.len(), 0);
assert!(slab.is_empty());
}
#[test]
fn test_from_iterator() {
let values = vec![1, 2, 3, 4, 5];
let slab: Slab<i32> = values.clone().into_iter().collect();
assert_eq!(slab.len(), 5);
if slab.len() == 5 {
assert_eq!(*slab.get(0).unwrap(), 5); assert_eq!(*slab.get(1).unwrap(), 4);
assert_eq!(*slab.get(2).unwrap(), 3);
assert_eq!(*slab.get(3).unwrap(), 2);
assert_eq!(*slab.get(4).unwrap(), 1); }
}
#[test]
fn test_extend() {
let mut slab = Slab::with_capacity(5).unwrap();
slab.push_front(1).unwrap();
slab.push_front(2).unwrap();
slab.extend(vec![3, 4, 5]);
assert_eq!(slab.len(), 5);
let items: Vec<_> = slab.iter().copied().collect();
assert_eq!(items, vec![5, 4, 3, 2, 1]);
}
#[test]
fn test_clear() {
let mut slab = Slab::with_capacity(3).unwrap();
slab.push_front(1).unwrap();
slab.push_front(2).unwrap();
slab.push_front(3).unwrap();
assert_eq!(slab.len(), 3);
assert!(slab.is_full());
slab.clear();
assert_eq!(slab.len(), 0);
assert!(slab.is_empty());
assert!(!slab.is_full());
let a = slab.push_front(4).unwrap();
let b = slab.push_front(5).unwrap();
let c = slab.push_front(6).unwrap();
assert_eq!(slab.len(), 3);
assert!(slab.is_full());
assert_eq!(*slab.get(a).unwrap(), 4);
assert_eq!(*slab.get(b).unwrap(), 5);
assert_eq!(*slab.get(c).unwrap(), 6);
}