use core::{
fmt,
hash::{BuildHasher, Hash},
mem,
ops::{Index, IndexMut},
};
#[cfg(feature = "std")]
use std::hash::RandomState;
use hashbrown::{hash_table, Equivalent, HashTable};
use slab::Slab;
use crate::{TryReserveError, ValueData};
use super::KeyData;
mod keys;
pub use keys::{FullKeys, Indices, IntoKeys, Keys};
mod values;
pub use values::{IntoValues, Values, ValuesMut};
mod iter;
pub use iter::{IntoFullIter, IntoIter, Iter, IterFull, IterFullMut, IterMut};
mod drain;
pub use drain::{Drain, DrainFull};
mod entry;
pub use entry::{Entry, OccupiedEntry, VacantEntry};
#[cfg(test)]
mod tests;
#[cfg(feature = "std")]
pub struct HashSlabMap<K, V, S = RandomState> {
pub(crate) table: HashTable<KeyData<K>>,
pub(crate) slab: Slab<ValueData<V>>,
pub(crate) builder: S,
}
#[cfg(not(feature = "std"))]
pub struct HashSlabMap<K, V, S> {
table: HashTable<KeyData<K>>,
slab: Slab<ValueData<V>>,
builder: S,
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl<K, V> HashSlabMap<K, V> {
#[inline]
pub fn new() -> Self {
Self::with_capacity(0)
}
#[inline]
pub fn with_capacity(n: usize) -> Self {
Self::with_capacity_and_hasher(n, Default::default())
}
}
impl<K, V, S> HashSlabMap<K, V, S> {
#[inline]
pub fn with_capacity_and_hasher(n: usize, builder: S) -> Self {
Self {
table: HashTable::with_capacity(n),
slab: Slab::with_capacity(n),
builder,
}
}
pub const fn with_hasher(builder: S) -> Self {
Self {
table: HashTable::new(),
slab: Slab::new(),
builder,
}
}
pub fn capacity(&self) -> usize {
self.table.capacity().min(self.slab.capacity())
}
pub fn hasher(&self) -> &S {
&self.builder
}
#[inline]
pub fn len(&self) -> usize {
debug_assert_eq!(
self.table.len(),
self.slab.len(),
"Number of entries in HashTable and Slab should be equal"
);
self.table.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn iter_full(&self) -> IterFull<'_, K, V> {
IterFull::new(self.table.iter(), &self.slab)
}
pub fn iter(&self) -> Iter<'_, K, V> {
Iter::new(self.iter_full())
}
pub fn iter_full_mut(&mut self) -> IterFullMut<'_, K, V> {
IterFullMut::new(self.table.iter(), &mut self.slab)
}
pub fn iter_mut(&mut self) -> IterMut<'_, K, V>
where
K: Clone,
{
IterMut::new(self.iter_full_mut())
}
pub fn into_full_iter(self) -> IntoFullIter<K, V> {
IntoFullIter::new(self.table.into_iter(), self.slab)
}
pub fn full_keys(&self) -> FullKeys<'_, K> {
FullKeys::new(self.table.iter())
}
pub fn keys(&self) -> Keys<'_, K> {
Keys::new(self.full_keys())
}
pub fn into_keys(self) -> IntoKeys<K> {
IntoKeys::new(self.table.into_iter())
}
pub fn indices(&self) -> Indices<'_, K> {
Indices::new(self.table.iter())
}
pub fn values(&self) -> Values<'_, K, V> {
Values::new(self.iter_full())
}
pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> {
ValuesMut::new(self.iter_full_mut())
}
pub fn into_values(self) -> IntoValues<K, V> {
IntoValues::new(self.into_iter())
}
pub fn clear(&mut self) {
self.table.clear();
self.slab.clear();
}
pub fn drain_full(&mut self) -> DrainFull<'_, K, V> {
DrainFull::new(self.table.drain(), &mut self.slab)
}
pub fn drain(&mut self) -> Drain<'_, K, V> {
Drain::new(self.drain_full())
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&K, &mut V) -> bool,
{
self.table.retain(|KeyData { key, index }| {
let value = &mut self.slab[*index].value;
if f(key, value) {
true
} else {
self.slab.remove(*index);
false
}
})
}
pub fn get_index(&self, index: usize) -> Option<(&K, &V)> {
let ValueData { value, hash } = self.slab.get(index)?;
self.table
.find(*hash, |e| e.index == index)
.map(|KeyData { key, .. }| (key, value))
}
pub fn get_index_value(&self, index: usize) -> Option<&V> {
self.slab.get(index).map(|ValueData { value, .. }| value)
}
pub fn vacant_index(&self) -> usize {
self.slab.vacant_key()
}
}
impl<K, V, S> HashSlabMap<K, V, S>
where
K: Hash + Eq,
S: BuildHasher,
{
pub fn reserve(&mut self, additional: usize) {
self.table.reserve(additional, make_hasher(&self.builder));
self.slab.reserve(additional);
}
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
self.table
.try_reserve(additional, make_hasher(&self.builder))?;
let capacity = self.slab.capacity();
if (capacity + additional) <= isize::MAX as usize {
self.slab.reserve(additional);
Ok(())
} else {
Err(TryReserveError::Slab {
capacity,
additional,
})
}
}
pub fn shrink_to_fit(&mut self) {
self.table.shrink_to_fit(make_hasher(&self.builder));
self.slab.shrink_to_fit();
}
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
self.insert_full(key, value).1
}
pub fn insert_full(&mut self, key: K, value: V) -> (usize, Option<V>) {
let hash = self.builder.hash_one(&key);
match self
.table
.entry(hash, |e| e.key == key, make_hasher(&self.builder))
{
hash_table::Entry::Occupied(entry) => {
let i = entry.get().index;
(i, Some(mem::replace(&mut self.slab[i].value, value)))
}
hash_table::Entry::Vacant(entry) => {
let index = self.slab.insert(ValueData::new(value, hash));
entry.insert(KeyData::new(key, index));
debug_assert_eq!(self.table.len(), self.slab.len());
(index, None)
}
}
}
pub fn get_full<Q>(&self, key: &Q) -> Option<(usize, &K, &V)>
where
Q: Hash + Equivalent<K> + ?Sized,
{
self.get_key_index(key)
.map(|(key, index)| (index, key, &self.slab[index].value))
}
pub fn get_key_value<Q>(&self, key: &Q) -> Option<(&K, &V)>
where
Q: Hash + Equivalent<K> + ?Sized,
{
self.get_full(key).map(|(_, key, data)| (key, data))
}
pub fn get<Q>(&self, key: &Q) -> Option<&V>
where
Q: Hash + Equivalent<K> + ?Sized,
{
self.get_full(key).map(|(_, _, data)| data)
}
pub fn get_index_of<Q>(&self, key: &Q) -> Option<usize>
where
Q: Hash + Equivalent<K> + ?Sized,
{
self.get_key_index(key).map(|(_, index)| index)
}
pub fn get_full_mut<Q>(&mut self, key: &Q) -> Option<(usize, &K, &mut V)>
where
Q: ?Sized + Hash + Equivalent<K>,
{
if self.table.is_empty() {
None
} else {
let hash = self.builder.hash_one(key);
self.table
.find(hash, |e| key.equivalent(&e.key))
.map(|KeyData { index, key, .. }| (*index, key, &mut self.slab[*index].value))
}
}
pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
where
Q: ?Sized + Hash + Equivalent<K>,
{
self.get_full_mut(key).map(|(_, _, value)| value)
}
pub fn get_index_mut(&mut self, index: usize) -> Option<(&K, &mut V)> {
let ValueData { value, hash } = self.slab.get_mut(index)?;
self.table
.find(*hash, |e| e.index == index)
.map(|KeyData { key, .. }| (key, value))
}
pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
where
Q: ?Sized + Hash + Equivalent<K>,
{
self.remove_entry(key).map(|(_, v)| v)
}
pub fn remove_entry<Q>(&mut self, key: &Q) -> Option<(K, V)>
where
Q: ?Sized + Hash + Equivalent<K>,
{
self.remove_full(key).map(|(_, k, v)| (k, v))
}
pub fn remove_full<Q>(&mut self, key: &Q) -> Option<(usize, K, V)>
where
Q: ?Sized + Hash + Equivalent<K>,
{
let hash = self.builder.hash_one(key);
self.table
.find_entry(hash, |e| key.equivalent(&e.key))
.ok()
.map(|entry| {
let (KeyData { key, index, .. }, _) = entry.remove();
let ValueData { value, .. } = self.slab.remove(index);
(index, key, value)
})
}
pub fn remove_index(&mut self, index: usize) -> Option<(K, V)> {
let ValueData { value, hash } = self.slab.try_remove(index)?;
self.table
.find_entry(hash, |e| e.index == index)
.ok()
.map(|entry| {
let (KeyData { key, .. }, _) = entry.remove();
(key, value)
})
}
pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
let hash = self.builder.hash_one(&key);
match self
.table
.entry(hash, |e| e.key == key, make_hasher(&self.builder))
{
hash_table::Entry::Occupied(occupied_entry) => {
Entry::Occupied(OccupiedEntry::new(occupied_entry, &mut self.slab))
}
hash_table::Entry::Vacant(vacant_entry) => {
Entry::Vacant(VacantEntry::new(vacant_entry, &mut self.slab, key, hash))
}
}
}
pub fn contains_key<Q>(&self, key: &Q) -> bool
where
Q: Hash + Equivalent<K> + ?Sized,
{
let hash = self.builder.hash_one(key);
self.table.find(hash, |e| key.equivalent(&e.key)).is_some()
}
pub fn contains_index(&self, index: usize) -> bool {
self.slab.contains(index)
}
pub fn append<S2>(&mut self, other: &mut HashSlabMap<K, V, S2>) {
self.extend(other.drain());
}
}
impl<K, V, S> HashSlabMap<K, V, S> {
fn get_key_index<Q>(&self, key: &Q) -> Option<(&K, usize)>
where
Q: Hash + Equivalent<K> + ?Sized,
S: BuildHasher,
{
if self.table.is_empty() {
None
} else {
let hash = self.builder.hash_one(key);
self.table
.find(hash, |e| key.equivalent(&e.key))
.map(|KeyData { index, key, .. }| (key, *index))
}
}
}
impl<K: Clone, V: Clone, S: Clone> Clone for HashSlabMap<K, V, S> {
fn clone(&self) -> Self {
Self {
table: self.table.clone(),
slab: self.slab.clone(),
builder: self.builder.clone(),
}
}
}
impl<K, V> fmt::Debug for HashSlabMap<K, V>
where
K: fmt::Debug,
V: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map()
.entries(self.iter_full().map(|(i, k, v)| (i, (k, v))))
.finish()
}
}
impl<K, V, S> Default for HashSlabMap<K, V, S>
where
S: Default,
{
fn default() -> Self {
Self::with_capacity_and_hasher(0, S::default())
}
}
impl<K, V, Q: ?Sized, S> Index<&Q> for HashSlabMap<K, V, S>
where
K: Hash + Eq,
Q: Hash + Equivalent<K>,
S: BuildHasher,
{
type Output = V;
fn index(&self, key: &Q) -> &V {
self.get(key).expect("HashSlabMap: key not found")
}
}
impl<K, V, S> Index<usize> for HashSlabMap<K, V, S>
where
K: Hash + Eq,
S: BuildHasher,
{
type Output = V;
fn index(&self, index: usize) -> &V {
self.get_index(index)
.expect("HashSlabMap: index out of bounds")
.1
}
}
impl<K, V, Q: ?Sized, S> IndexMut<&Q> for HashSlabMap<K, V, S>
where
K: Hash + Eq,
Q: Hash + Equivalent<K>,
S: BuildHasher,
{
fn index_mut(&mut self, key: &Q) -> &mut V {
self.get_mut(key).expect("HashSlabMap: key not found")
}
}
impl<K, V, S> IndexMut<usize> for HashSlabMap<K, V, S>
where
K: Hash + Eq,
S: BuildHasher,
{
fn index_mut(&mut self, index: usize) -> &mut V {
self.get_index_mut(index)
.expect("HashSlabMap: index out of bounds")
.1
}
}
impl<K, V, S> Extend<(K, V)> for HashSlabMap<K, V, S>
where
K: Hash + Eq,
S: BuildHasher,
{
fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iterable: I) {
let iter = iterable.into_iter();
let reserve = if self.is_empty() {
iter.size_hint().0
} else {
(iter.size_hint().0 + 1) / 2
};
self.reserve(reserve);
iter.for_each(move |(k, v)| {
self.insert(k, v);
});
}
}
impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashSlabMap<K, V, S>
where
K: Hash + Eq + Copy,
V: Copy,
S: BuildHasher,
{
fn extend<I: IntoIterator<Item = (&'a K, &'a V)>>(&mut self, iterable: I) {
self.extend(iterable.into_iter().map(|(&key, &value)| (key, value)));
}
}
impl<'a, K, V, S> Extend<&'a (K, V)> for HashSlabMap<K, V, S>
where
K: Eq + Hash + Copy,
V: Copy,
S: BuildHasher,
{
fn extend<T: IntoIterator<Item = &'a (K, V)>>(&mut self, iter: T) {
self.extend(iter.into_iter().map(|&(key, value)| (key, value)));
}
}
impl<K, V, S> FromIterator<(K, V)> for HashSlabMap<K, V, S>
where
K: Hash + Eq,
S: BuildHasher + Default,
{
fn from_iter<I: IntoIterator<Item = (K, V)>>(iterable: I) -> Self {
let iter = iterable.into_iter();
let (low, _) = iter.size_hint();
let mut map = Self::with_capacity_and_hasher(low, S::default());
map.extend(iter);
map
}
}
impl<K, V, const N: usize> From<[(K, V); N]> for HashSlabMap<K, V, RandomState>
where
K: Hash + Eq,
{
fn from(arr: [(K, V); N]) -> Self {
Self::from_iter(arr)
}
}
impl<K, V1, S1, V2, S2> PartialEq<HashSlabMap<K, V2, S2>> for HashSlabMap<K, V1, S1>
where
K: Hash + Eq,
V1: PartialEq<V2>,
S1: BuildHasher,
S2: BuildHasher,
{
fn eq(&self, other: &HashSlabMap<K, V2, S2>) -> bool {
if self.len() != other.len() {
return false;
}
self.iter()
.all(|(key, value)| other.get(key).map_or(false, |v| *value == *v))
}
}
impl<K, V, S> Eq for HashSlabMap<K, V, S>
where
K: Eq + Hash,
V: Eq,
S: BuildHasher,
{
}
#[inline]
pub(crate) fn make_hasher<K, S>(hash_builder: &S) -> impl Fn(&KeyData<K>) -> u64 + '_
where
K: Hash,
S: BuildHasher,
{
move |val| hash_builder.hash_one(&val.key)
}