mod entry;
mod r#ref;
use std::{
collections::hash_map::RandomState,
fmt::Debug,
hash::{BuildHasher, Hash},
ops::Deref,
sync::Arc,
};
use dashmap::DashMap;
use sharded_slab::Slab;
#[doc(inline)]
pub use self::entry::{Entry, OccupiedEntry, VacantEntry};
#[doc(inline)]
pub use self::r#ref::{OwnedRef, Ref, RefWrapper};
pub trait Key: Copy + Eq + Hash {}
impl<T> Key for T where T: Copy + Eq + Hash {}
pub trait Keyed {
type Key: Key;
fn key(&self) -> Self::Key;
}
#[derive(Debug, Copy, Clone)]
pub struct Index<K: Key, V> {
off: usize,
key: K,
_marker: std::marker::PhantomData<V>,
}
pub struct ReSlab<K: Key, V, S = RandomState> {
idxs: DashMap<K, usize, S>,
slab: Arc<Slab<V>>,
}
impl<K: Key, V, S> ReSlab<K, V, S>
where
S: Default + BuildHasher + Clone,
{
#[inline]
pub fn new() -> Self {
Self::with_capacity(0)
}
#[inline]
pub fn with_hasher(builder: S) -> Self {
Self::with_capacity_and_hasher(0, builder)
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self::with_capacity_and_hasher(capacity, Default::default())
}
#[inline]
pub fn with_capacity_and_hasher(capacity: usize, builder: S) -> Self {
Self {
idxs: DashMap::with_capacity_and_hasher(capacity, builder.clone()),
slab: Arc::new(Slab::new()),
}
}
#[inline]
pub fn get<'a>(&'a self, key: &K) -> Option<Ref<'a, K, V>> {
self.idxs.get(key).map(|offset| {
let entry = unsafe { self.get_direct(*offset.value()) };
entry.expect("BUG: dangling index found in indeces map")
})
}
pub fn get_by<'a>(&'a self, index: &Index<K, V>) -> Option<Ref<'a, K, V>>
where
V: Keyed<Key = K>,
{
self.slab
.get(index.offset())
.filter(|i| i.deref().key() == index.key())
.map(Ref::new)
}
#[inline]
pub unsafe fn get_direct(&self, offset: usize) -> Option<Ref<'_, K, V>> {
self.slab.get(offset).map(Ref::new)
}
#[inline]
pub fn get_owned(&self, key: &K) -> Option<OwnedRef<K, V>> {
self.idxs.get(key).map(|offset| {
let entry = unsafe { self.get_owned_direct(*offset.value()) };
entry.expect("BUG: dangling index found in indeces map")
})
}
pub fn get_owned_by(&self, index: &Index<K, V>) -> Option<OwnedRef<K, V>>
where
V: Keyed<Key = K>,
{
self.slab
.clone()
.get_owned(index.offset())
.filter(|i| i.deref().key() == index.key())
.map(OwnedRef::new)
}
#[inline]
pub unsafe fn get_owned_direct(
&self,
offset: usize,
) -> Option<OwnedRef<K, V>> {
self.slab.clone().get_owned(offset).map(OwnedRef::new)
}
#[inline]
pub fn contains(&self, key: &K) -> bool {
self.idxs.contains_key(key)
}
#[inline]
pub fn exists(&self, idx: &Index<K, V>) -> bool {
self.idxs
.get(&idx.key())
.map(|offset| offset.value() == &idx.offset())
.unwrap_or(false)
}
#[inline]
pub fn entry(&self, key: K) -> Entry<'_, K, V, S> {
Entry::new(key, &self.idxs, &self.slab)
}
#[inline]
pub fn remove(&self, idx: &Index<K, V>) -> bool {
if let Entry::Occupied(o) = self.entry(idx.key) {
if o.offset() != idx.offset() {
return false;
}
let offset = unsafe { o.unlink() };
assert_eq!(
offset,
idx.offset(),
"invalid slab offset was detected"
);
let removed = self.slab.remove(offset);
assert!(removed, "failed to remove slab entry");
}
false
}
#[inline]
pub fn index_of(&self, key: K) -> Option<Index<K, V>> {
self.idxs.get(&key).map(|idx| Index::new(key, *idx.value()))
}
}
impl<K: Key, V, S> Default for ReSlab<K, V, S>
where
S: Default + BuildHasher + Clone,
{
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<K, V, S> std::fmt::Debug for ReSlab<K, V, S>
where
K: Key + Debug,
V: Debug,
S: BuildHasher + Clone + Debug,
{
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ReSlab")
.field("idxs", &self.idxs)
.field("slab", &self.slab)
.finish()
}
}
impl<K: Key, V> Index<K, V> {
#[inline]
const fn new(key: K, slab_offset: usize) -> Self {
Self {
off: slab_offset,
key,
_marker: std::marker::PhantomData,
}
}
#[inline]
pub const fn key(&self) -> K {
self.key
}
#[inline]
pub const fn offset(&self) -> usize {
self.off
}
}