1use alloc::collections::VecDeque;
2use core::borrow::Borrow;
3use core::hash::Hash;
4
5use crate::hash_map::{Entry, HashMap};
6
7pub(crate) struct LimitedCache<K: Clone + Hash + Eq, V> {
16 map: HashMap<K, V>,
17
18 oldest: VecDeque<K>,
20}
21
22impl<K, V> LimitedCache<K, V>
23where
24 K: Eq + Hash + Clone + core::fmt::Debug,
25 V: Default,
26{
27 pub(crate) fn get_or_insert_default_and_edit(&mut self, k: K, edit: impl FnOnce(&mut V)) {
28 let inserted_new_item = match self.map.entry(k) {
29 Entry::Occupied(value) => {
30 edit(value.into_mut());
31 false
32 }
33 entry @ Entry::Vacant(_) => {
34 self.oldest
35 .push_back(entry.key().clone());
36 edit(entry.or_insert_with(V::default));
37 true
38 }
39 };
40
41 if inserted_new_item && self.oldest.capacity() == self.oldest.len() {
43 if let Some(oldest_key) = self.oldest.pop_front() {
44 self.map.remove(&oldest_key);
45 }
46 }
47 }
48
49 pub(crate) fn get_mut<Q: Hash + Eq + ?Sized>(&mut self, k: &Q) -> Option<&mut V>
50 where
51 K: Borrow<Q>,
52 {
53 self.map.get_mut(k)
54 }
55}
56
57impl<K, V> LimitedCache<K, V>
58where
59 K: Eq + Hash + Clone + core::fmt::Debug,
60 V: Default,
61{
62 pub(crate) fn new(capacity_order_of_magnitude: usize) -> Self {
64 Self {
65 map: HashMap::with_capacity(capacity_order_of_magnitude),
66 oldest: VecDeque::with_capacity(capacity_order_of_magnitude),
67 }
68 }
69
70 pub(crate) fn insert(&mut self, k: K, v: V) {
71 let inserted_new_item = match self.map.entry(k) {
72 Entry::Occupied(mut old) => {
73 old.insert(v);
75 false
76 }
77
78 entry @ Entry::Vacant(_) => {
79 self.oldest
80 .push_back(entry.key().clone());
81 entry.or_insert(v);
82 true
83 }
84 };
85
86 if inserted_new_item && self.oldest.capacity() == self.oldest.len() {
88 if let Some(oldest_key) = self.oldest.pop_front() {
89 self.map.remove(&oldest_key);
90 }
91 }
92 }
93
94 pub(crate) fn get<Q: Hash + Eq + ?Sized>(&self, k: &Q) -> Option<&V>
95 where
96 K: Borrow<Q>,
97 {
98 self.map.get(k)
99 }
100
101 pub(crate) fn remove<Q: Hash + Eq + ?Sized>(&mut self, k: &Q) -> Option<V>
102 where
103 K: Borrow<Q>,
104 {
105 let value = self.map.remove(k)?;
106
107 if let Some(index) = self
109 .oldest
110 .iter()
111 .position(|item| item.borrow() == k)
112 {
113 self.oldest.remove(index);
114 }
115
116 Some(value)
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use std::prelude::v1::*;
123
124 type Test = super::LimitedCache<String, usize>;
125
126 #[test]
127 fn test_updates_existing_item() {
128 let mut t = Test::new(3);
129 t.insert("abc".into(), 1);
130 t.insert("abc".into(), 2);
131 assert_eq!(t.get("abc"), Some(&2));
132 }
133
134 #[test]
135 fn test_evicts_oldest_item() {
136 let mut t = Test::new(3);
137 t.insert("abc".into(), 1);
138 t.insert("def".into(), 2);
139 t.insert("ghi".into(), 3);
140
141 assert_eq!(t.get("abc"), None);
142 assert_eq!(t.get("def"), Some(&2));
143 assert_eq!(t.get("ghi"), Some(&3));
144 }
145
146 #[test]
147 fn test_evicts_second_oldest_item_if_first_removed() {
148 let mut t = Test::new(3);
149 t.insert("abc".into(), 1);
150 t.insert("def".into(), 2);
151
152 assert_eq!(t.remove("abc"), Some(1));
153
154 t.insert("ghi".into(), 3);
155 t.insert("jkl".into(), 4);
156
157 assert_eq!(t.get("abc"), None);
158 assert_eq!(t.get("def"), None);
159 assert_eq!(t.get("ghi"), Some(&3));
160 assert_eq!(t.get("jkl"), Some(&4));
161 }
162
163 #[test]
164 fn test_evicts_after_second_oldest_item_removed() {
165 let mut t = Test::new(3);
166 t.insert("abc".into(), 1);
167 t.insert("def".into(), 2);
168
169 assert_eq!(t.remove("def"), Some(2));
170 assert_eq!(t.get("abc"), Some(&1));
171
172 t.insert("ghi".into(), 3);
173 t.insert("jkl".into(), 4);
174
175 assert_eq!(t.get("abc"), None);
176 assert_eq!(t.get("def"), None);
177 assert_eq!(t.get("ghi"), Some(&3));
178 assert_eq!(t.get("jkl"), Some(&4));
179 }
180
181 #[test]
182 fn test_removes_all_items() {
183 let mut t = Test::new(3);
184 t.insert("abc".into(), 1);
185 t.insert("def".into(), 2);
186
187 assert_eq!(t.remove("def"), Some(2));
188 assert_eq!(t.remove("abc"), Some(1));
189
190 t.insert("ghi".into(), 3);
191 t.insert("jkl".into(), 4);
192 t.insert("mno".into(), 5);
193
194 assert_eq!(t.get("abc"), None);
195 assert_eq!(t.get("def"), None);
196 assert_eq!(t.get("ghi"), None);
197 assert_eq!(t.get("jkl"), Some(&4));
198 assert_eq!(t.get("mno"), Some(&5));
199 }
200
201 #[test]
202 fn test_inserts_many_items() {
203 let mut t = Test::new(3);
204
205 for _ in 0..10000 {
206 t.insert("abc".into(), 1);
207 t.insert("def".into(), 2);
208 t.insert("ghi".into(), 3);
209 }
210 }
211
212 #[test]
213 fn test_get_or_insert_default_and_edit_evicts_old_items_to_meet_capacity() {
214 let mut t = Test::new(3);
215
216 t.get_or_insert_default_and_edit("abc".into(), |v| *v += 1);
217 t.get_or_insert_default_and_edit("def".into(), |v| *v += 2);
218
219 t.get_or_insert_default_and_edit("ghi".into(), |v| *v += 3);
221 assert_eq!(t.get("abc"), None);
222
223 t.get_or_insert_default_and_edit("jkl".into(), |v| *v += 4);
225 assert_eq!(t.get("def"), None);
226
227 t.get_or_insert_default_and_edit("abc".into(), |v| *v += 5);
229 assert_eq!(t.get("ghi"), None);
230
231 t.get_or_insert_default_and_edit("def".into(), |v| *v += 6);
233
234 assert_eq!(t.get("abc"), Some(&5));
235 assert_eq!(t.get("def"), Some(&6));
236 assert_eq!(t.get("ghi"), None);
237 assert_eq!(t.get("jkl"), None);
238 }
239
240 #[test]
241 fn test_get_or_insert_default_and_edit_edits_existing_item() {
242 let mut t = Test::new(3);
243
244 t.get_or_insert_default_and_edit("abc".into(), |v| *v += 1);
245 t.get_or_insert_default_and_edit("abc".into(), |v| *v += 2);
246 t.get_or_insert_default_and_edit("abc".into(), |v| *v += 3);
247
248 assert_eq!(t.get("abc"), Some(&6));
249 }
250}