use super::CacheTrait;
pub trait ComputerMut<Key, Value>: 'static + Send + Sync {
fn compute(&mut self, key: Key) -> Value;
}
pub struct FrameCache<Value, Computer> {
generation: u32,
computer: Computer,
cache: nohash_hasher::IntMap<u64, (u32, Value)>,
}
impl<Value, Computer> Default for FrameCache<Value, Computer>
where
Computer: Default,
{
fn default() -> Self {
Self::new(Computer::default())
}
}
impl<Value, Computer> FrameCache<Value, Computer> {
pub fn new(computer: Computer) -> Self {
Self {
generation: 0,
computer,
cache: Default::default(),
}
}
pub fn evict_cache(&mut self) {
let current_generation = self.generation;
self.cache.retain(|_key, cached| {
cached.0 == current_generation });
self.generation = self.generation.wrapping_add(1);
}
}
impl<Value, Computer> FrameCache<Value, Computer> {
pub fn get<Key>(&mut self, key: Key) -> Value
where
Key: Copy + std::hash::Hash,
Value: Clone,
Computer: ComputerMut<Key, Value>,
{
let hash = crate::util::hash(key);
match self.cache.entry(hash) {
std::collections::hash_map::Entry::Occupied(entry) => {
let cached = entry.into_mut();
cached.0 = self.generation;
cached.1.clone()
}
std::collections::hash_map::Entry::Vacant(entry) => {
let value = self.computer.compute(key);
entry.insert((self.generation, value.clone()));
value
}
}
}
}
impl<Value: 'static + Send + Sync, Computer: 'static + Send + Sync> CacheTrait
for FrameCache<Value, Computer>
{
fn update(&mut self) {
self.evict_cache();
}
fn len(&self) -> usize {
self.cache.len()
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
}