1use crate::linked_list::{LinkedList, ListCursor};
2use std::{collections::HashMap, fmt::Debug, hash::Hash};
3
4pub struct LRU<Key: Copy + Debug + Eq + Hash, Value> {
7 lru_list: LinkedList<(Key, Value)>,
8 access_map: HashMap<Key, ListCursor<(Key, Value)>>,
9 capacity: usize,
10}
11
12impl<Key: Copy + Debug + Eq + Hash, Value> LRU<Key, Value> {
13 pub fn new_with_capacity(capacity: usize) -> Self {
14 debug_assert!(capacity > 0);
15 let storage = LinkedList::new();
16 let indices = HashMap::with_capacity(capacity);
17 LRU {
18 lru_list: storage,
19 access_map: indices,
20 capacity,
21 }
22 }
23
24 pub fn push(&mut self, key: &Key, value: Value) {
25 debug_assert!(self.lru_list.len() <= self.capacity);
26 debug_assert!(!self.access_map.contains_key(key));
27 if self.access_map.len() == self.capacity {
28 debug_assert!(!self.access_map.is_empty());
30 let evicted = self.lru_list.pop_back();
31 let evicted_key = &evicted.unwrap().0;
32 self.access_map.remove(evicted_key);
33 }
34 let handle = self.lru_list.push_front((*key, value));
35 self.access_map.insert(*key, handle);
36 }
37
38 pub fn contains(&self, key: &Key) -> bool {
39 self.access_map.contains_key(key)
40 }
41
42 pub fn get(&mut self, key: &Key) -> Option<&Value> {
43 if let Some(handle) = self.access_map.get(key) {
44 self.lru_list.move_to_front(handle);
45 return Some(&self.lru_list.get_front().1);
46 }
47 None
48 }
49
50 pub fn capacity(&self) -> usize {
51 self.capacity
52 }
53
54 pub fn len(&self) -> usize {
55 assert_eq!(self.lru_list.len(), self.access_map.len());
56 self.lru_list.len()
57 }
58
59 pub fn is_empty(&self) -> bool {
60 self.len() == 0
61 }
62
63 pub fn clear(&mut self) {
64 self.lru_list.clear();
65 self.access_map.clear();
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::LRU;
72
73 struct SomeTestStruct(i32);
74
75 #[test]
76 fn construct() {
77 let mut lru = LRU::new_with_capacity(10);
78 assert_eq!(0, lru.len());
79 lru.push(&1, SomeTestStruct(1));
80 assert_eq!(1, lru.len());
81 lru.push(&2, SomeTestStruct(2));
82 assert_eq!(2, lru.len());
83 lru.push(&3, SomeTestStruct(3));
84 assert_eq!(3, lru.len());
85 lru.push(&4, SomeTestStruct(4));
86 assert_eq!(4, lru.len());
87 lru.push(&5, SomeTestStruct(5));
88 assert_eq!(5, lru.len());
89 lru.push(&6, SomeTestStruct(6));
90 assert_eq!(6, lru.len());
91 lru.push(&7, SomeTestStruct(7));
92 assert_eq!(7, lru.len());
93 lru.push(&8, SomeTestStruct(8));
94 assert_eq!(8, lru.len());
95 lru.push(&9, SomeTestStruct(9));
96 assert_eq!(9, lru.len());
97 lru.push(&10, SomeTestStruct(10));
98 assert_eq!(10, lru.len());
99 assert_eq!(10, lru.capacity());
100
101 let handle = lru.get(&1).unwrap();
103 assert_eq!(1, handle.0);
104 lru.push(&11, SomeTestStruct(11));
106 assert!(!lru.contains(&2));
107 assert_eq!(lru.len(), 10);
108
109 let handle = lru.get(&2);
111 assert!(handle.is_none());
112
113 let keys = vec![1, 3, 4, 5, 6, 7, 8, 9, 10, 11];
115 keys.into_iter().for_each(|key| {
116 assert!(lru.contains(&key));
117 });
118 }
119
120 #[test]
121 fn clear_is_empty() {
122 let mut lru = LRU::new_with_capacity(10);
123 for i in [0, 1, 2, 3] {
124 lru.push(&i, 2 * i);
125 }
126 assert!(!lru.is_empty());
127 lru.clear();
128 assert!(lru.is_empty());
129 }
130}