use crate::container::{
ContainerClear, ContainerLen, ContainerRemove, ContainerReserve, SparseContainer,
};
use crate::{FnCache, FnCacheMany};
pub struct GenericCache<'f, C: SparseContainer> {
pub(crate) cache: C,
f: Box<dyn Fn(&mut RefCache<C>, &C::Input) -> C::Output + Send + 'f>,
}
impl<'f, C: SparseContainer> GenericCache<'f, C> {
pub fn with_cache(cache: C, f: impl Fn(&C::Input) -> C::Output + Send + 'f) -> Self {
Self {
cache,
f: Box::new(move |_, i| f(i)),
}
}
pub fn recursive_with_cache(
cache: C,
f: impl Fn(&mut RefCache<C>, &C::Input) -> C::Output + Send + 'f,
) -> Self {
Self {
cache,
f: Box::new(f),
}
}
pub fn cache(&self) -> &C {
&self.cache
}
}
impl<'f, C> GenericCache<'f, C>
where
C: SparseContainer + Default,
{
pub fn new(f: impl Fn(&C::Input) -> C::Output + Send + 'f) -> Self {
Self::with_cache(Default::default(), f)
}
pub fn recursive(f: impl Fn(&mut RefCache<C>, &C::Input) -> C::Output + Send + 'f) -> Self {
Self::recursive_with_cache(Default::default(), f)
}
}
impl<'f, C: SparseContainer + ContainerLen> GenericCache<'f, C> {
pub fn len(&self) -> usize {
self.cache.len()
}
}
impl<'f, C: SparseContainer + ContainerClear> GenericCache<'f, C> {
pub fn clear(&mut self) {
self.cache.clear()
}
}
impl<'f, C: SparseContainer + ContainerReserve> GenericCache<'f, C> {
pub fn reserve(&mut self, additional: usize) {
self.cache.reserve(additional)
}
}
impl<'f, C: ContainerRemove> GenericCache<'f, C> {
pub fn remove(&mut self, input: &C::Input) -> Option<C::Output> {
self.cache.remove(input)
}
}
impl<'f, C: SparseContainer> FnCache<C::Input, C::Output> for GenericCache<'f, C> {
fn get(&mut self, input: C::Input) -> &C::Output {
if self.cache.has(&input) {
self.cache.get(&input).unwrap()
} else {
let mut ref_cache = RefCache::new(&mut self.cache, self.f.as_ref());
let output = (self.f)(&mut ref_cache, &input);
self.cache.put(input, output)
}
}
}
impl<'f, C> FnCacheMany<C::Input, C::Output> for GenericCache<'f, C>
where
C: SparseContainer,
C::Input: Clone,
{
fn get_many<const N: usize>(&mut self, inputs: [C::Input; N]) -> [&C::Output; N] {
for i in &inputs {
self.get(i.clone());
}
inputs.map(|i| self.cache.get(&i).unwrap())
}
}
pub struct RefCache<'c, C: SparseContainer> {
pub(crate) cache: &'c mut C,
f: &'c (dyn Fn(&mut Self, &C::Input) -> C::Output + Send),
}
impl<'c, C: SparseContainer> RefCache<'c, C> {
pub fn new(
cache: &'c mut C,
f: &'c (dyn Fn(&mut Self, &C::Input) -> C::Output + Send),
) -> Self {
Self { cache, f }
}
}
impl<'c, C> FnCache<C::Input, C::Output> for RefCache<'c, C>
where
C: SparseContainer,
{
fn get(&mut self, input: C::Input) -> &C::Output {
if self.cache.has(&input) {
self.cache.get(&input).unwrap()
} else {
let output = (self.f)(self, &input);
self.cache.put(input, output)
}
}
}
impl<'c, C> FnCacheMany<C::Input, C::Output> for RefCache<'c, C>
where
C: SparseContainer,
C::Input: Clone,
{
fn get_many<const N: usize>(&mut self, inputs: [C::Input; N]) -> [&C::Output; N] {
for i in &inputs {
self.get(i.clone());
}
inputs.map(|i| self.cache.get(&i).unwrap())
}
}