use inner::Inner;
use std::borrow::Borrow;
use std::cell;
use std::collections::hash_map::RandomState;
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 ReadHandle<K, V, M = (), S = RandomState>
where
K: Eq + Hash,
S: BuildHasher,
{
pub(crate) inner: sync::Arc<AtomicPtr<Inner<K, V, M, S>>>,
epoch: sync::Arc<sync::atomic::AtomicUsize>,
my_epoch: sync::atomic::AtomicUsize,
_not_sync_no_feature: PhantomData<cell::Cell<()>>,
}
impl<K, V, M, S> Clone for ReadHandle<K, V, M, S>
where
K: Eq + Hash,
S: BuildHasher,
M: Clone,
{
fn clone(&self) -> Self {
let epoch = sync::Arc::new(atomic::AtomicUsize::new(0));
self.register_epoch(&epoch);
ReadHandle {
epoch: epoch,
my_epoch: atomic::AtomicUsize::new(0),
inner: sync::Arc::clone(&self.inner),
_not_sync_no_feature: PhantomData,
}
}
}
pub(crate) fn new<K, V, M, S>(inner: Inner<K, V, M, S>) -> ReadHandle<K, V, M, S>
where
K: Eq + Hash,
S: BuildHasher,
{
let epoch = sync::Arc::new(atomic::AtomicUsize::new(0));
inner.epochs.lock().unwrap().push(Arc::clone(&epoch));
let store = Box::into_raw(Box::new(inner));
ReadHandle {
epoch: epoch,
my_epoch: atomic::AtomicUsize::new(0),
inner: sync::Arc::new(AtomicPtr::new(store)),
_not_sync_no_feature: PhantomData,
}
}
impl<K, V, M, S> ReadHandle<K, V, M, S>
where
K: Eq + Hash,
S: BuildHasher,
M: Clone,
{
fn register_epoch(&self, epoch: &Arc<atomic::AtomicUsize>) {
if let Some(epochs) = self.with_handle(|inner| Arc::clone(&inner.epochs)) {
epochs.lock().unwrap().push(Arc::clone(epoch));
}
}
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);
let res = unsafe { r_handle.as_ref().map(f) };
self.epoch.store(
(epoch + 1) | 1usize << (mem::size_of::<usize>() * 8 - 1),
atomic::Ordering::Release,
);
res
}
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())
}
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.with_handle(move |inner| {
if !inner.is_ready() {
None
} else {
inner.data.get(key).map(move |v| then(&**v))
}
})
.unwrap_or(None)
}
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(move |v| then(&**v));
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, vs) in &inner.data {
f(k, &vs[..])
}
});
}
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, vs)| f(k, &vs[..])))
})
.unwrap_or_else(|| Collector::from_iter(iter::empty()))
}
}