1use super::Cached;
2
3use std::cmp::Eq;
4use std::hash::Hash;
5
6#[cfg(feature = "ahash")]
7use hashbrown::{hash_map::Entry, HashMap};
8
9#[cfg(not(feature = "ahash"))]
10use std::collections::{hash_map::Entry, HashMap};
11
12#[cfg(feature = "async")]
13use {super::CachedAsync, async_trait::async_trait, futures::Future};
14
15#[derive(Clone, Debug)]
21pub struct UnboundCache<K, V> {
22 pub(super) store: HashMap<K, V>,
23 pub(super) hits: u64,
24 pub(super) misses: u64,
25 pub(super) initial_capacity: Option<usize>,
26}
27
28impl<K, V> PartialEq for UnboundCache<K, V>
29where
30 K: Eq + Hash,
31 V: PartialEq,
32{
33 fn eq(&self, other: &UnboundCache<K, V>) -> bool {
34 self.store.eq(&other.store)
35 }
36}
37
38impl<K, V> Eq for UnboundCache<K, V>
39where
40 K: Eq + Hash,
41 V: PartialEq,
42{
43}
44
45impl<K: Hash + Eq, V> UnboundCache<K, V> {
46 #[allow(clippy::new_without_default)]
48 #[must_use]
49 pub fn new() -> UnboundCache<K, V> {
50 UnboundCache {
51 store: Self::new_store(None),
52 hits: 0,
53 misses: 0,
54 initial_capacity: None,
55 }
56 }
57
58 #[must_use]
60 pub fn with_capacity(size: usize) -> UnboundCache<K, V> {
61 UnboundCache {
62 store: Self::new_store(Some(size)),
63 hits: 0,
64 misses: 0,
65 initial_capacity: Some(size),
66 }
67 }
68
69 fn new_store(capacity: Option<usize>) -> HashMap<K, V> {
70 capacity.map_or_else(HashMap::new, HashMap::with_capacity)
71 }
72
73 #[must_use]
75 pub fn get_store(&self) -> &HashMap<K, V> {
76 &self.store
77 }
78}
79
80impl<K: Hash + Eq, V> Cached<K, V> for UnboundCache<K, V> {
81 fn cache_get<Q>(&mut self, key: &Q) -> Option<&V>
82 where
83 K: std::borrow::Borrow<Q>,
84 Q: std::hash::Hash + Eq + ?Sized,
85 {
86 if let Some(v) = self.store.get(key) {
87 self.hits += 1;
88 Some(v)
89 } else {
90 self.misses += 1;
91 None
92 }
93 }
94 fn cache_get_mut<Q>(&mut self, key: &Q) -> std::option::Option<&mut V>
95 where
96 K: std::borrow::Borrow<Q>,
97 Q: std::hash::Hash + Eq + ?Sized,
98 {
99 if let Some(v) = self.store.get_mut(key) {
100 self.hits += 1;
101 Some(v)
102 } else {
103 self.misses += 1;
104 None
105 }
106 }
107 fn cache_set(&mut self, key: K, val: V) -> Option<V> {
108 self.store.insert(key, val)
109 }
110 fn cache_get_or_set_with<F: FnOnce() -> V>(&mut self, key: K, f: F) -> &mut V {
111 match self.store.entry(key) {
112 Entry::Occupied(occupied) => {
113 self.hits += 1;
114 occupied.into_mut()
115 }
116
117 Entry::Vacant(vacant) => {
118 self.misses += 1;
119 vacant.insert(f())
120 }
121 }
122 }
123 fn cache_try_get_or_set_with<F: FnOnce() -> Result<V, E>, E>(
124 &mut self,
125 k: K,
126 f: F,
127 ) -> Result<&mut V, E> {
128 match self.store.entry(k) {
129 Entry::Occupied(occupied) => {
130 self.hits += 1;
131 Ok(occupied.into_mut())
132 }
133
134 Entry::Vacant(vacant) => {
135 self.misses += 1;
136 Ok(vacant.insert(f()?))
137 }
138 }
139 }
140 fn cache_remove<Q>(&mut self, k: &Q) -> Option<V>
141 where
142 K: std::borrow::Borrow<Q>,
143 Q: std::hash::Hash + Eq + ?Sized,
144 {
145 self.store.remove(k)
146 }
147 fn cache_clear(&mut self) {
148 self.store.clear();
149 }
150 fn cache_reset(&mut self) {
151 self.store = Self::new_store(self.initial_capacity);
152 }
153 fn cache_reset_metrics(&mut self) {
154 self.misses = 0;
155 self.hits = 0;
156 }
157 fn cache_size(&self) -> usize {
158 self.store.len()
159 }
160 fn cache_hits(&self) -> Option<u64> {
161 Some(self.hits)
162 }
163 fn cache_misses(&self) -> Option<u64> {
164 Some(self.misses)
165 }
166}
167
168#[cfg(feature = "async")]
169#[async_trait]
170impl<K, V> CachedAsync<K, V> for UnboundCache<K, V>
171where
172 K: Hash + Eq + Clone + Send,
173{
174 async fn get_or_set_with<F, Fut>(&mut self, key: K, f: F) -> &mut V
175 where
176 V: Send,
177 F: FnOnce() -> Fut + Send,
178 Fut: Future<Output = V> + Send,
179 {
180 match self.store.entry(key) {
181 Entry::Occupied(occupied) => {
182 self.hits += 1;
183 occupied.into_mut()
184 }
185
186 Entry::Vacant(vacant) => {
187 self.misses += 1;
188 vacant.insert(f().await)
189 }
190 }
191 }
192
193 async fn try_get_or_set_with<F, Fut, E>(&mut self, key: K, f: F) -> Result<&mut V, E>
194 where
195 V: Send,
196 F: FnOnce() -> Fut + Send,
197 Fut: Future<Output = Result<V, E>> + Send,
198 {
199 let v = match self.store.entry(key) {
200 Entry::Occupied(occupied) => {
201 self.hits += 1;
202 occupied.into_mut()
203 }
204
205 Entry::Vacant(vacant) => {
206 self.misses += 1;
207 vacant.insert(f().await?)
208 }
209 };
210 Ok(v)
211 }
212}
213
214#[cfg(test)]
215mod tests {
217 use super::*;
218
219 #[test]
220 fn basic_cache() {
221 let mut c = UnboundCache::new();
222 assert!(c.cache_get(&1).is_none());
223 let misses = c.cache_misses().unwrap();
224 assert_eq!(1, misses);
225
226 assert_eq!(c.cache_set(1, 100), None);
227 assert!(c.cache_get(&1).is_some());
228 let hits = c.cache_hits().unwrap();
229 let misses = c.cache_misses().unwrap();
230 assert_eq!(1, hits);
231 assert_eq!(1, misses);
232 }
233
234 #[test]
235 fn clear() {
236 let mut c = UnboundCache::new();
237
238 assert_eq!(c.cache_set(1, 100), None);
239 assert_eq!(c.cache_set(2, 200), None);
240 assert_eq!(c.cache_set(3, 300), None);
241
242 c.cache_get(&1);
244 c.cache_get(&2);
245 c.cache_get(&3);
246 c.cache_get(&10);
247 c.cache_get(&20);
248 c.cache_get(&30);
249
250 assert_eq!(3, c.cache_size());
251 assert_eq!(3, c.cache_hits().unwrap());
252 assert_eq!(3, c.cache_misses().unwrap());
253 assert!(3 <= c.store.capacity());
254
255 c.cache_clear();
258
259 assert_eq!(0, c.cache_size());
260 assert_eq!(3, c.cache_hits().unwrap());
261 assert_eq!(3, c.cache_misses().unwrap());
262 assert!(3 <= c.store.capacity()); let capacity = 1;
265 let mut c = UnboundCache::with_capacity(capacity);
266 assert!(capacity <= c.store.capacity());
267
268 assert_eq!(c.cache_set(1, 100), None);
269 assert_eq!(c.cache_set(2, 200), None);
270 assert_eq!(c.cache_set(3, 300), None);
271
272 assert!(3 <= c.store.capacity());
273
274 c.cache_clear();
275
276 assert!(3 <= c.store.capacity()); }
278
279 #[test]
280 fn reset() {
281 let mut c = UnboundCache::new();
282 assert_eq!(c.cache_set(1, 100), None);
283 assert_eq!(c.cache_set(2, 200), None);
284 assert_eq!(c.cache_set(3, 300), None);
285 assert!(3 <= c.store.capacity());
286
287 c.cache_reset();
288
289 assert_eq!(0, c.store.capacity());
290
291 let init_capacity = 1;
292 let mut c = UnboundCache::with_capacity(init_capacity);
293 assert_eq!(c.cache_set(1, 100), None);
294 assert_eq!(c.cache_set(2, 200), None);
295 assert_eq!(c.cache_set(3, 300), None);
296 assert!(3 <= c.store.capacity());
297
298 c.cache_reset();
299
300 assert!(init_capacity <= c.store.capacity());
301 }
302
303 #[test]
304 fn remove() {
305 let mut c = UnboundCache::new();
306
307 assert_eq!(c.cache_set(1, 100), None);
308 assert_eq!(c.cache_set(2, 200), None);
309 assert_eq!(c.cache_set(3, 300), None);
310
311 c.cache_get(&1);
313 c.cache_get(&2);
314 c.cache_get(&3);
315 c.cache_get(&10);
316 c.cache_get(&20);
317 c.cache_get(&30);
318
319 assert_eq!(3, c.cache_size());
320 assert_eq!(3, c.cache_hits().unwrap());
321 assert_eq!(3, c.cache_misses().unwrap());
322
323 assert_eq!(Some(100), c.cache_remove(&1));
326
327 assert_eq!(2, c.cache_size());
328 assert_eq!(3, c.cache_hits().unwrap());
329 assert_eq!(3, c.cache_misses().unwrap());
330
331 assert_eq!(Some(200), c.cache_remove(&2));
332
333 assert_eq!(1, c.cache_size());
334
335 assert_eq!(None, c.cache_remove(&2));
337
338 assert_eq!(1, c.cache_size());
339 }
340
341 #[test]
342 fn get_or_set_with() {
343 let mut c = UnboundCache::new();
344
345 assert_eq!(c.cache_get_or_set_with(0, || 0), &0);
346 assert_eq!(c.cache_get_or_set_with(1, || 1), &1);
347 assert_eq!(c.cache_get_or_set_with(2, || 2), &2);
348 assert_eq!(c.cache_get_or_set_with(3, || 3), &3);
349 assert_eq!(c.cache_get_or_set_with(4, || 4), &4);
350 assert_eq!(c.cache_get_or_set_with(5, || 5), &5);
351
352 assert_eq!(c.cache_misses(), Some(6));
353
354 assert_eq!(c.cache_get_or_set_with(0, || 0), &0);
355
356 assert_eq!(c.cache_misses(), Some(6));
357
358 assert_eq!(c.cache_get_or_set_with(0, || 42), &0);
359
360 assert_eq!(c.cache_misses(), Some(6));
361
362 assert_eq!(c.cache_get_or_set_with(1, || 1), &1);
363
364 assert_eq!(c.cache_misses(), Some(6));
365
366 c.cache_reset();
367 fn _try_get(n: usize) -> Result<usize, String> {
368 if n < 10 {
369 Ok(n)
370 } else {
371 Err("dead".to_string())
372 }
373 }
374 let res: Result<&mut usize, String> = c.cache_try_get_or_set_with(0, || _try_get(10));
375 assert!(res.is_err());
376
377 let res: Result<&mut usize, String> = c.cache_try_get_or_set_with(0, || _try_get(1));
378 assert_eq!(res.unwrap(), &1);
379 let res: Result<&mut usize, String> = c.cache_try_get_or_set_with(0, || _try_get(5));
380 assert_eq!(res.unwrap(), &1);
381 }
382}