1use dashmap::{DashMap, mapref::entry::Entry};
5use ahash::AHasher;
6use std::hash::{Hash, Hasher, BuildHasherDefault};
7use std::convert::Infallible;
8use either::Either;
9use super::node::{WeakNode, Node, Data};
10use crate::util::PassThroughHasher;
11use crate::value::{ValueDesc, ValueData, ValId};
12
13pub trait CacheType<T> {
15 type UnderlyingMap;
17}
18
19#[derive(Debug, Copy, Clone, Eq, PartialEq)]
21pub struct GlobalCache;
22
23impl<T> CacheType<T> for GlobalCache {
24 type UnderlyingMap = DashMap<u64, WeakNode<T>, BuildHasherDefault<PassThroughHasher>>;
25}
26
27#[derive(Debug, Clone)]
29pub struct NodeCache<T, C: CacheType<T> = GlobalCache> {
30 pub map: C::UnderlyingMap,
32 pub keys: (u64, u64)
34}
35
36pub type CacheEntry<'a, T> =
38 Entry<'a, u64, WeakNode<T>, BuildHasherDefault<PassThroughHasher>>;
39
40pub trait CacheAcceptor<T> {
42 fn accept(self, weak: WeakNode<T>);
44}
45
46impl<'a, T> CacheAcceptor<T> for CacheEntry<'a, T> {
47 fn accept(self, weak: WeakNode<T>) {
48 *(self.or_default()) = weak;
49 }
50}
51
52impl<T> CacheAcceptor<T> for () {
53 fn accept(self, _weak: WeakNode<T>) {}
54}
55
56impl<T> NodeCache<T, GlobalCache> {
57 pub fn with_keys(keys: (u64, u64)) -> NodeCache<T> {
59 NodeCache { map: DashMap::default(), keys }
60 }
61 pub fn new() -> NodeCache<T> { Self::with_keys((0, 0)) }
63 pub fn cached_entry<'a, K>(&'a self, key: &K) -> Either<Node<T>, CacheEntry<'a, T>>
67 where K: Hash {
68 let hash = {
69 let mut hasher = AHasher::new_with_keys(self.keys.0, self.keys.1);
70 key.hash(&mut hasher);
71 hasher.finish()
72 };
73 let entry = self.map.entry(hash);
74 if let Entry::Occupied(occupied) = &entry {
75 if let Some(node) = occupied.get().upgrade() {
76 return Either::Left(node)
77 }
78 }
79 Either::Right(entry)
80 }
81 pub fn cached_constructor<D, E, F>(&self, data: D, constructor: F) -> Result<Node<T>, E>
85 where D: Hash, F: FnOnce(D) -> Result<Node<T>, E> {
86 let entry = match self.cached_entry(&data) {
87 Either::Left(node) => return Ok(node),
88 Either::Right(entry) => entry
89 };
90 let node = constructor(data)?;
91 *(entry.or_default()) = node.downgrade();
92 Ok(node)
93 }
94 pub fn remove<K>(&self, key: &K) -> Option<(u64, WeakNode<T>)> where K: Hash {
96 let mut hasher = AHasher::new_with_keys(self.keys.0, self.keys.1);
97 key.hash(&mut hasher);
98 let cache_key = hasher.finish();
99 self.map.remove(&cache_key)
100 }
101 #[inline(always)] pub fn cached_desc<D>(&self, desc: D) -> Result<Node<T>, T::CacheError>
105 where D: Hash, T: CacheBy<D> {
106 self.cached_constructor(desc, T::node_to_cache)
107 }
108}
109
110pub trait CacheBy<K: Hash> {
112 type CacheError;
114 fn node_to_cache(key: K) -> Result<Node<Self>, Self::CacheError>;
116}
117
118impl<V> CacheBy<V> for ValueData where V: ValueDesc + Hash {
119 type CacheError = V::Err;
120 #[inline(always)] fn node_to_cache(key: V) -> Result<ValId, V::Err> { key.to_node() }
121}
122
123impl<T: Hash> CacheBy<Data<T>> for Data<T> {
124 type CacheError = Infallible;
125 #[inline(always)] fn node_to_cache(key: Data<T>) -> Result<Node<Data<T>>, Infallible> {
126 Ok(Node::new(key))
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use crate::util::AlwaysOk;
133 use super::*;
134
135 #[test]
136 fn bools_cache_properly() {
137 let cache = NodeCache::<Data<bool>>::new();
138 let dt = Data(true);
139 let df = Data(false);
140 let nt = cache.cached_desc(dt).aok();
141 let pass = cache.cached_constructor(Data(true), |_| Err(()))
142 .expect("Valid key, should not generate");
143 assert_eq!(nt, pass);
144 cache.cached_constructor(Data(false), |_| Err(()))
145 .expect_err("Invalid key, generator always errors");
146 let nf = cache.cached_desc(df).aok();
147 let pass = cache.cached_constructor(Data(false), |_| Err(()))
148 .expect("Valid key, should not generate");
149 assert_eq!(nf, pass);
150 let nt2 = cache.cached_desc(dt).aok();
151 let nf2 = cache.cached_desc(df).aok();
152 assert_eq!(nt, nt2);
153 assert_eq!(nf, nf2);
154 assert_ne!(nt, nf);
155 let mnt = Node::new(dt);
156 let mnf = Node::new(df);
157 assert_ne!(nt, mnt);
158 assert_ne!(nf, mnt);
159 assert_ne!(nt, mnf);
160 assert_ne!(nf, mnf);
161 let (_hash, ntr) = cache.remove(&dt).expect("Data(true) was previously inserted");
162 assert_eq!(ntr.upgrade().expect("We hold a reference to Data(true)"), nt);
163 let nt3 = cache.cached_desc(dt).expect("Valid key");
164 let nf3 = cache.cached_desc(df).expect("Valid key");
165 assert_ne!(nt, nt3);
166 assert_eq!(nf, nf3);
167 }
168}