cranpose_core/collections/
pass_aged.rs1use std::{borrow::Borrow, hash::Hash};
4
5use super::bounded_lru::BoundedLruCache;
6
7pub const IDLE_PASSES: u64 = 120;
11
12struct Used<V> {
14 value: V,
15 pass: u64,
16}
17
18pub struct PassAgedCache<K, V> {
23 entries: BoundedLruCache<K, Used<V>>,
24 pass: u64,
25}
26
27impl<K, V> PassAgedCache<K, V>
28where
29 K: Eq + Hash,
30{
31 pub fn with_capacity_at_least_one(capacity: usize) -> Self {
32 Self {
33 entries: BoundedLruCache::with_capacity_at_least_one(capacity),
34 pass: 0,
35 }
36 }
37
38 pub fn len(&self) -> usize {
39 self.entries.len()
40 }
41
42 pub fn is_empty(&self) -> bool {
43 self.entries.is_empty()
44 }
45
46 pub fn clear(&mut self) {
48 self.entries.clear();
49 }
50
51 pub fn get<Q>(&mut self, key: &Q) -> Option<&V>
53 where
54 K: Borrow<Q>,
55 Q: Hash + Eq + ?Sized,
56 {
57 let pass = self.pass;
58 let used = self.entries.get_mut(key)?;
59 used.pass = pass;
60 Some(&used.value)
61 }
62
63 pub fn push(&mut self, key: K, value: V) -> Option<(K, V)> {
66 let pass = self.pass;
67 self.entries
68 .push(key, Used { value, pass })
69 .map(|(key, used)| (key, used.value))
70 }
71
72 pub fn pop_lru(&mut self) -> Option<(K, V)> {
73 self.entries.pop_lru().map(|(key, used)| (key, used.value))
74 }
75
76 pub fn begin_pass(&mut self, mut dropped: impl FnMut(V)) {
81 self.pass += 1;
82 let pass = self.pass;
83 while self
84 .entries
85 .peek_lru()
86 .is_some_and(|(_, used)| pass - used.pass > IDLE_PASSES)
87 {
88 let Some((_, used)) = self.entries.pop_lru() else {
89 break;
90 };
91 dropped(used.value);
92 }
93 }
94}
95
96#[cfg(test)]
97#[path = "tests/pass_aged_tests.rs"]
98mod tests;