1use std::{
2 collections::{HashMap, LinkedList},
3 hash::Hash,
4 rc::Rc,
5};
6
7pub struct LRU<K, V> {
8 list: LinkedList<(Rc<K>, Rc<V>)>,
9 map: HashMap<Rc<K>, (Rc<V>, usize)>,
10 num_items: usize,
11 max_items: usize,
12}
13
14impl<K: Eq + Hash, V> LRU<K, V> {
15 pub fn new(max_items: usize) -> Self {
16 Self {
17 list: LinkedList::new(),
18 map: HashMap::new(),
19 num_items: 0,
20 max_items,
21 }
22 }
23
24 pub fn push(&mut self, key: Rc<K>, value: Rc<V>) -> Option<(Rc<K>, Rc<V>)> {
26 if let Some((_, count)) = self.map.get_mut(&key) {
27 self.list.push_back((key, value));
29 *count += 1;
30
31 return self.maybe_gc();
32 }
33
34 self.list.push_back((key.clone(), value.clone()));
36 self.map.insert(key, (value, 1));
37 self.num_items += 1;
38
39 return self.maybe_gc();
40 }
41
42 #[inline(always)]
43 pub fn maybe_gc(&mut self) -> Option<(Rc<K>, Rc<V>)> {
44 if self.num_items > self.max_items {
45 self.gc()
46 } else {
47 None
48 }
49 }
50
51 pub fn gc(&mut self) -> Option<(Rc<K>, Rc<V>)> {
52 let mut iterations = 0;
53
54 while iterations < self.list.len() && self.num_items > self.max_items {
55 iterations += 1;
56
57 if let Some((key, value)) = self.list.pop_front() {
58 if let Some((_, count)) = self.map.get_mut(&key) {
59 if *count > 1 {
60 *count -= 1;
62 } else if Rc::strong_count(&value) > 2 {
63 self.list.push_back((key, value));
65 } else {
66 self.map.remove(&key);
68 self.num_items -= 1;
69 return Some((key, value));
71 }
72 } else {
73 return Some((key, value));
74 }
75 } else {
76 return None;
78 }
79 }
80
81 return None;
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88 use std::rc::Rc;
89
90 #[test]
91 fn test_basic_insertion_and_eviction() {
92 let mut lru = LRU {
93 list: LinkedList::new(),
94 map: HashMap::new(),
95 num_items: 0,
96 max_items: 3,
97 };
98
99 assert!(lru.push(Rc::new(1), Rc::new("a")).is_none());
101 assert!(lru.push(Rc::new(2), Rc::new("b")).is_none());
102 assert!(lru.push(Rc::new(3), Rc::new("c")).is_none());
103
104 assert_eq!(lru.num_items, 3);
106
107 let evicted = lru.push(Rc::new(4), Rc::new("d")).unwrap();
109 assert_eq!(*evicted.0, 1); assert_eq!(lru.num_items, 3);
113 assert!(lru.map.contains_key(&Rc::new(2)));
114 assert!(lru.map.contains_key(&Rc::new(3)));
115 assert!(lru.map.contains_key(&Rc::new(4)));
116 }
117
118 #[test]
119 fn test_reinsertion_of_existing_key() {
120 let mut lru = LRU {
121 list: LinkedList::new(),
122 map: HashMap::new(),
123 num_items: 0,
124 max_items: 3,
125 };
126
127 let key = Rc::new(1);
128 let value = Rc::new("a");
129
130 lru.push(key.clone(), value.clone());
131 lru.push(Rc::new(2), Rc::new("b"));
132 lru.push(Rc::new(3), Rc::new("c"));
133
134 lru.push(key.clone(), value.clone());
136
137 let evicted = lru.push(Rc::new(4), Rc::new("d")).unwrap();
139 assert_eq!(*evicted.0, 2); assert_eq!(lru.num_items, 3);
143 assert!(lru.map.contains_key(&key));
144 assert!(lru.map.contains_key(&Rc::new(3)));
145 assert!(lru.map.contains_key(&Rc::new(4)));
146 }
147
148 #[test]
149 fn test_gc_with_reference_counts() {
150 let mut lru = LRU {
151 list: LinkedList::new(),
152 map: HashMap::new(),
153 num_items: 0,
154 max_items: 2,
155 };
156
157 let key1 = Rc::new(1);
158 let value1 = Rc::new("a");
159 lru.push(key1.clone(), value1.clone());
160
161 let key2 = Rc::new(2);
162 let value2 = Rc::new("b");
163 lru.push(key2.clone(), value2.clone());
164
165 let _key1_ref = Rc::clone(&key1);
167 let _value1_ref = Rc::clone(&value1);
168
169 let key3 = Rc::new(3);
170 let value3 = Rc::new("c");
171
172 let evicted = lru.push(key3.clone(), value3.clone());
174 assert!(evicted.is_none()); drop(value2);
178
179 let evicted = lru.push(Rc::new(4), Rc::new("d")).unwrap();
181 assert_eq!(*evicted.0, 2); assert_eq!(lru.num_items, 3);
185 assert!(lru.map.contains_key(&Rc::new(1)));
186 assert!(lru.map.contains_key(&Rc::new(3)));
187 assert!(lru.map.contains_key(&Rc::new(4)));
188 }
189
190 #[test]
191 fn test_handling_empty_lru() {
192 let mut lru = LRU {
193 list: LinkedList::new(),
194 map: HashMap::new(),
195 num_items: 0,
196 max_items: 2,
197 };
198
199 let evicted = lru.gc();
201 assert!(evicted.is_none());
202
203 lru.push(Rc::new(1), Rc::new("a"));
205 let evicted = lru.push(Rc::new(2), Rc::new("b"));
206 assert!(evicted.is_none());
207
208 let _ = lru.push(Rc::new(3), Rc::new("c"));
210 let _ = lru.push(Rc::new(4), Rc::new("d"));
211 assert_eq!(lru.num_items, 2);
212 }
213
214 #[test]
215 fn test_push_new_item() {
216 let mut lru = LRU::new(2);
217 let key = Rc::new(1);
218 let value = Rc::new("a");
219
220 let evicted = lru.push(key.clone(), value.clone());
221 assert!(evicted.is_none());
222 assert_eq!(lru.num_items, 1);
223 assert!(lru.map.contains_key(&key));
224 }
225
226 #[test]
227 fn test_eviction() {
228 let mut lru = LRU::new(2);
229 let key1 = Rc::new(1);
230 let key2 = Rc::new(2);
231 let key3 = Rc::new(3);
232 let value1 = Rc::new("a");
233 let value2 = Rc::new("b");
234 let value3 = Rc::new("c");
235
236 lru.push(key1, value1);
237 lru.push(key2.clone(), value2.clone());
238 let evicted = lru.push(key3.clone(), value3.clone());
239
240 assert!(evicted.is_some());
241 let (evicted_key, evicted_value) = evicted.unwrap();
242 assert_eq!(*evicted_key, 1);
243 assert_eq!(*evicted_value, "a");
244 assert_eq!(lru.num_items, 2);
245 assert!(lru.map.contains_key(&key2));
246 assert!(lru.map.contains_key(&key3));
247 }
248
249 #[test]
250 fn test_reference_count_handling() {
251 let mut lru = LRU::new(1);
252 let key: Rc<i32> = Rc::new(1);
253 let value = Rc::new("a");
254
255 {
256 let key_ref = key.clone();
257 let value_ref = value.clone();
258 lru.push(key_ref, value_ref);
259 assert_eq!(Rc::strong_count(&key), 3);
260 assert_eq!(Rc::strong_count(&value), 3);
261 }
262
263 let evicted = lru.push(key.clone(), value.clone());
264 assert!(evicted.is_none());
265 assert_eq!(Rc::strong_count(&key), 4);
266 assert_eq!(Rc::strong_count(&value), 4);
267 }
268
269 #[test]
270 fn test_gc_on_empty_list() {
271 let mut lru = LRU::<i32, Box<dyn std::any::Any>>::new(1);
272 let evicted = lru.gc();
273 assert!(evicted.is_none());
274 }
275
276 fn setup_lru(max_items: usize) -> LRU<i32, i32> {
277 LRU {
278 list: LinkedList::new(),
279 map: HashMap::new(),
280 num_items: 0,
281 max_items,
282 }
283 }
284
285 #[test]
286 fn test_push_new_element() {
287 let mut lru = setup_lru(2);
288 let key = Rc::new(1);
289 let value = Rc::new(10);
290
291 assert_eq!(lru.push(Rc::clone(&key), Rc::clone(&value)), None);
292 assert_eq!(lru.list.len(), 1);
293 assert_eq!(lru.map.len(), 1);
294 assert_eq!(lru.num_items, 1);
295 }
296
297 #[test]
298 fn test_push_existing_element() {
299 let mut lru = setup_lru(2);
300 let key = Rc::new(1);
301 let value = Rc::new(10);
302
303 lru.push(Rc::clone(&key), Rc::clone(&value));
304 assert_eq!(lru.push(Rc::clone(&key), Rc::clone(&value)), None);
305 assert_eq!(lru.list.len(), 2);
306 assert_eq!(lru.map.len(), 1);
307 assert_eq!(lru.num_items, 1);
308 }
309
310 #[test]
311 fn test_gc_multiple_references() {
312 let mut lru = setup_lru(2);
313 let key1 = Rc::new(1);
314 let value1 = Rc::new(10);
315 let key2 = Rc::new(2);
316 let value2 = Rc::new(20);
317
318 lru.push(Rc::clone(&key1), Rc::clone(&value1));
319 lru.push(Rc::clone(&key2), Rc::clone(&value2));
320 lru.push(Rc::clone(&key1), Rc::clone(&value1)); assert_eq!(lru.gc(), None); assert_eq!(lru.list.len(), 3);
324 assert_eq!(lru.map.len(), 2);
325 assert_eq!(lru.num_items, 2);
326 }
327
328 #[test]
329 fn test_push_and_retrieve() {
330 let mut lru = LRU {
331 list: LinkedList::new(),
332 map: HashMap::new(),
333 num_items: 0,
334 max_items: 3,
335 };
336
337 let key1 = Rc::new(1);
338 let value1 = Rc::new("a");
339 let key2 = Rc::new(2);
340 let value2 = Rc::new("b");
341 let key3 = Rc::new(3);
342 let value3 = Rc::new("c");
343
344 lru.push(key1.clone(), value1.clone());
345 lru.push(key2.clone(), value2.clone());
346 lru.push(key3.clone(), value3.clone());
347
348 assert_eq!(lru.num_items, 3);
349 assert!(lru.map.contains_key(&key1));
350 assert!(lru.map.contains_key(&key2));
351 assert!(lru.map.contains_key(&key3));
352 }
353
354 #[test]
355 fn test_eviction_policy() {
356 let mut lru = LRU {
357 list: LinkedList::new(),
358 map: HashMap::new(),
359 num_items: 0,
360 max_items: 2,
361 };
362
363 let key1 = Rc::new(1);
364 let value1 = Rc::new("a");
365 let key2 = Rc::new(2);
366 let value2 = Rc::new("b");
367 let key3 = Rc::new(3);
368 let value3 = Rc::new("c");
369
370 lru.push(key1.clone(), value1.clone());
371 lru.push(key2.clone(), value2.clone());
372 let evicted = lru.push(key3.clone(), value3.clone());
373
374 assert_eq!(lru.num_items, 3);
375 assert!(lru.map.contains_key(&key1));
376 assert!(lru.map.contains_key(&key2));
377 assert!(lru.map.contains_key(&key3));
378 assert_eq!(evicted, None);
379 }
380
381 #[test]
382 fn test_multiple_references() {
383 let mut lru = LRU {
384 list: LinkedList::new(),
385 map: HashMap::new(),
386 num_items: 0,
387 max_items: 2,
388 };
389
390 let key1 = Rc::new(1);
391 let value1 = Rc::new("a");
392
393 lru.push(key1.clone(), value1.clone());
394 lru.push(key1.clone(), value1.clone());
395
396 assert_eq!(lru.num_items, 1);
397 assert_eq!(lru.list.len(), 2);
398 assert_eq!(lru.map.get(&key1).unwrap().1, 2);
399 }
400
401 #[test]
402 fn test_eviction_with_external_references() {
403 let mut lru = LRU {
404 list: LinkedList::new(),
405 map: HashMap::new(),
406 num_items: 0,
407 max_items: 1,
408 };
409
410 let key1 = Rc::new(1);
411 let value1 = Rc::new("a");
412 let key2 = Rc::new(2);
413 let value2 = Rc::new("b");
414
415 lru.push(key1, value1);
416 let evicted = lru.push(key2.clone(), value2.clone());
417
418 assert_eq!(lru.num_items, 1);
419 assert!(lru.map.contains_key(&key2));
420 assert_eq!(evicted, Some((Rc::new(1), Rc::new("a"))));
421 }
422
423 #[test]
424 fn test_gc_behavior() {
425 let mut lru = LRU {
426 list: LinkedList::new(),
427 map: HashMap::new(),
428 num_items: 0,
429 max_items: 1,
430 };
431
432 let key1 = Rc::new(1);
433 let value1 = Rc::new("a");
434 let key2 = Rc::new(2);
435 let value2 = Rc::new("b");
436
437 lru.push(key1.clone(), value1.clone());
438 lru.push(key2.clone(), value2.clone());
439
440 let gc_result = lru.gc();
441
442 assert!(gc_result.is_none());
443 assert_eq!(lru.num_items, 2);
444 assert!(lru.map.contains_key(&key1));
445 assert!(lru.map.contains_key(&key2));
446 }
447
448 #[test]
449 fn test_push_within_limit() {
450 let mut lru = LRU::new(3);
451 let k1 = Rc::new(1);
452 let v1 = Rc::new(10);
453 assert_eq!(lru.push(Rc::clone(&k1), Rc::clone(&v1)), None);
454 assert_eq!(lru.num_items, 1);
455 }
456
457 #[test]
458 fn test_push_eviction() {
459 let mut lru = LRU::new(2);
460 let k1 = Rc::new(1);
461 let v1 = Rc::new(10);
462 let k2 = Rc::new(2);
463 let v2 = Rc::new(20);
464 let k3 = Rc::new(3);
465 let v3 = Rc::new(30);
466
467 lru.push(k1, v1);
468 lru.push(Rc::clone(&k2), Rc::clone(&v2));
469 let evicted = lru.push(Rc::clone(&k3), Rc::clone(&v3));
470 assert!(evicted.is_some());
471 assert_eq!(*evicted.unwrap().0, 1);
472 assert_eq!(lru.num_items, 2);
473 }
474
475 #[test]
476 fn test_gc_no_eviction() {
477 let mut lru = LRU::new(3);
478 let k1 = Rc::new(1);
479 let v1 = Rc::new(10);
480 lru.push(Rc::clone(&k1), Rc::clone(&v1));
481 assert_eq!(lru.gc(), None);
482 }
483
484 #[test]
485 fn test_gc_with_eviction() {
486 let mut lru = LRU::new(1);
487 let k1 = Rc::new(1);
488 let v1 = Rc::new(10);
489 let k2 = Rc::new(2);
490 let v2 = Rc::new(20);
491
492 lru.push(Rc::clone(&k1), Rc::clone(&v1));
493 lru.push(Rc::clone(&k2), Rc::clone(&v2));
494
495 drop(v1);
496
497 let evicted = lru.gc();
498
499 assert!(evicted.is_some());
500 assert_eq!(*evicted.unwrap().0, 1);
501 }
502}