use std::collections::{BTreeMap, HashMap};
use kurbo::Rect as KRect;
use crate::resolve::Theme;
use super::*;
struct Entry<T> {
value: T,
cost: usize,
stale: bool,
used: u64,
}
pub struct Cache<T, K: Tiled = Key> {
cap: usize,
cost: usize,
clock: u64,
entries: HashMap<K, Entry<T>>,
by_use: BTreeMap<u64, K>,
}
impl<T, K: Tiled> Cache<T, K> {
pub fn new(cap: usize) -> Cache<T, K> {
Cache {
cap,
cost: 0,
clock: 0,
entries: HashMap::new(),
by_use: BTreeMap::new(),
}
}
pub fn get(&mut self, key: &K) -> Option<(&T, bool)> {
self.clock += 1;
let e = self.entries.get_mut(key)?;
self.by_use.remove(&e.used);
e.used = self.clock;
self.by_use.insert(self.clock, *key);
Some((&e.value, e.stale))
}
pub fn peek(&self, key: &K) -> Option<(&T, bool)> {
self.entries.get(key).map(|e| (&e.value, e.stale))
}
pub fn insert(&mut self, key: K, value: T, cost: usize) -> Vec<(K, T)> {
self.remove(&key);
let mut dropped = Vec::new();
self.clock += 1;
self.entries.insert(
key,
Entry {
value,
cost,
stale: false,
used: self.clock,
},
);
self.by_use.insert(self.clock, key);
self.cost += cost;
while self.cost > self.cap {
let Some((_, oldest)) = self.by_use.iter().next().map(|(u, k)| (*u, *k)) else {
break;
};
if oldest == key {
break;
}
if let Some(v) = self.remove(&oldest) {
dropped.push((oldest, v));
}
}
dropped
}
pub fn remove(&mut self, key: &K) -> Option<T> {
let e = self.entries.remove(key)?;
self.by_use.remove(&e.used);
self.cost -= e.cost;
Some(e.value)
}
pub fn damage(&mut self, theme: Theme, origin: (f64, f64), rects: &[KRect]) {
self.damage_where(|k| k.key().theme == theme, origin, rects);
}
pub fn damage_where(
&mut self,
which: impl Fn(&K) -> bool,
origin: (f64, f64),
rects: &[KRect],
) {
for (k, e) in &mut self.entries {
if e.stale || !which(k) {
continue;
}
let r = k.key().rect(origin);
if rects
.iter()
.any(|d| d.x0 < r.x1 && d.x1 > r.x0 && d.y0 < r.y1 && d.y1 > r.y0)
{
e.stale = true;
}
}
}
pub fn damage_all(&mut self, theme: Theme) {
self.damage_all_where(|k| k.key().theme == theme);
}
pub fn damage_all_where(&mut self, which: impl Fn(&K) -> bool) {
for (k, e) in &mut self.entries {
if which(k) {
e.stale = true;
}
}
}
pub fn forget(&mut self, which: impl Fn(&K) -> bool) {
let gone: Vec<K> = self.entries.keys().filter(|k| which(k)).copied().collect();
for k in gone {
self.remove(&k);
}
}
pub fn iter(&self) -> impl Iterator<Item = (&K, &T, bool)> {
self.entries.iter().map(|(k, e)| (k, &e.value, e.stale))
}
pub fn clear(&mut self) -> Vec<T> {
self.by_use.clear();
self.cost = 0;
self.entries.drain().map(|(_, e)| e.value).collect()
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn cost(&self) -> usize {
self.cost
}
}
#[cfg(test)]
mod tests;