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 if let Some(value) = self.map.remove(k) {
106 if let Some(index) = self
108 .oldest
109 .iter()
110 .position(|item| item.borrow() == k)
111 {
112 self.oldest.remove(index);
113 }
114 Some(value)
115 } else {
116 None
117 }
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use std::prelude::v1::*;
124
125 type Test = super::LimitedCache<String, usize>;
126
127 #[test]
128 fn test_updates_existing_item() {
129 let mut t = Test::new(3);
130 t.insert("abc".into(), 1);
131 t.insert("abc".into(), 2);
132 assert_eq!(t.get("abc"), Some(&2));
133 }
134
135 #[test]
136 fn test_evicts_oldest_item() {
137 let mut t = Test::new(3);
138 t.insert("abc".into(), 1);
139 t.insert("def".into(), 2);
140 t.insert("ghi".into(), 3);
141
142 assert_eq!(t.get("abc"), None);
143 assert_eq!(t.get("def"), Some(&2));
144 assert_eq!(t.get("ghi"), Some(&3));
145 }
146
147 #[test]
148 fn test_evicts_second_oldest_item_if_first_removed() {
149 let mut t = Test::new(3);
150 t.insert("abc".into(), 1);
151 t.insert("def".into(), 2);
152
153 assert_eq!(t.remove("abc"), Some(1));
154
155 t.insert("ghi".into(), 3);
156 t.insert("jkl".into(), 4);
157
158 assert_eq!(t.get("abc"), None);
159 assert_eq!(t.get("def"), None);
160 assert_eq!(t.get("ghi"), Some(&3));
161 assert_eq!(t.get("jkl"), Some(&4));
162 }
163
164 #[test]
165 fn test_evicts_after_second_oldest_item_removed() {
166 let mut t = Test::new(3);
167 t.insert("abc".into(), 1);
168 t.insert("def".into(), 2);
169
170 assert_eq!(t.remove("def"), Some(2));
171 assert_eq!(t.get("abc"), Some(&1));
172
173 t.insert("ghi".into(), 3);
174 t.insert("jkl".into(), 4);
175
176 assert_eq!(t.get("abc"), None);
177 assert_eq!(t.get("def"), None);
178 assert_eq!(t.get("ghi"), Some(&3));
179 assert_eq!(t.get("jkl"), Some(&4));
180 }
181
182 #[test]
183 fn test_removes_all_items() {
184 let mut t = Test::new(3);
185 t.insert("abc".into(), 1);
186 t.insert("def".into(), 2);
187
188 assert_eq!(t.remove("def"), Some(2));
189 assert_eq!(t.remove("abc"), Some(1));
190
191 t.insert("ghi".into(), 3);
192 t.insert("jkl".into(), 4);
193 t.insert("mno".into(), 5);
194
195 assert_eq!(t.get("abc"), None);
196 assert_eq!(t.get("def"), None);
197 assert_eq!(t.get("ghi"), None);
198 assert_eq!(t.get("jkl"), Some(&4));
199 assert_eq!(t.get("mno"), Some(&5));
200 }
201
202 #[test]
203 fn test_inserts_many_items() {
204 let mut t = Test::new(3);
205
206 for _ in 0..10000 {
207 t.insert("abc".into(), 1);
208 t.insert("def".into(), 2);
209 t.insert("ghi".into(), 3);
210 }
211 }
212
213 #[test]
214 fn test_get_or_insert_default_and_edit_evicts_old_items_to_meet_capacity() {
215 let mut t = Test::new(3);
216
217 t.get_or_insert_default_and_edit("abc".into(), |v| *v += 1);
218 t.get_or_insert_default_and_edit("def".into(), |v| *v += 2);
219
220 t.get_or_insert_default_and_edit("ghi".into(), |v| *v += 3);
222 assert_eq!(t.get("abc"), None);
223
224 t.get_or_insert_default_and_edit("jkl".into(), |v| *v += 4);
226 assert_eq!(t.get("def"), None);
227
228 t.get_or_insert_default_and_edit("abc".into(), |v| *v += 5);
230 assert_eq!(t.get("ghi"), None);
231
232 t.get_or_insert_default_and_edit("def".into(), |v| *v += 6);
234
235 assert_eq!(t.get("abc"), Some(&5));
236 assert_eq!(t.get("def"), Some(&6));
237 assert_eq!(t.get("ghi"), None);
238 assert_eq!(t.get("jkl"), None);
239 }
240
241 #[test]
242 fn test_get_or_insert_default_and_edit_edits_existing_item() {
243 let mut t = Test::new(3);
244
245 t.get_or_insert_default_and_edit("abc".into(), |v| *v += 1);
246 t.get_or_insert_default_and_edit("abc".into(), |v| *v += 2);
247 t.get_or_insert_default_and_edit("abc".into(), |v| *v += 3);
248
249 assert_eq!(t.get("abc"), Some(&6));
250 }
251}