use ahash::RandomState;
use dashmap::DashMap;
use elysees::Arc;
use std::borrow::Borrow;
use std::fmt::{self, Debug, Formatter};
use std::hash::{BuildHasher, Hash};
pub mod arr;
pub trait CanCollect {
#[inline(always)]
fn can_collect(&self) -> bool {
false
}
#[inline(always)]
fn can_collect_clone(&self) -> bool {
self.can_collect()
}
}
pub trait Caches<T: ?Sized>: Hash + Eq + Clone + CanCollect {
fn cached(&self) -> &T;
}
pub trait GlobalCache {
type Entry;
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
fn cache<Q>(&self, value: Q) -> Self::Entry
where
Self::Entry: Borrow<Q>,
Q: Into<Self::Entry> + Hash + Eq;
#[inline(always)]
fn gc(&self) -> usize {
0
}
#[inline(always)]
fn try_gc(&self, _key: &mut Self::Entry) -> Option<Self::Entry> {
None
}
}
pub struct DashCache<C, S = RandomState> {
cache: DashMap<C, (), S>,
}
impl<C: Hash + Eq> DashCache<C> {
#[inline]
pub fn new() -> DashCache<C> {
DashCache::default()
}
}
impl<C: Hash + Eq, S: BuildHasher + Clone + Default> Default for DashCache<C, S> {
#[inline]
fn default() -> DashCache<C, S> {
DashCache {
cache: DashMap::default(),
}
}
}
impl<C, S> From<DashMap<C, (), S>> for DashCache<C, S> {
#[inline]
fn from(cache: DashMap<C, (), S>) -> DashCache<C, S> {
DashCache { cache }
}
}
impl<C, S> Debug for DashCache<C, S>
where
C: Debug + Hash + Eq,
S: BuildHasher + Clone,
{
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
fmt.debug_struct("DashCache")
.field("cache", &self.cache)
.finish()
}
}
impl<C, S> GlobalCache for DashCache<C, S>
where
S: BuildHasher + Clone,
C: Hash + Eq + Clone + CanCollect,
{
type Entry = C;
#[inline]
fn cache<Q>(&self, value: Q) -> C
where
C: Borrow<Q>,
Q: Into<C> + Hash + Eq,
{
if let Some(cached) = self.cache.get(&value) {
return cached.key().clone();
}
self.cache.entry(value.into()).or_default().key().clone()
}
#[inline]
fn gc(&self) -> usize {
let mut collected = 0;
self.cache.retain(|arc, _| {
if arc.can_collect() {
collected += 1;
false
} else {
true
}
});
collected
}
#[inline]
fn try_gc(&self, key: &mut Self::Entry) -> Option<Self::Entry> {
if key.can_collect_clone() {
return self.cache.remove(key).map(|(key, _)| key);
}
None
}
#[inline]
fn len(&self) -> usize {
self.cache.len()
}
#[inline]
fn is_empty(&self) -> bool {
self.cache.is_empty()
}
}
impl<T: ?Sized> CanCollect for Arc<T> {
#[inline]
fn can_collect(&self) -> bool {
self.is_unique()
}
#[inline(always)]
fn can_collect_clone(&self) -> bool {
Arc::count(self, std::sync::atomic::Ordering::Acquire) <= 2
}
}
impl<T: Hash + Eq + ?Sized> Caches<T> for Arc<T> {
#[inline]
fn cached(&self) -> &T {
self
}
}
impl<T: ?Sized> CanCollect for std::sync::Arc<T> {
#[inline]
fn can_collect(&self) -> bool {
std::sync::Arc::strong_count(self) == 1
}
#[inline(always)]
fn can_collect_clone(&self) -> bool {
std::sync::Arc::strong_count(self) <= 2
}
}
impl<T: Hash + Eq + ?Sized> Caches<T> for std::sync::Arc<T> {
#[inline]
fn cached(&self) -> &T {
self
}
}
impl<T: ?Sized> CanCollect for std::rc::Rc<T> {
#[inline]
fn can_collect(&self) -> bool {
std::rc::Rc::strong_count(self) == 1
}
#[inline(always)]
fn can_collect_clone(&self) -> bool {
std::rc::Rc::strong_count(self) <= 2
}
}
impl<T: Hash + Eq + ?Sized> Caches<T> for std::rc::Rc<T> {
#[inline]
fn cached(&self) -> &T {
self
}
}