use arrayvec::ArrayVec;
use std::iter::{IntoIterator, Iterator};
use std::mem;
use std::ops;
use std::pin::Pin;
pub const CHUNK_SIZE: usize = 1024;
#[derive(Debug, Clone)]
pub struct Slab<T> {
chunks: Vec<Chunk<T>>,
len: usize,
next: usize,
}
impl<T> Default for Slab<T> {
fn default() -> Self {
Slab::new()
}
}
#[derive(Debug, Clone)]
struct Chunk<T> {
pub entries: Pin<Box<ArrayVec<[Entry<T>; CHUNK_SIZE]>>>,
pub len: usize,
}
impl<T> Chunk<T> {
pub fn new() -> Self {
Chunk {
entries: Box::pin(ArrayVec::new()),
len: 0,
}
}
}
#[derive(Debug, Clone)]
enum Entry<T> {
Occupied(T),
Vacant(usize),
}
pub struct Iter<'a, T: 'a> {
chunks: std::slice::Iter<'a, Chunk<T>>,
entries: std::slice::Iter<'a, Entry<T>>,
curr: usize,
}
pub struct IterMut<'a, T: 'a> {
chunks: std::slice::IterMut<'a, Chunk<T>>,
entries: std::slice::IterMut<'a, Entry<T>>,
curr: usize,
}
impl<T> Slab<T> {
pub fn new() -> Self {
Slab {
chunks: Vec::new(),
len: 0,
next: 0,
}
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn contains(&self, key: usize) -> bool {
self.get(key).is_some()
}
pub fn capacity(&self) -> usize {
self.chunks.len() * CHUNK_SIZE
}
pub fn iter(&self) -> Iter<T> {
Iter {
chunks: self.chunks.iter(),
entries: [].iter(),
curr: 0,
}
}
pub unsafe fn iter_mut(&mut self) -> IterMut<T> {
IterMut {
chunks: self.chunks.iter_mut(),
entries: [].iter_mut(),
curr: 0,
}
}
pub fn get(&self, key: usize) -> Option<&T> {
let slab_key = key / CHUNK_SIZE;
let entry_key = key % CHUNK_SIZE;
let slab = self.chunks.get(slab_key)?;
match slab.entries.get(entry_key) {
Some(&Entry::Occupied(ref val)) => Some(val),
_ => None,
}
}
pub unsafe fn get_mut(&mut self, key: usize) -> Option<&mut T> {
let slab_key = key / CHUNK_SIZE;
let entry_key = key % CHUNK_SIZE;
let slab = self.chunks.get_mut(slab_key)?;
let entries = slab.entries.as_mut().get_unchecked_mut();
match entries.get_mut(entry_key) {
Some(&mut Entry::Occupied(ref mut val)) => Some(val),
_ => None,
}
}
pub fn insert(&mut self, val: T) -> (usize, &T) {
let key = self.next;
(key, self.insert_at(key, val))
}
fn insert_at(&mut self, key: usize, val: T) -> &T {
self.len += 1;
let slab_key = key / CHUNK_SIZE;
let entry_key = key % CHUNK_SIZE;
if slab_key == self.chunks.len() {
debug_assert_eq!(entry_key, 0);
self.chunks.push(Chunk::new());
}
let slab = self.chunks.get_mut(slab_key).expect("invalid key");
slab.len += 1;
let entries = unsafe { slab.entries.as_mut().get_unchecked_mut() };
if entry_key == entries.len() {
entries.push(Entry::Occupied(val));
self.next = key + 1;
match entries.get(entries.len() - 1) {
Some(Entry::Occupied(ref v)) => v,
_ => unreachable!(),
}
} else {
let entry = &mut entries[entry_key];
let prev = mem::replace(entry, Entry::Occupied(val));
match prev {
Entry::Vacant(next) => {
self.next = next;
}
_ => unreachable!(),
}
match entry {
Entry::Occupied(ref v) => v,
_ => unreachable!(),
}
}
}
pub fn remove(&mut self, key: usize) -> T {
let slab_key = key / CHUNK_SIZE;
let entry_key = key % CHUNK_SIZE;
let chunk = self.chunks.get_mut(slab_key).expect("invalid key");
let entries = unsafe { chunk.entries.as_mut().get_unchecked_mut() };
let prev = mem::replace(&mut entries[entry_key], Entry::Vacant(self.next));
match prev {
Entry::Occupied(val) => {
chunk.len -= 1;
self.len -= 1;
self.next = key;
val
}
_ => {
entries[key] = prev;
panic!("invalid key");
}
}
}
pub fn free_unused(&mut self) {
self.chunks.retain(|slab| slab.len > 0)
}
pub unsafe fn retain<F>(&mut self, mut f: F)
where
F: FnMut(usize, &mut T) -> bool,
{
for i in 0..self.chunks.len() {
for j in 0..CHUNK_SIZE {
let chunk = self.chunks.get_mut(i).unwrap();
let entry = chunk.entries.as_mut().get_unchecked_mut().get_mut(j);
let key = i * CHUNK_SIZE + j;
let keep = match entry {
Some(Entry::Occupied(ref mut v)) => f(key, v),
None => break,
_ => true,
};
if !keep {
self.remove(key);
}
}
}
}
}
impl<T> ops::Index<usize> for Slab<T> {
type Output = T;
fn index(&self, key: usize) -> &T {
match self.get(key) {
Some(&ref v) => v,
_ => panic!("invalid key"),
}
}
}
impl<'a, T> IntoIterator for &'a Slab<T> {
type Item = (usize, &'a T);
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Iter<'a, T> {
self.iter()
}
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = (usize, &'a T);
fn next(&mut self) -> Option<Self::Item> {
loop {
while let Some(entry) = self.entries.next() {
let curr = self.curr;
self.curr += 1;
if let Entry::Occupied(ref v) = *entry {
return Some((curr, v));
}
}
if let Some(chunk) = self.chunks.next() {
self.entries = chunk.entries.iter();
} else {
return None;
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.chunks.len() * CHUNK_SIZE))
}
}
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = (usize, &'a mut T);
fn next(&mut self) -> Option<Self::Item> {
loop {
while let Some(entry) = self.entries.next() {
let curr = self.curr;
self.curr += 1;
if let Entry::Occupied(ref mut v) = *entry {
return Some((curr, v));
}
}
if let Some(chunk) = self.chunks.next() {
let entries = chunk.entries.as_mut();
self.entries = unsafe { entries.get_unchecked_mut().iter_mut() };
} else {
return None;
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.chunks.len() * CHUNK_SIZE))
}
}