keos_project5/
lru.rs

1//! A Least Recently Used (LRU) Cache.
2//!
3//! `LRUCache<K, V, MAX_SIZE>` stores up to `MAX_SIZE` key-value pairs,
4//! automatically evicting the least recently used entry when the capacity
5//! is exceeded. This makes it useful for caching expensive computations,
6//! I/O results, or any data where temporal locality is expected.
7//!
8//! # Example
9//! ```
10//! let mut cache: LRUCache<i32, String, 2> = LRUCache::new();
11//!
12//! cache.put(1, "one".to_string());
13//! cache.put(2, "two".to_string());
14//!
15//! // Access key 1, making it most recently used
16//! assert_eq!(cache.get(1).map(|v| v.as_str()), Some("one"));
17//!
18//! // Insert new key, evicting key 2 (least recently used)
19//! cache.put(3, "three".to_string());
20//!
21//! assert!(cache.get(2).is_none()); // evicted
22//! assert!(cache.get(1).is_some());
23//! assert!(cache.get(3).is_some());
24//! ```
25use alloc::{collections::BTreeMap, vec::Vec};
26
27struct Node<K: Clone, V> {
28    v: V,
29    prev: Option<K>,
30    next: Option<K>,
31}
32
33/// An Least Recently Used Cache with capacity `MAX_SIZE`.
34pub struct LRUCache<K: Ord + Clone, V, const MAX_SIZE: usize> {
35    inner: BTreeMap<K, Node<K, V>>,
36
37    // Access information
38    head: Option<K>,
39    tail: Option<K>,
40}
41
42impl<K: Ord + Clone, V, const MAX_SIZE: usize> Default for LRUCache<K, V, MAX_SIZE> {
43    fn default() -> Self {
44        Self::new()
45    }
46}
47
48impl<K: Ord + Clone, V, const MAX_SIZE: usize> LRUCache<K, V, MAX_SIZE> {
49    // Attach the access information about key.
50    fn attach(&mut self, k: K) -> &mut Node<K, V> {
51        if let Some(tail) = self.tail.take() {
52            let last = self.inner.get_mut(&tail).unwrap();
53            last.next = Some(k.clone());
54        } else {
55            self.head = Some(k.clone());
56        }
57        let ptail = self.tail.clone();
58        self.tail = Some(k.clone());
59
60        let node = self.inner.get_mut(&k).unwrap();
61        node.prev = ptail;
62        node
63    }
64
65    // Detach the access information about key.
66    fn detach(&mut self, prev: Option<K>, next: Option<K>) {
67        if let Some(next) = next.as_ref() {
68            self.inner.get_mut(next).unwrap().prev = prev.clone();
69        } else {
70            self.tail = prev.clone();
71        }
72
73        if let Some(prev) = prev {
74            self.inner.get_mut(&prev).unwrap().next = next;
75        } else {
76            self.head = next;
77        }
78    }
79
80    /// Makes a new, empty `LRUCache`.
81    ///
82    /// Does not allocate anything on its own.
83    pub const fn new() -> Self {
84        Self {
85            inner: BTreeMap::new(),
86            head: None,
87            tail: None,
88        }
89    }
90
91    /// Returns a mutable reference to the value corresponding to the key and
92    /// update the last access time.
93    pub fn get(&mut self, k: K) -> Option<&mut V> {
94        let node = self.inner.get_mut(&k)?;
95        let (prev, next) = (node.prev.take(), node.next.take());
96        self.detach(prev, next);
97        Some(&mut self.attach(k).v)
98    }
99
100    /// Inserts the value computed with `f` into the `LRUCache` if it is not
101    /// present, then returns a reference to the value in the `LRUCache`.
102    pub fn get_or_insert_with<E>(
103        &mut self,
104        k: K,
105        f: impl FnOnce() -> Result<V, E>,
106    ) -> Result<&mut V, E> {
107        Ok(if let Some(node) = self.inner.get_mut(&k) {
108            let (prev, next) = (node.prev.take(), node.next.take());
109            self.detach(prev, next);
110            &mut self.attach(k).v
111        } else {
112            &mut self.__put(k, f()?).v
113        })
114    }
115
116    fn __put(&mut self, k: K, v: V) -> &mut Node<K, V> {
117        if let Some(node) = self.inner.get_mut(&k) {
118            node.v = v;
119            let (prev, next) = (node.prev.take(), node.next.take());
120            self.detach(prev, next);
121        } else {
122            if MAX_SIZE <= self.inner.len() {
123                self.remove(&self.head.clone().unwrap());
124            }
125            let node = Node {
126                v,
127                prev: self.tail.clone(),
128                next: None,
129            };
130            self.inner.insert(k.clone(), node);
131        }
132        self.attach(k)
133    }
134
135    /// Inserts a key-value pair into the `LRUCache`.
136    ///
137    /// If the map did have this key present, the value is updated.
138    /// The key is not updated, though; this matters for types that can be ==
139    /// without being identical.
140    ///
141    /// If the cache size is overflowed after insertion, evict the oldest
142    /// accessed entry.
143    pub fn put(&mut self, k: K, v: V) {
144        self.__put(k, v);
145    }
146
147    /// Removes a key from the LRUCache, returning the stored value if the
148    /// key was previously in the LRUCache.
149    ///
150    /// The key may be any borrowed form of the LRUCache’s key type, but the
151    /// ordering on the borrowed form must match the ordering on the key
152    /// type.
153    pub fn remove(&mut self, k: &K) -> Option<V> {
154        let mut node = self.inner.remove(k)?;
155        self.detach(node.prev.take(), node.next.take());
156        Some(node.v)
157    }
158
159    /// Retains only the elements specified by the predicate.
160    /// In other words, remove all pairs (k, v) for which f(&k, &mut v) returns
161    /// false.
162    pub fn retain(&mut self, mut f: impl FnMut(&K, &mut V) -> bool) {
163        let retain_targets = self
164            .inner
165            .iter_mut()
166            .filter_map(|(k, v)| {
167                if !f(k, &mut v.v) {
168                    Some(k.clone())
169                } else {
170                    None
171                }
172            })
173            .collect::<Vec<_>>();
174        for target in retain_targets.into_iter() {
175            self.remove(&target);
176        }
177    }
178
179    /// Iterates over the key-value pairs in the LRUCache.
180    pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut V)> {
181        self.inner.iter_mut().map(|(k, v)| (k, &mut v.v))
182    }
183}