use core::hash::Hash;
use hashbrown::hash_table;
use crate::Ptr;
use crate::arena::ActiveSlotRef;
use crate::arena::Arena;
use crate::arena::FreedSlot;
use crate::linked_hash_map::HeadTail;
pub enum Entry<'a, K, V> {
Occupied(OccupiedEntry<'a, K, V>),
Vacant(VacantEntry<'a, K, V>),
}
impl<'a, K, V> Entry<'a, K, V>
where
K: Hash + Eq,
{
pub fn or_insert(self, default: V) -> &'a mut V {
match self {
Entry::Occupied(e) => e.into_mut(),
Entry::Vacant(v) => v.insert_tail(default).1,
}
}
pub fn and_modify<F>(self, f: F) -> Self
where
F: FnOnce(&mut V),
{
if let Entry::Occupied(mut e) = self {
f(e.get_mut());
Entry::Occupied(e)
} else {
self
}
}
}
pub struct OccupiedEntry<'a, K, T> {
pub(crate) entry: hash_table::OccupiedEntry<'a, ActiveSlotRef<K, T>>,
pub(crate) head_tail: &'a mut Option<HeadTail<K, T>>,
pub(crate) arena: &'a mut Arena<K, T>,
}
impl<'a, K, T> OccupiedEntry<'a, K, T> {
pub fn get(&self) -> &T {
&self.entry.get().data(self.arena).value
}
pub fn get_mut(&mut self) -> &mut T {
&mut self.entry.get_mut().data_mut(self.arena).value
}
pub fn into_mut(self) -> &'a mut T {
let OccupiedEntry { entry, .. } = self;
&mut entry.into_mut().data_mut(self.arena).value
}
pub fn insert_no_move(mut self, value: T) -> T {
core::mem::replace(&mut self.entry.get_mut().data_mut(self.arena).value, value)
}
pub fn ptr(&self) -> Ptr {
self.entry.get().this(self.arena)
}
pub fn key(&self) -> &K {
&self.entry.get().data(self.arena).key
}
pub fn insert(self, value: T) -> T {
self.insert_no_move(value)
}
pub fn remove_entry(self) -> (K, T) {
let entry = self.entry.remove().0;
let FreedSlot {
data, prev_next, ..
} = unsafe { self.arena.free_and_unlink(entry) };
if let Some((prev, next)) = prev_next {
if let Some(head_tail) = self.head_tail {
if head_tail.head == entry {
head_tail.head = next;
}
if head_tail.tail == entry {
head_tail.tail = prev;
}
}
} else if self
.head_tail
.as_ref()
.is_some_and(|ht| ht.head == entry || ht.tail == entry)
{
*self.head_tail = None;
}
(data.key, data.value)
}
pub fn remove(self) -> T {
self.remove_entry().1
}
}
pub struct VacantEntry<'a, K, T> {
pub(crate) key: K,
pub(crate) entry: hash_table::VacantEntry<'a, ActiveSlotRef<K, T>>,
pub(crate) nodes: &'a mut Arena<K, T>,
pub(crate) head_tail: &'a mut Option<HeadTail<K, T>>,
}
impl<'a, K: Hash + Eq, T> VacantEntry<'a, K, T> {
pub fn insert_tail(self, value: T) -> (Ptr, &'a mut T) {
let after = self.head_tail.as_ref().map(|ht| ht.tail);
let (_, ptr, data) = self.insert_after_internal(value, after);
(ptr, data)
}
pub fn insert_unlinked(self, value: T) -> (Ptr, &'a mut T) {
let mut ptr = self.nodes.alloc_circular(self.key, value);
self.entry.insert(ptr);
(ptr.this(self.nodes), &mut ptr.data_mut(self.nodes).value)
}
pub fn insert_after(self, value: T, after: Ptr) -> (Ptr, &'a mut T) {
let after = self
.nodes
.map_ptr(after)
.or(self.head_tail.as_ref().map(|ht| ht.tail));
let (_, ptr, data) = self.insert_after_internal(value, after);
(ptr, data)
}
pub(crate) fn insert_after_internal(
self,
value: T,
after: Option<ActiveSlotRef<K, T>>,
) -> (ActiveSlotRef<K, T>, Ptr, &'a mut T) {
if let Some(mut after) = after {
let mut after_next = after.next(self.nodes);
let mut ptr = self.nodes.alloc(self.key, value, after, after_next);
*after.next_mut(self.nodes) = ptr;
*after_next.prev_mut(self.nodes) = ptr;
self.entry.insert(ptr);
if let Some(head_tail) = self.head_tail.as_mut()
&& head_tail.tail == after
{
head_tail.tail = ptr;
}
(
ptr,
ptr.this(self.nodes),
&mut ptr.data_mut(self.nodes).value,
)
} else {
debug_assert_eq!(*self.head_tail, None);
let mut ptr = self.nodes.alloc_circular(self.key, value);
*self.head_tail = Some(HeadTail {
head: ptr,
tail: ptr,
});
self.entry.insert(ptr);
(
ptr,
ptr.this(self.nodes),
&mut ptr.data_mut(self.nodes).value,
)
}
}
pub fn insert_head(self, value: T) -> (Ptr, &'a mut T) {
let ptr = self.head_tail.as_ref().map(|ht| ht.head);
let (_, ptr, data) = self.insert_before_internal(value, ptr);
(ptr, data)
}
pub fn insert_before(self, value: T, before: Ptr) -> (Ptr, &'a mut T) {
let before = self
.nodes
.map_ptr(before)
.or(self.head_tail.as_ref().map(|ht| ht.head));
let (_, ptr, data) = self.insert_before_internal(value, before);
(ptr, data)
}
pub(crate) fn insert_before_internal(
self,
value: T,
before: Option<ActiveSlotRef<K, T>>,
) -> (ActiveSlotRef<K, T>, Ptr, &'a mut T) {
if let Some(mut before) = before {
let mut before_prev = before.prev(self.nodes);
let mut ptr = self.nodes.alloc(self.key, value, before_prev, before);
*before.prev_mut(self.nodes) = ptr;
*before_prev.next_mut(self.nodes) = ptr;
self.entry.insert(ptr);
if let Some(head_tail) = self.head_tail.as_mut()
&& head_tail.head == before
{
head_tail.head = ptr;
}
(
ptr,
ptr.this(self.nodes),
&mut ptr.data_mut(self.nodes).value,
)
} else {
debug_assert_eq!(*self.head_tail, None);
let mut ptr = self.nodes.alloc_circular(self.key, value);
*self.head_tail = Some(HeadTail {
head: ptr,
tail: ptr,
});
self.entry.insert(ptr);
(
ptr,
ptr.this(self.nodes),
&mut ptr.data_mut(self.nodes).value,
)
}
}
pub fn into_key(self) -> K {
self.key
}
pub fn key(&self) -> &K {
&self.key
}
}