use std::{collections::HashMap, hash::Hash};
pub trait FnCacher<IFunc, IType, IReturn>
where
IFunc: Fn(IType) -> IReturn,
IType: Clone + Hash + Eq,
IReturn: Clone,
{
fn new(func: IFunc) -> Self;
fn with_arg(&mut self, arg: IFunc) -> IReturn;
}
#[deprecated = "You should manually implement instead of the now deprecated traits."]
pub trait FnCacherExt<IFunc, IType, IReturn>: FnCacher<IFunc, IType, IReturn>
where
IFunc: Fn(IType) -> IReturn,
IType: Clone + Hash + Eq,
IReturn: Clone,
{
fn reset(&mut self);
fn to(&mut self, f: IType);
fn to_unchanged(&mut self, f: IType);
}
#[deprecated = "You should manually implement instead of the now deprecated traits."]
pub trait ICacherExt<IFunc, IType, IReturn>: __private::Sealed
where
IFunc: Fn(IType) -> IReturn,
IType: Clone + Hash + Eq,
IReturn: Clone,
{
fn reset(&mut self);
fn to(&mut self, func: IFunc);
fn to_unchanged(&mut self, func: IFunc);
}
#[derive(Debug, Clone)]
pub struct ICacher<IFunc, IType, IReturn>
where
IFunc: Fn(IType) -> IReturn,
IType: Clone + Hash + Eq,
IReturn: Clone,
{
func: IFunc,
values: HashMap<IType, IReturn>,
}
impl<IFunc, IType, IReturn> ICacher<IFunc, IType, IReturn>
where
IFunc: Fn(IType) -> IReturn,
IType: Clone + Hash + Eq,
IReturn: Clone,
{
#[inline]
pub fn new(func: IFunc, capacity: Option<usize>) -> Self {
ICacher {
func,
values: HashMap::with_capacity(capacity.unwrap_or_default()),
}
}
#[inline]
pub fn with_arg(&mut self, arg: IType) -> IReturn {
if self.values.contains_key(&arg) {
return self.values[&arg].clone();
}
let value = (self.func)(arg.clone());
self.values.insert(arg, value.clone());
value
}
#[inline]
pub fn reset(&mut self) {
self.values.clear();
}
#[inline]
pub fn to(&mut self, func: IFunc) {
self.to_unchanged(func);
self.values.clear();
}
#[inline]
pub fn to_unchanged(&mut self, func: IFunc) {
self.func = func;
}
#[inline]
pub fn is_cached(&self, arg: &IType) -> bool {
self.values.contains_key(&arg)
}
#[inline]
pub fn remove_cache(&mut self, arg: IType) -> Option<IReturn> {
match self.values.remove(&arg) {
Some(val) => Some(val),
None => None,
}
}
#[inline]
pub fn void(&mut self, arg: IType) {
self.with_arg(arg);
}
#[inline]
pub fn cache_if<Func: Fn() -> bool>(&mut self, func: Func, arg: IType) -> bool {
if self.is_cached(&arg) || !func() {
return false;
}
self.void(arg);
return true;
}
}
mod __private {
pub trait Sealed {}
impl<A, B, C> Sealed for super::ICacher<A, B, C>
where
A: Fn(B) -> C,
B: Clone + super::Hash + Eq,
C: Clone,
{
}
}