use super::{BiHashItem, BiHashMap, RefMut, entry_indexes::EntryIndexes};
use crate::{
DefaultHashBuilder,
support::{
alloc::{Allocator, Global},
borrow::DormantMutRef,
map_hash::MapHash,
},
};
use alloc::vec::Vec;
use core::{fmt, hash::BuildHasher};
pub enum Entry<'a, T: BiHashItem, S = DefaultHashBuilder, A: Allocator = Global>
{
Vacant(VacantEntry<'a, T, S, A>),
Occupied(OccupiedEntry<'a, T, S, A>),
}
impl<'a, T: BiHashItem, S, A: Allocator> fmt::Debug for Entry<'a, T, S, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Entry::Vacant(entry) => {
f.debug_tuple("Vacant").field(entry).finish()
}
Entry::Occupied(entry) => {
f.debug_tuple("Occupied").field(entry).finish()
}
}
}
}
impl<'a, T: BiHashItem, S: Clone + BuildHasher, A: Allocator>
Entry<'a, T, S, A>
{
#[inline]
pub fn or_insert(self, default: T) -> OccupiedEntryMut<'a, T, S> {
match self {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => {
OccupiedEntryMut::Unique(entry.insert(default))
}
}
}
#[inline]
pub fn or_insert_with<F: FnOnce() -> T>(
self,
default: F,
) -> OccupiedEntryMut<'a, T, S> {
match self {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => {
OccupiedEntryMut::Unique(entry.insert(default()))
}
}
}
#[inline]
pub fn and_modify<F>(self, f: F) -> Self
where
F: FnMut(RefMut<'_, T, S>),
{
match self {
Entry::Occupied(mut entry) => {
entry.get_mut().for_each(f);
Entry::Occupied(entry)
}
Entry::Vacant(entry) => Entry::Vacant(entry),
}
}
}
pub struct VacantEntry<
'a,
T: BiHashItem,
S = DefaultHashBuilder,
A: Allocator = Global,
> {
map: DormantMutRef<'a, BiHashMap<T, S, A>>,
hashes: [MapHash; 2],
}
impl<'a, T: BiHashItem, S, A: Allocator> fmt::Debug
for VacantEntry<'a, T, S, A>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("VacantEntry")
.field("hashes", &self.hashes)
.finish_non_exhaustive()
}
}
impl<'a, T: BiHashItem, S: Clone + BuildHasher, A: Allocator>
VacantEntry<'a, T, S, A>
{
pub(super) unsafe fn new(
map: DormantMutRef<'a, BiHashMap<T, S, A>>,
hashes: [MapHash; 2],
) -> Self {
VacantEntry { map, hashes }
}
pub fn insert(self, value: T) -> RefMut<'a, T, S> {
let map = unsafe { self.map.awaken() };
let state = &map.tables.state;
if !self.hashes[0].is_same_hash(state, value.key1()) {
panic!("key1 hashes do not match");
}
if !self.hashes[1].is_same_hash(state, value.key2()) {
panic!("key2 hashes do not match");
}
let Ok(index) = map.insert_unique_impl(value) else {
panic!("key already present in map");
};
map.get_by_index_mut(index).expect("index is known to be valid")
}
#[inline]
pub fn insert_entry(mut self, value: T) -> OccupiedEntry<'a, T, S, A> {
let index = {
let map = unsafe { self.map.reborrow() };
let state = &map.tables.state;
if !self.hashes[0].is_same_hash(state, value.key1()) {
panic!("key1 hashes do not match");
}
if !self.hashes[1].is_same_hash(state, value.key2()) {
panic!("key2 hashes do not match");
}
let Ok(index) = map.insert_unique_impl(value) else {
panic!("key already present in map");
};
index
};
unsafe { OccupiedEntry::new(self.map, EntryIndexes::Unique(index)) }
}
}
pub struct OccupiedEntry<
'a,
T: BiHashItem,
S = DefaultHashBuilder,
A: Allocator = Global,
> {
map: DormantMutRef<'a, BiHashMap<T, S, A>>,
indexes: EntryIndexes,
}
impl<'a, T: BiHashItem, S, A: Allocator> fmt::Debug
for OccupiedEntry<'a, T, S, A>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OccupiedEntry")
.field("indexes", &self.indexes)
.finish_non_exhaustive()
}
}
impl<'a, T: BiHashItem, S: Clone + BuildHasher, A: Allocator>
OccupiedEntry<'a, T, S, A>
{
pub(super) unsafe fn new(
map: DormantMutRef<'a, BiHashMap<T, S, A>>,
indexes: EntryIndexes,
) -> Self {
OccupiedEntry { map, indexes }
}
pub fn is_unique(&self) -> bool {
self.indexes.is_unique()
}
#[inline]
pub fn is_non_unique(&self) -> bool {
!self.is_unique()
}
pub fn get(&self) -> OccupiedEntryRef<'_, T> {
let map = unsafe { self.map.reborrow_shared() };
map.get_by_entry_index(self.indexes)
}
pub fn get_mut(&mut self) -> OccupiedEntryMut<'_, T, S> {
let map = unsafe { self.map.reborrow() };
map.get_by_entry_index_mut(self.indexes)
}
pub fn into_ref(self) -> OccupiedEntryRef<'a, T> {
let map = unsafe { self.map.awaken() };
map.get_by_entry_index(self.indexes)
}
pub fn into_mut(self) -> OccupiedEntryMut<'a, T, S> {
let map = unsafe { self.map.awaken() };
map.get_by_entry_index_mut(self.indexes)
}
pub fn insert(&mut self, value: T) -> Vec<T> {
let map = unsafe { self.map.reborrow() };
let (index, old_items) = map.replace_at_indexes(self.indexes, value);
self.indexes = EntryIndexes::Unique(index);
old_items
}
pub fn remove(mut self) -> Vec<T> {
let map = unsafe { self.map.reborrow() };
map.remove_by_entry_index(self.indexes)
}
}
#[derive(Debug)]
pub enum OccupiedEntryRef<'a, T: BiHashItem> {
Unique(&'a T),
NonUnique {
by_key1: Option<&'a T>,
by_key2: Option<&'a T>,
},
}
impl<'a, T: BiHashItem> OccupiedEntryRef<'a, T> {
#[inline]
pub fn is_unique(&self) -> bool {
matches!(self, Self::Unique(_))
}
#[inline]
pub fn is_non_unique(&self) -> bool {
matches!(self, Self::NonUnique { .. })
}
#[inline]
pub fn as_unique(&self) -> Option<&'a T> {
match self {
Self::Unique(v) => Some(v),
Self::NonUnique { .. } => None,
}
}
#[inline]
pub fn by_key1(&self) -> Option<&'a T> {
match self {
Self::Unique(v) => Some(v),
Self::NonUnique { by_key1, .. } => *by_key1,
}
}
#[inline]
pub fn by_key2(&self) -> Option<&'a T> {
match self {
Self::Unique(v) => Some(v),
Self::NonUnique { by_key2, .. } => *by_key2,
}
}
}
pub enum OccupiedEntryMut<
'a,
T: BiHashItem,
S: Clone + BuildHasher = DefaultHashBuilder,
> {
Unique(RefMut<'a, T, S>),
NonUnique {
by_key1: Option<RefMut<'a, T, S>>,
by_key2: Option<RefMut<'a, T, S>>,
},
}
impl<'a, T: BiHashItem + fmt::Debug, S: Clone + BuildHasher> fmt::Debug
for OccupiedEntryMut<'a, T, S>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
OccupiedEntryMut::Unique(ref_mut) => {
f.debug_tuple("Unique").field(ref_mut).finish()
}
OccupiedEntryMut::NonUnique { by_key1, by_key2 } => f
.debug_struct("NonUnique")
.field("by_key1", by_key1)
.field("by_key2", by_key2)
.finish(),
}
}
}
impl<'a, T: BiHashItem, S: Clone + BuildHasher> OccupiedEntryMut<'a, T, S> {
#[inline]
pub fn is_unique(&self) -> bool {
matches!(self, Self::Unique(_))
}
#[inline]
pub fn is_non_unique(&self) -> bool {
matches!(self, Self::NonUnique { .. })
}
#[inline]
pub fn as_unique(&mut self) -> Option<RefMut<'_, T, S>> {
match self {
Self::Unique(v) => Some(v.reborrow()),
Self::NonUnique { .. } => None,
}
}
#[inline]
pub fn by_key1(&mut self) -> Option<RefMut<'_, T, S>> {
match self {
Self::Unique(v) => Some(v.reborrow()),
Self::NonUnique { by_key1, .. } => {
by_key1.as_mut().map(|v| v.reborrow())
}
}
}
#[inline]
pub fn by_key2(&mut self) -> Option<RefMut<'_, T, S>> {
match self {
Self::Unique(v) => Some(v.reborrow()),
Self::NonUnique { by_key2, .. } => {
by_key2.as_mut().map(|v| v.reborrow())
}
}
}
pub fn for_each<F>(&mut self, mut f: F)
where
F: FnMut(RefMut<'_, T, S>),
{
match self {
Self::Unique(v) => f(v.reborrow()),
Self::NonUnique { by_key1, by_key2 } => {
if let Some(v) = by_key1 {
f(v.reborrow());
}
if let Some(v) = by_key2 {
f(v.reborrow());
}
}
}
}
}