use std::hash::Hash;
use std::ptr::NonNull;
use std::sync::Arc;
use anyhow::Result;
use crate::collections::hashmap::iterator::Iter;
use crate::collections::hashmap::raw::RawMap;
use crate::collections::hashmap::reference::Ref;
use crate::rcu::default::RcuDefaultFlavor;
use crate::rcu::flavor::RcuFlavor;
use crate::{RcuGuard, RcuReadContext, RcuRef};
pub struct RcuHashMap<K, V, F = RcuDefaultFlavor>(RawMap<K, V, F>)
where
K: Send + 'static,
V: Send + 'static,
F: RcuFlavor + 'static;
impl<K, V, F> RcuHashMap<K, V, F>
where
K: Send,
V: Send,
F: RcuFlavor,
{
pub fn new() -> Result<Arc<Self>> {
Ok(Arc::new(Self(RawMap::new()?)))
}
pub fn insert<G>(&self, key: K, value: V, guard: &G) -> Option<Ref<K, V, F>>
where
K: Send + Eq + Hash,
V: Send,
G: RcuGuard<Flavor = F>,
{
let _ = guard;
let node = unsafe { self.0.add_replace(key, value) };
NonNull::new(node).map(Ref::new)
}
pub fn contains<G>(&self, key: &K, guard: &G) -> bool
where
K: Eq + Hash,
G: RcuGuard<Flavor = F>,
{
let _ = guard;
let mut iter = unsafe { self.0.lookup(key) };
!iter.get().is_null()
}
pub fn get<'me, 'guard, G>(&'me self, key: &K, _guard: &'guard G) -> Option<&'guard V>
where
'me: 'guard,
K: Eq + Hash,
G: RcuGuard<Flavor = F>,
{
let mut iter = unsafe { self.0.lookup(key) };
unsafe { iter.get().as_ref() }.map(|node| &node.value)
}
pub fn remove<G>(&self, key: &K, guard: &G) -> Option<Ref<K, V, F>>
where
K: Send + Eq + Hash,
V: Send,
G: RcuGuard<Flavor = F>,
{
let _ = guard;
let mut iter = unsafe { self.0.lookup(key) };
let node = match unsafe { iter.get().as_ref() } {
None => std::ptr::null_mut(),
Some(node) => {
unsafe { self.0.del(node.into()) }
}
};
NonNull::new(node).map(Ref::new)
}
pub fn iter<'me, 'guard, G>(&'me self, guard: &'guard G) -> Iter<'guard, K, V, F>
where
'me: 'guard,
G: RcuGuard<Flavor = F>,
{
let _ = guard;
Iter::new(
unsafe { self.0.iter() },
)
}
}
impl<K, V, F> Drop for RcuHashMap<K, V, F>
where
K: Send + 'static,
V: Send + 'static,
F: RcuFlavor + 'static,
{
fn drop(&mut self) {
let mut raw = self.0.clone();
F::rcu_cleanup_and_block(Box::new(move |context| {
let guard = context.rcu_read_lock();
unsafe { raw.del_all() }
.iter()
.copied()
.map(Ref::<K, V, F>::new)
.collect::<Vec<_>>()
.safe_cleanup();
drop(guard);
unsafe { raw.destroy() };
}));
}
}