use std::{collections::hash_map::RandomState, ptr::NonNull};
use crate::{
core::{Core, MapIndex, RefCount, SharedMapAccess},
loom::cell::UnsafeCell,
loom::sync::Arc,
util::unlikely,
view::sealed::ReadAccess,
Map, View,
};
pub struct ReadHandle<K, V, S = RandomState> {
core: Arc<Core<K, V, S>>,
map_access: SharedMapAccess<K, V, S>,
refcount: NonNull<RefCount>,
refcount_key: usize,
}
unsafe impl<K, V, S> Send for ReadHandle<K, V, S>
where
K: Send + Sync,
V: Send + Sync,
S: Send + Sync,
{
}
unsafe impl<K, V, S> Sync for ReadHandle<K, V, S>
where
K: Send + Sync,
V: Send + Sync,
S: Send + Sync,
{
}
impl<K, V, S> ReadHandle<K, V, S> {
pub(crate) fn new(
core: Arc<Core<K, V, S>>,
map_access: SharedMapAccess<K, V, S>,
refcount: NonNull<RefCount>,
refcount_key: usize,
) -> Self {
Self {
refcount,
map_access,
core,
refcount_key,
}
}
#[inline]
pub fn guard(&self) -> View<ReadGuard<'_, K, V, S>> {
let map_index = unsafe { self.refcount.as_ref() }.increment();
View::new(ReadGuard {
handle: self,
map: unsafe { self.map_access.get(map_index) },
map_index,
})
}
}
impl<K, V, S> Clone for ReadHandle<K, V, S> {
fn clone(&self) -> Self {
Core::new_reader(Arc::clone(&self.core))
}
}
impl<K, V, S> Drop for ReadHandle<K, V, S> {
fn drop(&mut self) {
unsafe { self.core.release_refcount(self.refcount_key) };
}
}
pub struct ReadGuard<'guard, K, V, S = RandomState> {
handle: &'guard ReadHandle<K, V, S>,
map: &'guard UnsafeCell<Map<K, V, S>>,
map_index: MapIndex,
}
unsafe impl<K, V, S> Send for ReadGuard<'_, K, V, S>
where
K: Send + Sync,
V: Send + Sync,
S: Send + Sync,
{
}
unsafe impl<K, V, S> Sync for ReadGuard<'_, K, V, S>
where
K: Send + Sync,
V: Send + Sync,
S: Send + Sync,
{
}
impl<'guard, K, V, S> ReadAccess for ReadGuard<'guard, K, V, S> {
type Map = Map<K, V, S>;
#[inline]
fn with_map<'read, F, R>(&'read self, op: F) -> R
where
F: FnOnce(&'read Self::Map) -> R,
{
self.map.with(|ptr| op(unsafe { &*ptr }))
}
}
impl<'guard, K, V, S> Drop for ReadGuard<'guard, K, V, S> {
#[inline]
fn drop(&mut self) {
let current_reader_map = unsafe { self.handle.refcount.as_ref() }.decrement();
if unlikely(current_reader_map != self.map_index) {
unsafe { self.handle.core.release_residual() };
}
}
}