use super::inner::Inner;
use std::borrow::Borrow;
use std::cell;
use fxhash::FxBuildHasher;
use std::hash::{BuildHasher, Hash};
use std::iter::{self, FromIterator};
use std::marker::PhantomData;
use std::mem;
use std::sync::atomic;
use std::sync::atomic::AtomicPtr;
use std::sync::{self, Arc};
pub struct MonoReadHandle<K, V, M = (), S = FxBuildHasher>
where
K: Eq + Hash,
S: BuildHasher,
{
pub(crate) inner: sync::Arc<AtomicPtr<Inner<K, V, M, S>>>,
pub(crate) epochs: crate::monomap::Epochs,
epoch: sync::Arc<sync::atomic::AtomicUsize>,
my_epoch: sync::atomic::AtomicUsize,
_not_sync_no_feature: PhantomData<cell::Cell<()>>,
}
pub struct MonoReadHandleFactory<K, V, M = (), S = FxBuildHasher>
where
K: Eq + Hash,
S: BuildHasher,
{
inner: sync::Arc<AtomicPtr<Inner<K, V, M, S>>>,
epochs: crate::monomap::Epochs,
}
impl<K, V, M, S> Clone for MonoReadHandleFactory<K, V, M, S>
where
K: Eq + Hash,
S: BuildHasher,
{
fn clone(&self) -> Self {
Self {
inner: sync::Arc::clone(&self.inner),
epochs: sync::Arc::clone(&self.epochs),
}
}
}
impl<K, V, M, S> MonoReadHandleFactory<K, V, M, S>
where
K: Eq + Hash,
S: BuildHasher,
{
pub fn handle(&self) -> MonoReadHandle<K, V, M, S> {
MonoReadHandle::new(
sync::Arc::clone(&self.inner),
sync::Arc::clone(&self.epochs),
)
}
}
impl<K, V, M, S> Clone for MonoReadHandle<K, V, M, S>
where
K: Eq + Hash,
S: BuildHasher,
{
fn clone(&self) -> Self {
MonoReadHandle::new(
sync::Arc::clone(&self.inner),
sync::Arc::clone(&self.epochs),
)
}
}
pub(crate) fn new<K, V, M, S>(
inner: Inner<K, V, M, S>,
epochs: crate::monomap::Epochs,
) -> MonoReadHandle<K, V, M, S>
where
K: Eq + Hash,
S: BuildHasher,
{
let store = Box::into_raw(Box::new(inner));
MonoReadHandle::new(sync::Arc::new(AtomicPtr::new(store)), epochs)
}
impl<K, V, M, S> MonoReadHandle<K, V, M, S>
where
K: Eq + Hash,
S: BuildHasher,
{
fn new(inner: sync::Arc<AtomicPtr<Inner<K, V, M, S>>>, epochs: crate::monomap::Epochs) -> Self {
let epoch = sync::Arc::new(atomic::AtomicUsize::new(0));
epochs.lock().unwrap().push(Arc::clone(&epoch));
Self {
epochs,
epoch,
my_epoch: atomic::AtomicUsize::new(0),
inner,
_not_sync_no_feature: PhantomData,
}
}
pub fn factory(&self) -> MonoReadHandleFactory<K, V, M, S> {
MonoReadHandleFactory {
inner: sync::Arc::clone(&self.inner),
epochs: sync::Arc::clone(&self.epochs),
}
}
}
impl<K, V, M, S> MonoReadHandle<K, V, M, S>
where
K: Eq + Hash,
S: BuildHasher,
M: Clone,
{
fn with_handle<F, T>(&self, f: F) -> Option<T>
where
F: FnOnce(&Inner<K, V, M, S>) -> T,
{
let epoch = self.my_epoch.fetch_add(1, atomic::Ordering::Relaxed);
self.epoch.store(epoch + 1, atomic::Ordering::Release);
atomic::fence(atomic::Ordering::SeqCst);
let r_handle = self.inner.load(atomic::Ordering::Acquire);
struct RestoreParity<'a>(&'a sync::Arc<sync::atomic::AtomicUsize>, usize);
impl<'a> Drop for RestoreParity<'a> {
fn drop(&mut self) {
self.0.store(
(self.1 + 1) | 1usize << (mem::size_of::<usize>() * 8 - 1),
atomic::Ordering::Release,
);
}
}
let _guard = RestoreParity(&self.epoch, epoch);
unsafe { r_handle.as_ref().map(f) }
}
pub fn len(&self) -> usize {
self.with_handle(|inner| inner.data.len()).unwrap_or(0)
}
pub fn is_empty(&self) -> bool {
self.with_handle(|inner| inner.data.is_empty())
.unwrap_or(true)
}
pub fn meta(&self) -> Option<M> {
self.with_handle(|inner| inner.meta.clone())
}
fn get_raw<Q: ?Sized, F, T>(&self, key: &Q, then: F) -> Option<T>
where
F: FnOnce(&V) -> T,
K: Borrow<Q>,
Q: Hash + Eq,
{
self.with_handle(move |inner| {
if !inner.is_ready() {
None
} else {
inner.data.get(key).map(then)
}
})
.unwrap_or(None)
}
#[inline]
pub fn get_and<Q: ?Sized, F, T>(&self, key: &Q, then: F) -> Option<T>
where
F: FnOnce(&V) -> T,
K: Borrow<Q>,
Q: Hash + Eq,
{
self.get_raw(key.borrow(), |value| then(&value))
}
pub fn meta_get_and<Q: ?Sized, F, T>(&self, key: &Q, then: F) -> Option<(Option<T>, M)>
where
F: FnOnce(&V) -> T,
K: Borrow<Q>,
Q: Hash + Eq,
{
self.with_handle(move |inner| {
if !inner.is_ready() {
None
} else {
let res = inner.data.get(key).map(then);
let res = (res, inner.meta.clone());
Some(res)
}
})
.unwrap_or(None)
}
pub fn is_destroyed(&self) -> bool {
self.with_handle(|_| ()).is_none()
}
pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
where
K: Borrow<Q>,
Q: Hash + Eq,
{
self.with_handle(move |inner| inner.data.contains_key(key))
.unwrap_or(false)
}
pub fn for_each<F>(&self, mut f: F)
where
F: FnMut(&K, &V),
{
self.with_handle(move |inner| {
for (k, v) in &inner.data {
f(k, v)
}
});
}
pub fn map_into<Map, Collector, Target>(&self, mut f: Map) -> Collector
where
Map: FnMut(&K, &V) -> Target,
Collector: FromIterator<Target>,
{
self.with_handle(move |inner| {
Collector::from_iter(inner.data.iter().map(|(k, v)| f(k, &v)))
})
.unwrap_or_else(|| Collector::from_iter(iter::empty()))
}
}