freya_core/
fifo_cache.rs

1use std::collections::VecDeque;
2
3use rustc_hash::FxHashMap;
4
5pub struct FifoCache<K, V> {
6    map: FxHashMap<K, V>,
7    order: VecDeque<K>,
8    capacity: usize,
9}
10
11impl<K, V> Default for FifoCache<K, V> {
12    fn default() -> Self {
13        Self {
14            map: FxHashMap::default(),
15            order: VecDeque::new(),
16            capacity: 256,
17        }
18    }
19}
20
21impl<K, V> FifoCache<K, V>
22where
23    K: Clone + Eq + std::hash::Hash,
24{
25    pub fn new() -> Self {
26        Self::default()
27    }
28
29    pub fn insert(&mut self, key: K, value: V) {
30        if self.map.contains_key(&key) {
31            self.map.insert(key, value);
32        } else {
33            if self.order.len() >= self.capacity
34                && let Some(old_key) = self.order.pop_front()
35            {
36                self.map.remove(&old_key);
37            }
38            self.order.push_back(key.clone());
39            self.map.insert(key, value);
40        }
41    }
42
43    pub fn get(&self, key: &K) -> Option<&V> {
44        self.map.get(key)
45    }
46
47    pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
48        self.map.get_mut(key)
49    }
50
51    pub fn len(&self) -> usize {
52        self.map.len()
53    }
54
55    pub fn is_empty(&self) -> bool {
56        self.map.is_empty()
57    }
58
59    pub fn clear(&mut self) {
60        self.map.clear();
61        self.order.clear();
62    }
63}
64
65impl<K, V> std::fmt::Debug for FifoCache<K, V>
66where
67    K: std::fmt::Debug,
68    V: std::fmt::Debug,
69{
70    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71        f.debug_struct("FifoCache")
72            .field("map", &self.map)
73            .field("order", &self.order)
74            .field("capacity", &self.capacity)
75            .finish()
76    }
77}
78
79#[cfg(test)]
80mod test {
81    use super::FifoCache;
82
83    #[test]
84    fn fifo_cache() {
85        let mut cache = FifoCache::<i32, i32>::new();
86
87        for i in 0..256 {
88            cache.insert(i, i * 10);
89        }
90
91        assert_eq!(cache.len(), 256);
92        assert_eq!(cache.get(&0), Some(&0));
93        assert_eq!(cache.get(&255), Some(&2550));
94
95        // Insert one more, should remove 0
96        cache.insert(256, 2560);
97        assert_eq!(cache.len(), 256);
98        assert_eq!(cache.get(&0), None);
99        assert_eq!(cache.get(&1), Some(&10));
100        assert_eq!(cache.get(&256), Some(&2560));
101
102        // Update existing
103        cache.insert(1, 100);
104        assert_eq!(cache.get(&1), Some(&100));
105        assert_eq!(cache.len(), 256);
106    }
107}