1use std::borrow::Borrow;
2use std::hash::{BuildHasher, Hash};
3
4use foldhash::fast::RandomState;
5use hashbrown::HashTable;
6use hashbrown::hash_table::Entry;
7use slotmap::{Key, SlotMap, new_key_type};
8
9pub struct LruCachedFunc<T, R, F> {
11 func: F,
12 cache: LruCache<T, R>,
13}
14
15impl<T, R, F> LruCachedFunc<T, R, F>
16where
17 F: FnMut(T) -> R,
18 T: std::hash::Hash + Eq + Clone,
19 R: Copy,
20{
21 pub fn new(func: F, size: usize) -> Self {
22 Self {
23 func,
24 cache: LruCache::with_capacity(size),
25 }
26 }
27
28 pub fn eval(&mut self, x: T, use_cache: bool) -> R {
29 if use_cache {
30 *self
31 .cache
32 .get_or_insert_with(&x, |xr| (self.func)(xr.clone()))
33 } else {
34 (self.func)(x)
35 }
36 }
37}
38
39new_key_type! {
40 struct LruKey;
41}
42
43pub struct LruCache<K, V, S = RandomState> {
44 table: HashTable<LruKey>,
45 elements: SlotMap<LruKey, LruEntry<K, V>>,
46 max_capacity: usize,
47 most_recent: LruKey,
48 least_recent: LruKey,
49 build_hasher: S,
50}
51
52struct LruEntry<K, V> {
53 key: K,
54 value: V,
55 list: LruListNode,
56}
57
58#[derive(Copy, Clone, Default)]
59struct LruListNode {
60 more_recent: LruKey,
61 less_recent: LruKey,
62}
63
64impl<K, V> LruCache<K, V> {
65 pub fn with_capacity(capacity: usize) -> Self {
66 Self::with_capacity_and_hasher(capacity, RandomState::default())
67 }
68}
69
70impl<K, V, S> LruCache<K, V, S> {
71 pub fn with_capacity_and_hasher(max_capacity: usize, build_hasher: S) -> Self {
72 let max_capacity = max_capacity.max(1);
73 Self {
74 table: HashTable::with_capacity(max_capacity + 1),
77 elements: SlotMap::with_capacity_and_key(max_capacity + 1),
78 max_capacity,
79 most_recent: LruKey::null(),
80 least_recent: LruKey::null(),
81 build_hasher,
82 }
83 }
84
85 pub fn max_capacity(&self) -> usize {
86 self.max_capacity
87 }
88
89 pub fn len(&self) -> usize {
90 self.elements.len()
91 }
92
93 pub fn is_empty(&self) -> bool {
94 self.elements.is_empty()
95 }
96}
97
98impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
99 fn lru_list_unlink(&mut self, lru_key: LruKey) {
100 let list = self.elements[lru_key].list;
101 if let Some(more_recent) = self.elements.get_mut(list.more_recent) {
102 more_recent.list.less_recent = list.less_recent;
103 } else {
104 self.most_recent = list.less_recent;
105 }
106 if let Some(less_recent) = self.elements.get_mut(list.less_recent) {
107 less_recent.list.more_recent = list.more_recent;
108 } else {
109 self.least_recent = list.more_recent;
110 }
111 }
112
113 fn lru_list_insert_mru(&mut self, lru_key: LruKey) {
114 let prev_most_recent_key = self.most_recent;
115 self.most_recent = lru_key;
116 if let Some(prev_most_recent) = self.elements.get_mut(prev_most_recent_key) {
117 prev_most_recent.list.more_recent = lru_key;
118 } else {
119 self.least_recent = lru_key;
120 }
121 let list = &mut self.elements[lru_key].list;
122 list.more_recent = LruKey::null();
123 list.less_recent = prev_most_recent_key;
124 }
125
126 pub fn pop_lru(&mut self) -> Option<(K, V)> {
127 if self.elements.is_empty() {
128 return None;
129 }
130 let lru_key = self.least_recent;
131 let hash = self.build_hasher.hash_one(&self.elements[lru_key].key);
132 self.lru_list_unlink(lru_key);
133 let lru_entry = self.elements.remove(lru_key).unwrap();
134 self.table
135 .find_entry(hash, |k| *k == lru_key)
136 .unwrap()
137 .remove();
138 Some((lru_entry.key, lru_entry.value))
139 }
140
141 pub fn get<Q>(&mut self, key: &Q) -> Option<&V>
142 where
143 K: Borrow<Q>,
144 Q: Hash + Eq + ?Sized,
145 {
146 let hash = self.build_hasher.hash_one(key);
147 let lru_key = *self
148 .table
149 .find(hash, |lru_key| self.elements[*lru_key].key.borrow() == key)?;
150 self.lru_list_unlink(lru_key);
151 self.lru_list_insert_mru(lru_key);
152 let lru_node = self.elements.get(lru_key).unwrap();
153 Some(&lru_node.value)
154 }
155
156 pub fn insert(&mut self, key: K, value: V) -> Option<V> {
158 let hash = self.build_hasher.hash_one(&key);
159 match self.table.entry(
160 hash,
161 |lru_key| self.elements[*lru_key].key == key,
162 |lru_key| self.build_hasher.hash_one(&self.elements[*lru_key].key),
163 ) {
164 Entry::Occupied(o) => {
165 let lru_key = *o.get();
166 self.lru_list_unlink(lru_key);
167 self.lru_list_insert_mru(lru_key);
168 Some(core::mem::replace(&mut self.elements[lru_key].value, value))
169 },
170
171 Entry::Vacant(v) => {
172 let lru_entry = LruEntry {
173 key,
174 value,
175 list: LruListNode::default(),
176 };
177 let lru_key = self.elements.insert(lru_entry);
178 v.insert(lru_key);
179 self.lru_list_insert_mru(lru_key);
180 if self.elements.len() > self.max_capacity {
181 self.pop_lru();
182 }
183 None
184 },
185 }
186 }
187
188 pub fn get_or_insert_with<Q, F: FnOnce(&Q) -> V>(&mut self, key: &Q, f: F) -> &mut V
189 where
190 K: Borrow<Q>,
191 Q: Hash + Eq + ToOwned<Owned = K> + ?Sized,
192 {
193 enum Never {}
194 let Ok(ret) = self.try_get_or_insert_with::<Q, Never, _>(key, |k| Ok(f(k)));
195 ret
196 }
197
198 pub fn try_get_or_insert_with<Q, E, F: FnOnce(&Q) -> Result<V, E>>(
199 &mut self,
200 key: &Q,
201 f: F,
202 ) -> Result<&mut V, E>
203 where
204 K: Borrow<Q>,
205 Q: Hash + Eq + ToOwned<Owned = K> + ?Sized,
206 {
207 let hash = self.build_hasher.hash_one(key);
208 match self.table.entry(
209 hash,
210 |lru_key| self.elements[*lru_key].key.borrow() == key,
211 |lru_key| self.build_hasher.hash_one(&self.elements[*lru_key].key),
212 ) {
213 Entry::Occupied(o) => {
214 let lru_key = *o.get();
215 if lru_key != self.most_recent {
216 self.lru_list_unlink(lru_key);
217 self.lru_list_insert_mru(lru_key);
218 }
219 Ok(&mut self.elements[lru_key].value)
220 },
221
222 Entry::Vacant(v) => {
223 let lru_entry = LruEntry {
224 value: f(key)?,
225 key: key.to_owned(),
226 list: LruListNode::default(),
227 };
228 let lru_key = self.elements.insert(lru_entry);
229 v.insert(lru_key);
230 self.lru_list_insert_mru(lru_key);
231 if self.elements.len() > self.max_capacity {
232 self.pop_lru();
233 }
234 Ok(&mut self.elements[lru_key].value)
235 },
236 }
237 }
238}