1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#[cfg(feature = "concurrent_hash_map")]
pub mod chashmap;
pub mod rw_lock;
use crate::FnMemo;
use once_cell::sync::OnceCell;
use recur_fn::RecurFn;
use std::sync::Arc;
pub trait Cache {
type Arg;
type Output;
fn new() -> Self;
fn get(&self, arg: &Self::Arg) -> Option<Arc<OnceCell<Self::Output>>>;
fn get_or_new(&self, arg: Self::Arg) -> Arc<OnceCell<Self::Output>>;
fn clear(&self);
}
pub struct Memo<C, F> {
cache: C,
f: F,
}
impl<C: Cache, F> Memo<C, F> {
pub fn new(f: F) -> Self {
Memo { cache: C::new(), f }
}
}
impl<C: Cache, F: RecurFn<C::Arg, C::Output>> FnMemo<C::Arg, C::Output> for Memo<C, F>
where
C::Arg: Clone,
C::Output: Clone,
{
fn call(&self, arg: C::Arg) -> C::Output {
self.cache
.get(&arg)
.unwrap_or_else(|| self.cache.get_or_new(arg.clone()))
.get_or_init(|| self.f.body(|arg| self.call(arg), arg))
.clone()
}
fn clear_cache(&self) {
self.cache.clear();
}
}