use alloc::collections::BTreeMap;
use alloc::vec::Vec;
#[derive(Clone, Debug, PartialEq, Eq)]
struct Slot<V> {
v: V,
tick: u64,
weight: u64,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Lru<K: Ord + Clone, V> {
map: BTreeMap<K, Slot<V>>,
order: BTreeMap<u64, K>,
tick: u64,
weight: u64,
pub max_len: usize,
pub max_weight: u64,
}
impl<K: Ord + Clone, V> Lru<K, V> {
pub fn new(max_len: usize, max_weight: u64) -> Lru<K, V> {
Lru { map: BTreeMap::new(), order: BTreeMap::new(), tick: 0, weight: 0, max_len, max_weight }
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
pub fn weight(&self) -> u64 {
self.weight
}
pub fn contains(&self, k: &K) -> bool {
self.map.contains_key(k)
}
pub fn peek(&self, k: &K) -> Option<&V> {
self.map.get(k).map(|s| &s.v)
}
fn touch(&mut self, k: &K) {
self.tick += 1;
let t = self.tick;
if let Some(s) = self.map.get_mut(k) {
self.order.remove(&s.tick);
s.tick = t;
self.order.insert(t, k.clone());
}
}
pub fn get(&mut self, k: &K) -> Option<&V> {
if !self.map.contains_key(k) {
return None;
}
self.touch(k);
self.map.get(k).map(|s| &s.v)
}
pub fn get_mut(&mut self, k: &K) -> Option<&mut V> {
if !self.map.contains_key(k) {
return None;
}
self.touch(k);
self.map.get_mut(k).map(|s| &mut s.v)
}
pub fn insert(&mut self, k: K, v: V, weight: u64) -> Vec<(K, V)> {
let _ = self.remove(&k);
self.tick += 1;
let t = self.tick;
self.order.insert(t, k.clone());
self.map.insert(k, Slot { v, tick: t, weight });
self.weight = self.weight.saturating_add(weight);
let mut out = Vec::new();
while (self.max_len > 0 && self.map.len() > self.max_len) || (self.max_weight > 0 && self.weight > self.max_weight) {
match self.pop_lru() {
Some(e) => out.push(e),
None => break,
}
}
out
}
pub fn remove(&mut self, k: &K) -> Option<V> {
let s = self.map.remove(k)?;
self.order.remove(&s.tick);
self.weight = self.weight.saturating_sub(s.weight);
Some(s.v)
}
pub fn pop_lru(&mut self) -> Option<(K, V)> {
let (&t, _) = self.order.iter().next()?;
let k = self.order.remove(&t)?;
let s = self.map.remove(&k)?;
self.weight = self.weight.saturating_sub(s.weight);
Some((k, s.v))
}
pub fn clear(&mut self) {
self.map.clear();
self.order.clear();
self.weight = 0;
}
pub fn keys(&self) -> impl Iterator<Item = &K> {
self.order.values()
}
pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
self.map.iter().map(|(k, s)| (k, &s.v))
}
}