use std::ffi::{c_int, c_void};
use std::hash::{DefaultHasher, Hash, Hasher};
use std::marker::PhantomData;
use std::ptr::NonNull;
use anyhow::{bail, Result};
use container_of::container_of;
use urcu_cds_sys::lfht;
use crate::rcu::flavor::RcuFlavor;
use crate::utility::{PhantomUnsend, PhantomUnsync};
fn hash_of<T: Hash>(t: &T) -> u64 {
let mut s = DefaultHasher::new();
t.hash(&mut s);
s.finish()
}
unsafe extern "C" fn key_eq<K, V>(handle_ptr: *mut lfht::Node, key_ptr: *const c_void) -> c_int
where
K: Eq,
{
let node = unsafe { RawNode::<K, V>::from_handle(handle_ptr).as_ref_unchecked() };
let key = unsafe { (key_ptr as *const K).as_ref_unchecked() };
if &node.key == key {
1
} else {
0
}
}
pub struct RawNodeHandle {
handle: *mut lfht::Node,
key: *const c_void,
key_hash: u64,
}
pub struct RawNode<K, V> {
handle: lfht::Node,
pub(crate) key: K,
pub(crate) value: V,
}
impl<K, V> RawNode<K, V> {
fn new(key: K, value: V) -> Box<Self> {
let mut node = Box::new(Self {
key,
value,
handle: lfht::Node::default(),
});
unsafe { lfht::node_init(&mut node.handle) };
node
}
fn to_handle(self: Box<Self>) -> RawNodeHandle
where
K: Hash,
{
let node = Box::into_raw(self);
let node = unsafe { node.as_mut_unchecked() };
RawNodeHandle {
handle: &mut node.handle,
key: &node.key as *const K as *const c_void,
key_hash: hash_of(&node.key),
}
}
unsafe fn from_handle(handle: *mut lfht::Node) -> *mut Self {
container_of!(handle, Self, handle)
}
pub fn as_refs(&self) -> (&K, &V) {
(&self.key, &self.value)
}
}
pub struct RawIter<'a, K, V, F> {
handle: lfht::Iter,
map: &'a RawMap<K, V, F>,
_unsend: PhantomUnsend<(K, V, F)>,
_unsync: PhantomUnsync<(K, V, F)>,
}
impl<'a, K, V, F> RawIter<'a, K, V, F> {
fn new<I>(map: &'a RawMap<K, V, F>, init: I) -> Self
where
I: FnOnce(*mut lfht::Iter),
{
let mut iterator = Self {
map,
handle: Default::default(),
_unsend: PhantomData,
_unsync: PhantomData,
};
init(&mut iterator.handle);
iterator
}
pub fn get(&mut self) -> *mut RawNode<K, V> {
let node = unsafe { lfht::iter_get_node(&mut self.handle) };
if node.is_null() {
std::ptr::null_mut()
} else {
unsafe { RawNode::<K, V>::from_handle(node) }
}
}
pub fn next(&mut self) {
unsafe { lfht::next(self.map.handle, &mut self.handle) }
}
pub fn del(&mut self) -> *mut RawNode<K, V> {
let node = unsafe { lfht::iter_get_node(&mut self.handle) };
unsafe {
if lfht::del(self.map.handle, node) < 0 {
std::ptr::null_mut()
} else {
RawNode::from_handle(node)
}
}
}
}
pub struct RawMap<K, V, F> {
handle: *mut lfht::Handle,
_unsend: PhantomUnsend<(K, V, F)>,
_unsync: PhantomUnsync<(K, V, F)>,
}
impl<K, V, F> RawMap<K, V, F> {
const INIT_FLAGS: i32 = (lfht::ACCOUNTING | lfht::AUTO_RESIZE) as i32;
const INIT_SIZE: u64 = 1;
const MIN_NR_ALLOC_BUCKETS: u64 = 1;
const MAX_NR_BUCKETS: u64 = 0;
pub fn new() -> Result<Self>
where
F: RcuFlavor,
{
let handle = unsafe {
lfht::new_flavor(
Self::INIT_SIZE,
Self::MIN_NR_ALLOC_BUCKETS,
Self::MAX_NR_BUCKETS,
Self::INIT_FLAGS,
F::unchecked_rcu_api(),
std::ptr::null_mut(),
)
};
if handle.is_null() {
bail!("failed to allocate RCU hash table");
}
Ok(Self {
handle,
_unsend: PhantomData,
_unsync: PhantomData,
})
}
pub unsafe fn add_replace(&self, key: K, value: V) -> *mut RawNode<K, V>
where
K: Eq + Hash,
{
let node = RawNode::new(key, value).to_handle();
let node = unsafe {
lfht::add_replace(
self.handle,
node.key_hash,
Some(key_eq::<K, V>),
node.key,
node.handle,
)
};
if node.is_null() {
std::ptr::null_mut()
} else {
RawNode::from_handle(node)
}
}
pub unsafe fn lookup(&self, key: &K) -> RawIter<K, V, F>
where
K: Eq + Hash,
{
RawIter::new(self, |iter| {
unsafe {
lfht::lookup(
self.handle,
hash_of(key),
Some(key_eq::<K, V>),
key as *const K as *const c_void,
iter,
);
}
})
}
pub unsafe fn iter(&self) -> RawIter<K, V, F> {
RawIter::new(self, |iter| {
unsafe { lfht::first(self.handle, iter) }
})
}
pub unsafe fn del(&self, mut node: NonNull<RawNode<K, V>>) -> *mut RawNode<K, V> {
unsafe {
if lfht::del(self.handle, &mut node.as_mut().handle) < 0 {
std::ptr::null_mut()
} else {
node.as_mut()
}
}
}
pub unsafe fn del_all(&self) -> Vec<NonNull<RawNode<K, V>>> {
let mut iter = self.iter();
let mut refs = Vec::new();
loop {
if iter.get().is_null() {
break;
}
NonNull::new(iter.del())
.iter()
.copied()
.for_each(|node| refs.push(node));
iter.next();
}
refs
}
pub fn clone(&mut self) -> Self {
Self {
handle: self.handle,
_unsend: PhantomData,
_unsync: PhantomData,
}
}
pub unsafe fn destroy(&mut self) {
unsafe { lfht::destroy(self.handle, std::ptr::null_mut()) };
}
}
unsafe impl<K, V, F> Send for RawMap<K, V, F>
where
K: Send,
V: Send,
{
}
unsafe impl<K, V, F> Sync for RawMap<K, V, F>
where
K: Sync,
V: Sync,
{
}