use std::{marker, mem};
pub use error::Error;
pub use occupied::Occupied;
pub use vacant::Vacant;
use crate::{
alloc::array,
depot::{capacity, index::Initialized, map::direct, queue::links},
};
mod error;
mod occupied;
pub(in crate::depot) mod raw;
mod vacant;
pub struct Table<K: crate::depot::raw::Key, V> {
pub(in crate::depot) block: array::Block<raw::Entry<K, V>, capacity::Count, capacity::Count>,
}
impl<K: crate::depot::raw::Key, V> Table<K, V> {
pub fn try_new(capacity: capacity::Count) -> Result<Self, crate::alloc::Error> {
let block = array::Block::try_new(capacity, capacity::Count::EMPTY)?
.repeat_with(raw::Entry::vacant);
Ok(Self { block })
}
pub const fn capacity(&self) -> usize {
self.block.extent().get()
}
pub const fn len(&self) -> usize {
self.block.state().get()
}
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<K: crate::depot::raw::Key, V> Table<K, V> {
pub(in crate::depot) unsafe fn value(&self, index: links::Index) -> &V {
unsafe {
self.block
.get_unchecked(index.get())
.value
.assume_init_ref()
}
}
pub(in crate::depot) unsafe fn vacate(
&mut self,
index: links::Index,
) -> &mut mem::MaybeUninit<V> {
let (len, entries) = self.block.parts_mut();
let slot = unsafe { entries.get_unchecked_mut(index.get()) };
*len = capacity::Count::new((len.get() - 1) as u32);
slot.key = crate::depot::raw::Slot::vacant();
&mut slot.value
}
pub fn get(&self, key: K) -> Option<&V> {
let slot = self.block.get(key.index())?;
(slot.key == crate::depot::raw::Slot::from_key(key))
.then(|| unsafe { slot.value.assume_init_ref() })
}
pub fn entry_at(&self, index: usize) -> Option<(K, &V)> {
self.block.get(index)?.read()
}
pub fn key_at(&self, index: usize) -> Option<K> {
self.block.get(index)?.key.present().map(K::from_live)
}
pub fn iter(&self) -> impl Iterator<Item = (K, &V)> {
self.block.iter().filter_map(raw::Entry::read)
}
pub fn project<P>(
live: crate::depot::raw::Proof<(&Self, links::Index), Initialized<P>>,
) -> crate::depot::raw::Proof<(&V, K), Initialized<P>> {
unsafe {
live.map(|(read, index)| {
let slot = read.block.get_unchecked(index.get());
let key = slot.key.live();
(slot.value.assume_init_ref(), K::from_live(key))
})
}
}
}
impl<K: crate::depot::raw::Key, V> Table<K, V> {
pub fn entry(&mut self, key: K) -> Option<direct::Occupied<'_, K, V>> {
let slot = self.block.get(key.index())?;
(slot.key == crate::depot::raw::Slot::from_key(key)).then_some(direct::Occupied {
table: self,
key,
plane: marker::PhantomData,
})
}
pub fn try_vacant(&mut self, key: K) -> Result<direct::Vacant<'_, K, V>, direct::Error<K>> {
let index = key.index();
let slot = self.block.get(index).ok_or(direct::Error::Outside {
key,
index,
capacity: self.capacity(),
})?;
if !slot.key.is_vacant() {
let stored = unsafe { slot.key.live() };
return Err(direct::Error::Occupied {
key,
stored: K::from_live(stored),
});
}
Ok(direct::Vacant {
table: self,
key,
plane: marker::PhantomData,
})
}
pub fn vacant(&mut self, key: K) -> Option<direct::Vacant<'_, K, V>> {
let slot = self.block.get(key.index())?;
slot.key.is_vacant().then_some(direct::Vacant {
table: self,
key,
plane: marker::PhantomData,
})
}
pub fn clear(&mut self) {
if self.is_empty() {
return;
}
for index in 0..self.capacity() {
if unsafe { self.block.get_unchecked(index) }.key.is_vacant() {
continue;
}
unsafe {
self.vacate(links::Index::new_usize(index))
.assume_init_drop();
}
}
}
}