r_tool/cache/
lfu_cache.rs1use std::collections::{HashMap, LinkedList};
2
3pub struct LFUCache<K:Eq, V> {
4 capacity: usize,
5 cache: HashMap<K, (V, usize, usize)>,
6 order: LinkedList<K>,
7}
8
9impl<K :Eq, V> LFUCache<K, V>
10 where
11 K: Eq + std::hash::Hash + Clone,
12{
13 pub fn new(capacity: usize) -> Self {
21 LFUCache {
22 capacity,
23 cache: HashMap::with_capacity(capacity),
24 order: LinkedList::new(),
25 }
26 }
27
28 pub fn get(&mut self, key: &K) -> Option<&V> {
36 if let Some((value, frequency, timestamp)) = self.cache.get_mut(key) {
37 *frequency += 1;
39 *timestamp = self.order.len();
41 let popped_key = self.order.pop_front().unwrap();
43 self.order.push_back(popped_key);
44 Some(value)
45 } else {
46 None
47 }
48 }
49
50 pub fn put(&mut self, key: K, value: V) {
57 if self.cache.len() >= self.capacity {
58 let min_frequency_key = self
60 .order
61 .iter()
62 .min_by_key(|&k| self.cache.get(k).map_or(usize::MAX, |(_, f, _)| *f))
63 .cloned();
64
65 if let Some(oldest_key) = min_frequency_key {
67 self.cache.remove(&oldest_key);
68 }
69 }
70
71 let timestamp = self.order.len();
73 self.cache.insert(key.clone(), (value, 1, timestamp));
74 self.order.push_back(key);
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[test]
84 fn test_lfu_cache() {
85 let mut lfu_cache = LFUCache::new(3);
86
87 lfu_cache.put("one", 1);
89 lfu_cache.put("two", 2);
90 lfu_cache.put("three", 3);
91
92 assert_eq!(lfu_cache.get(&"one"), Some(&1));
94
95 assert_eq!(lfu_cache.get(&"two"), Some(&2));
97 assert_eq!(lfu_cache.get(&"two"), Some(&2));
98
99 lfu_cache.put("four", 4);
101
102 assert_eq!(lfu_cache.cache.len(), 3);
104 assert_eq!(lfu_cache.get(&"one"), Some(&1));
105 assert_eq!(lfu_cache.get(&"two"), Some(&2));
106 assert_eq!(lfu_cache.get(&"three"), None); assert_eq!(lfu_cache.get(&"four"), Some(&4));
108 }
109}