use std::borrow::Borrow;
use std::ptr;
use kevy_hash::KevyHash;
use crate::map::{DELETED, KevyMap, ProbeOutcome};
pub enum RawEntryMut<'a, K, V> {
Occupied(RawOccupiedEntryMut<'a, K, V>),
Vacant(RawVacantEntryMut<'a, K, V>),
}
pub struct RawOccupiedEntryMut<'a, K, V> {
map: &'a mut KevyMap<K, V>,
slot: usize,
}
pub struct RawVacantEntryMut<'a, K, V> {
map: &'a mut KevyMap<K, V>,
}
impl<K, V> KevyMap<K, V> {
pub fn raw_entry_mut<Q>(&mut self, key: &Q) -> RawEntryMut<'_, K, V>
where
K: Borrow<Q> + KevyHash + Eq,
Q: KevyHash + Eq + ?Sized,
{
match self.probe_by_borrow(key) {
ProbeOutcome::Found(slot) => RawEntryMut::Occupied(RawOccupiedEntryMut {
map: self,
slot,
}),
ProbeOutcome::NotFound { .. } => {
RawEntryMut::Vacant(RawVacantEntryMut { map: self })
}
}
}
}
impl<'a, K, V> RawOccupiedEntryMut<'a, K, V> {
#[inline]
pub fn get(&self) -> &V {
let kv = unsafe { (*self.map.slots_ptr.as_ptr().add(self.slot)).assume_init_ref() };
&kv.1
}
#[inline]
pub fn get_mut(&mut self) -> &mut V {
let kv = unsafe { (*self.map.slots_ptr.as_ptr().add(self.slot)).assume_init_mut() };
&mut kv.1
}
#[inline]
pub fn into_mut(self) -> &'a mut V {
let kv = unsafe { (*self.map.slots_ptr.as_ptr().add(self.slot)).assume_init_mut() };
&mut kv.1
}
#[inline]
pub fn key(&self) -> &K {
let kv = unsafe { (*self.map.slots_ptr.as_ptr().add(self.slot)).assume_init_ref() };
&kv.0
}
pub fn remove(self) -> V {
self.map.set_meta(self.slot, DELETED);
self.map.occupied -= 1;
self.map.deleted += 1;
let (_k, v) = unsafe {
ptr::read(self.map.slots_ptr.as_ptr().add(self.slot) as *const (K, V))
};
v
}
}
impl<'a, K, V> RawVacantEntryMut<'a, K, V>
where
K: KevyHash + Eq,
{
pub fn insert(self, key: K, value: V) -> &'a mut V {
self.map.maybe_grow();
let hash = key.kevy_hash();
let outcome = self.map.probe_by_borrow(&key);
let slot = match outcome {
ProbeOutcome::NotFound { insert_at, via_tombstone } => {
self.map.set_meta(insert_at, crate::map::h2(hash));
unsafe {
(*self.map.slots_ptr.as_ptr().add(insert_at)).write((key, value));
}
self.map.occupied += 1;
if via_tombstone {
self.map.deleted -= 1;
}
insert_at
}
ProbeOutcome::Found(_) => {
unreachable!("raw vacant insert observed an existing key");
}
};
let kv = unsafe { (*self.map.slots_ptr.as_ptr().add(slot)).assume_init_mut() };
&mut kv.1
}
}