use std::sync::{Arc, RwLock};
use dry::macro_for;
use crate::{
estimators::{CIMEstimator, CPDEstimator},
models::{CIM, CPD, Labelled},
types::{Labels, Map, Set},
};
#[derive(Clone, Debug)]
pub struct Cache<'a, C, K, V> {
call: &'a C,
cache: Arc<RwLock<Map<K, V>>>,
}
impl<'a, E, P> Cache<'a, E, (Vec<usize>, Vec<usize>), P>
where
P: Clone,
{
#[inline]
pub fn new(call: &'a E) -> Self {
let cache = Arc::new(RwLock::new(Map::default()));
Self { call, cache }
}
}
impl<C, K, V> Labelled for Cache<'_, C, K, V>
where
C: Labelled,
{
#[inline]
fn labels(&self) -> &Labels {
self.call.labels()
}
}
macro_for!($type in [CPD, CIM] {
paste::paste! {
impl<E, P> [<$type Estimator>]<P> for Cache<'_, E, (Vec<usize>, Vec<usize>), P>
where
E: [<$type Estimator>]<P>,
P: $type + Clone,
P::Statistics: Clone,
{
fn fit(&self, x: &Set<usize>, z: &Set<usize>) -> P {
let key: (Vec<_>, Vec<_>) = (
x.into_iter().cloned().collect(),
z.into_iter().cloned().collect(),
);
if let Some(value) = self.cache.read().unwrap().get(&key) {
return value.clone();
}
let value = self.call.fit(x, z);
self.cache.write().unwrap().insert(key, value.clone());
value
}
}
}
});