use core::hash::{BuildHasher, Hash};
use core::mem::MaybeUninit;
use super::types::SmallMap;
pub enum Entry<'a, K, V, const N: usize, S> {
Occupied(OccupiedEntry<'a, K, V, N, S>),
Vacant(VacantEntry<'a, K, V, N, S>),
}
pub struct OccupiedEntry<'a, K, V, const N: usize, S> {
pub(super) inner: OccupiedInner<'a, K, V, N, S>,
}
pub(super) enum OccupiedInner<'a, K, V, const N: usize, S> {
Inline { map: &'a mut SmallMap<K, V, N, S>, index: usize },
Heap(hashbrown::hash_map::OccupiedEntry<'a, K, V, S>),
}
pub struct VacantEntry<'a, K, V, const N: usize, S> {
pub(super) inner: VacantInner<'a, K, V, N, S>,
}
pub(super) enum VacantInner<'a, K, V, const N: usize, S> {
Inline { map: &'a mut SmallMap<K, V, N, S>, key: K, h2: u8 },
Heap(hashbrown::hash_map::VacantEntry<'a, K, V, S>),
}
impl<'a, K, V, const N: usize, S> Entry<'a, K, V, N, S>
where
K: Eq + Hash,
S: BuildHasher,
{
#[inline]
pub fn key(&self) -> &K {
match self {
Entry::Occupied(o) => o.key(),
Entry::Vacant(v) => v.key(),
}
}
#[inline]
pub fn or_insert(self, default: V) -> &'a mut V {
match self {
Entry::Occupied(o) => o.into_mut(),
Entry::Vacant(v) => v.insert(default),
}
}
#[inline]
pub fn or_insert_with(self, f: impl FnOnce() -> V) -> &'a mut V {
match self {
Entry::Occupied(o) => o.into_mut(),
Entry::Vacant(v) => v.insert(f()),
}
}
#[inline]
pub fn or_insert_with_key(self, f: impl FnOnce(&K) -> V) -> &'a mut V {
match self {
Entry::Occupied(o) => o.into_mut(),
Entry::Vacant(v) => {
let value = f(v.key());
v.insert(value)
}
}
}
#[inline]
pub fn or_default(self) -> &'a mut V
where
V: Default,
{
self.or_insert_with(Default::default)
}
#[inline]
pub fn and_modify(self, f: impl FnOnce(&mut V)) -> Self {
match self {
Entry::Occupied(mut o) => {
f(o.get_mut());
Entry::Occupied(o)
}
Entry::Vacant(v) => Entry::Vacant(v),
}
}
}
impl<'a, K, V, const N: usize, S> OccupiedEntry<'a, K, V, N, S> {
#[inline]
pub fn key(&self) -> &K {
match &self.inner {
OccupiedInner::Inline { map, index } => match &**map {
SmallMap::Inline(inline) => unsafe {
&inline.entries[*index].assume_init_ref().0
},
_ => unreachable!(),
},
OccupiedInner::Heap(entry) => entry.key(),
}
}
#[inline]
pub fn get(&self) -> &V {
match &self.inner {
OccupiedInner::Inline { map, index } => match &**map {
SmallMap::Inline(inline) => unsafe {
&inline.entries[*index].assume_init_ref().1
},
_ => unreachable!(),
},
OccupiedInner::Heap(entry) => entry.get(),
}
}
#[inline]
pub fn get_mut(&mut self) -> &mut V {
match &mut self.inner {
OccupiedInner::Inline { map, index } => match &mut **map {
SmallMap::Inline(inline) => unsafe {
&mut inline.entries[*index].assume_init_mut().1
},
_ => unreachable!(),
},
OccupiedInner::Heap(entry) => entry.get_mut(),
}
}
#[inline]
pub fn into_mut(self) -> &'a mut V {
match self.inner {
OccupiedInner::Inline { map, index } => match map {
SmallMap::Inline(inline) => unsafe {
&mut inline.entries[index].assume_init_mut().1
},
_ => unreachable!(),
},
OccupiedInner::Heap(entry) => entry.into_mut(),
}
}
#[inline]
pub fn insert(&mut self, value: V) -> V {
match &mut self.inner {
OccupiedInner::Inline { map, index } => match &mut **map {
SmallMap::Inline(inline) => {
let (_, v) = unsafe { inline.entries[*index].assume_init_mut() };
core::mem::replace(v, value)
}
_ => unreachable!(),
},
OccupiedInner::Heap(entry) => entry.insert(value),
}
}
#[inline]
pub fn remove(self) -> V {
self.remove_entry().1
}
#[inline]
pub fn remove_entry(self) -> (K, V) {
match self.inner {
OccupiedInner::Inline { map, index } => match map {
SmallMap::Inline(inline) => {
let entry = unsafe { inline.entries[index].as_ptr().read() };
unsafe { inline.erase(index) };
entry
}
_ => unreachable!(),
},
OccupiedInner::Heap(entry) => entry.remove_entry(),
}
}
}
impl<'a, K, V, const N: usize, S> VacantEntry<'a, K, V, N, S> {
#[inline]
pub fn key(&self) -> &K {
match &self.inner {
VacantInner::Inline { key, .. } => key,
VacantInner::Heap(entry) => entry.key(),
}
}
#[inline]
pub fn into_key(self) -> K {
match self.inner {
VacantInner::Inline { key, .. } => key,
VacantInner::Heap(entry) => entry.into_key(),
}
}
}
impl<'a, K, V, const N: usize, S> VacantEntry<'a, K, V, N, S>
where
K: Eq + Hash,
S: BuildHasher,
{
#[inline]
pub fn insert(self, value: V) -> &'a mut V {
match self.inner {
VacantInner::Inline { map, key, h2 } => {
let is_full = match &*map {
SmallMap::Inline(inline) => inline.is_full(),
_ => unreachable!(),
};
if !is_full {
match map {
SmallMap::Inline(inline) => {
let idx = inline.len;
inline.h2_bytes[idx] = h2;
inline.entries[idx] = MaybeUninit::new((key, value));
inline.len += 1;
unsafe { &mut inline.entries[idx].assume_init_mut().1 }
}
_ => unreachable!(),
}
} else {
map.force_spill();
match map {
SmallMap::Heap(heap) => match heap.entry(key) {
hashbrown::hash_map::Entry::Vacant(v) => v.insert(value),
_ => unreachable!(),
},
_ => unreachable!(),
}
}
}
VacantInner::Heap(entry) => entry.insert(value),
}
}
}