1use std::{
2 hash::{
3 Hash,
4 Hasher,
5 },
6 rc::Rc,
7};
8
9use rustc_hash::{
10 FxHashMap,
11 FxHasher,
12};
13use smallvec::SmallVec;
14
15pub struct LRUCache<V, ID: Hash> {
16 map: FxHashMap<u64, (i32, Rc<V>)>,
17 pub users: FxHashMap<ID, SmallVec<[u64; 2]>>,
18}
19
20impl<V, ID: Hash> Default for LRUCache<V, ID> {
21 fn default() -> Self {
22 Self {
23 map: FxHashMap::default(),
24 users: FxHashMap::default(),
25 }
26 }
27}
28
29impl<V, ID: Hash + Eq> LRUCache<V, ID> {
30 pub fn get<H: Hash>(&self, hash_value: &H) -> Option<Rc<V>> {
31 let mut hasher = FxHasher::default();
32 hash_value.hash(&mut hasher);
33 let hash = hasher.finish();
34 let value = self.map.get(&hash);
35
36 value.as_ref().map(|v| v.1.clone())
37 }
38
39 pub fn utilize<H: Hash>(&mut self, id: ID, hash_value: &H) -> Option<Rc<V>> {
40 let mut hasher = FxHasher::default();
41 hash_value.hash(&mut hasher);
42 let hash = hasher.finish();
43 let mut value = self.map.get_mut(&hash);
44
45 let cache_value = value.as_ref().map(|v| v.1.clone());
46
47 let hashes = self.users.entry(id).or_default();
48
49 if !hashes.contains(&hash) {
51 if let Some(value) = &mut value {
52 value.0 += 1;
53 hashes.push(hash);
54 }
55
56 let index = match hashes.len() {
57 ..=1 => 0,
58 2 => 1,
59 len => len - 2,
60 };
61 for old_hash in hashes.drain(0..index) {
63 let Some(entry) = self.map.get_mut(&old_hash) else {
64 continue;
65 };
66
67 entry.0 -= 1;
68
69 if entry.0 == 0 {
70 self.map.remove(&old_hash);
71 }
72 }
73 }
74
75 cache_value
76 }
77
78 pub fn insert<H: Hash>(&mut self, id: ID, hash_value: &H, value: V) -> Rc<V> {
79 let mut hasher = FxHasher::default();
80 hash_value.hash(&mut hasher);
81 let hash = hasher.finish();
82 let value = Rc::new(value);
83
84 self.map.entry(hash).or_insert_with(|| (0, value.clone()));
85
86 let user_hashes = self.users.entry(id).or_default();
87 if !user_hashes.contains(&hash) {
88 user_hashes.push(hash);
89 self.map.get_mut(&hash).unwrap().0 += 1;
90 }
91
92 value
93 }
94
95 pub fn remove(&mut self, id: &ID) {
96 let Some(hashes) = self.users.remove(id) else {
97 return;
98 };
99
100 for hash in hashes.iter() {
101 let Some(entry) = self.map.get_mut(hash) else {
102 continue;
103 };
104
105 entry.0 -= 1;
106
107 if entry.0 == 0 {
108 self.map.remove(hash);
109 }
110 }
111 }
112
113 pub fn reset(&mut self) {
114 self.map.clear();
115 self.users.clear();
116 }
117
118 pub fn print_metrics(&self) {
119 println!("Cached Values {}", self.map.len());
120 println!("Cache Users {}", self.users.len());
121 }
122}
123
124#[cfg(test)]
125mod test {
126 use std::rc::Rc;
127
128 use crate::lru_cache::LRUCache;
129
130 #[test]
131 fn lru_cache() {
132 let mut cache = LRUCache::<i32, u64>::default();
133
134 cache
135 .utilize(1, &50)
136 .unwrap_or_else(|| cache.insert(1, &50, 5000));
137
138 assert_eq!(cache.utilize(1, &50), Some(Rc::new(5000)));
139
140 cache
141 .utilize(1, &60)
142 .unwrap_or_else(|| cache.insert(1, &60, 6000));
143 assert_eq!(cache.utilize(1, &60), Some(Rc::new(6000)));
144 assert_eq!(cache.utilize(1, &50), Some(Rc::new(5000)));
145
146 cache
147 .utilize(1, &70)
148 .unwrap_or_else(|| cache.insert(1, &70, 7000));
149 assert!(cache.get(&50).is_none());
150
151 assert_eq!(cache.utilize(1, &60), Some(Rc::new(6000)));
152 assert_eq!(cache.utilize(1, &70), Some(Rc::new(7000)));
153 assert_eq!(cache.utilize(1, &60), Some(Rc::new(6000)));
154 assert_eq!(cache.utilize(1, &70), Some(Rc::new(7000)));
155
156 cache.remove(&1);
157 assert!(cache.get(&60).is_none());
158 assert!(cache.get(&70).is_none());
159
160 cache
161 .utilize(1, &70)
162 .unwrap_or_else(|| cache.insert(1, &70, 7000));
163 assert!(cache.utilize(2, &70).is_some());
164
165 cache.remove(&1);
166 assert!(cache.get(&70).is_some());
167 cache.remove(&2);
168 assert!(cache.get(&70).is_none());
169 }
170}