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