1 use std::{ 2 borrow::Borrow, 3 fmt, 4 hash::{BuildHasher, Hash}, 5 usize, 6 }; 7 8 use hashbrown::hash_map; 9 10 use crate::linked_hash_map::{self, LinkedHashMap}; 11 12 pub use crate::linked_hash_map::{ 13 Drain, Entry, IntoIter, Iter, IterMut, OccupiedEntry, RawEntryBuilder, RawEntryBuilderMut, 14 RawOccupiedEntryMut, RawVacantEntryMut, VacantEntry, 15 }; 16 17 pub struct LruCache<K, V, S = hash_map::DefaultHashBuilder> { 18 map: LinkedHashMap<K, V, S>, 19 max_size: usize, 20 } 21 22 impl<K: Eq + Hash, V> LruCache<K, V> { 23 #[inline] new(capacity: usize) -> Self24 pub fn new(capacity: usize) -> Self { 25 LruCache { 26 map: LinkedHashMap::new(), 27 max_size: capacity, 28 } 29 } 30 31 /// Create a new unbounded `LruCache` that does not automatically evict entries. 32 /// 33 /// A simple convenience method that is equivalent to `LruCache::new(usize::MAX)` 34 #[inline] new_unbounded() -> Self35 pub fn new_unbounded() -> Self { 36 LruCache::new(usize::MAX) 37 } 38 } 39 40 impl<K, V, S> LruCache<K, V, S> { 41 #[inline] with_hasher(capacity: usize, hash_builder: S) -> Self42 pub fn with_hasher(capacity: usize, hash_builder: S) -> Self { 43 LruCache { 44 map: LinkedHashMap::with_hasher(hash_builder), 45 max_size: capacity, 46 } 47 } 48 49 #[inline] capacity(&self) -> usize50 pub fn capacity(&self) -> usize { 51 self.max_size 52 } 53 54 #[inline] len(&self) -> usize55 pub fn len(&self) -> usize { 56 self.map.len() 57 } 58 59 #[inline] is_empty(&self) -> bool60 pub fn is_empty(&self) -> bool { 61 self.map.is_empty() 62 } 63 64 #[inline] clear(&mut self)65 pub fn clear(&mut self) { 66 self.map.clear(); 67 } 68 69 #[inline] iter(&self) -> Iter<K, V>70 pub fn iter(&self) -> Iter<K, V> { 71 self.map.iter() 72 } 73 74 #[inline] iter_mut(&mut self) -> IterMut<K, V>75 pub fn iter_mut(&mut self) -> IterMut<K, V> { 76 self.map.iter_mut() 77 } 78 79 #[inline] drain(&mut self) -> Drain<K, V>80 pub fn drain(&mut self) -> Drain<K, V> { 81 self.map.drain() 82 } 83 } 84 85 impl<K: Eq + Hash, V, S> LruCache<K, V, S> 86 where 87 S: BuildHasher, 88 { 89 #[inline] contains_key<Q>(&mut self, key: &Q) -> bool where K: Borrow<Q>, Q: Hash + Eq + ?Sized,90 pub fn contains_key<Q>(&mut self, key: &Q) -> bool 91 where 92 K: Borrow<Q>, 93 Q: Hash + Eq + ?Sized, 94 { 95 self.get_mut(key).is_some() 96 } 97 98 /// Insert a new value into the `LruCache`. 99 /// 100 /// If necessary, will remove the value at the front of the LRU list to make room. 101 #[inline] insert(&mut self, k: K, v: V) -> Option<V>102 pub fn insert(&mut self, k: K, v: V) -> Option<V> { 103 let old_val = self.map.insert(k, v); 104 if self.len() > self.capacity() { 105 self.remove_lru(); 106 } 107 old_val 108 } 109 110 /// Get the value for the given key, *without* marking the value as recently used and moving it 111 /// to the back of the LRU list. 112 #[inline] peek<Q>(&self, k: &Q) -> Option<&V> where K: Borrow<Q>, Q: Hash + Eq + ?Sized,113 pub fn peek<Q>(&self, k: &Q) -> Option<&V> 114 where 115 K: Borrow<Q>, 116 Q: Hash + Eq + ?Sized, 117 { 118 self.map.get(k) 119 } 120 121 /// Get the value for the given key mutably, *without* marking the value as recently used and 122 /// moving it to the back of the LRU list. 123 #[inline] peek_mut<Q>(&mut self, k: &Q) -> Option<&mut V> where K: Borrow<Q>, Q: Hash + Eq + ?Sized,124 pub fn peek_mut<Q>(&mut self, k: &Q) -> Option<&mut V> 125 where 126 K: Borrow<Q>, 127 Q: Hash + Eq + ?Sized, 128 { 129 self.map.get_mut(k) 130 } 131 132 /// Retrieve the given key, marking it as recently used and moving it to the back of the LRU 133 /// list. 134 #[inline] get<Q>(&mut self, k: &Q) -> Option<&V> where K: Borrow<Q>, Q: Hash + Eq + ?Sized,135 pub fn get<Q>(&mut self, k: &Q) -> Option<&V> 136 where 137 K: Borrow<Q>, 138 Q: Hash + Eq + ?Sized, 139 { 140 self.get_mut(k).map(|v| &*v) 141 } 142 143 /// Retrieve the given key, marking it as recently used and moving it to the back of the LRU 144 /// list. 145 #[inline] get_mut<Q>(&mut self, k: &Q) -> Option<&mut V> where K: Borrow<Q>, Q: Hash + Eq + ?Sized,146 pub fn get_mut<Q>(&mut self, k: &Q) -> Option<&mut V> 147 where 148 K: Borrow<Q>, 149 Q: Hash + Eq + ?Sized, 150 { 151 match self.map.raw_entry_mut().from_key(k) { 152 linked_hash_map::RawEntryMut::Occupied(mut occupied) => { 153 occupied.to_back(); 154 Some(occupied.into_mut()) 155 } 156 linked_hash_map::RawEntryMut::Vacant(_) => None, 157 } 158 } 159 160 /// If the returned entry is vacant, it will always have room to insert a single value. By 161 /// using the entry API, you can exceed the configured capacity by 1. 162 /// 163 /// The returned entry is not automatically moved to the back of the LRU list. By calling 164 /// `Entry::to_back` / `Entry::to_front` you can manually control the position of this entry in 165 /// the LRU list. 166 #[inline] entry(&mut self, key: K) -> Entry<'_, K, V, S>167 pub fn entry(&mut self, key: K) -> Entry<'_, K, V, S> { 168 if self.len() > self.capacity() { 169 self.remove_lru(); 170 } 171 self.map.entry(key) 172 } 173 174 /// The constructed raw entry is never automatically moved to the back of the LRU list. By 175 /// calling `Entry::to_back` / `Entry::to_front` you can manually control the position of this 176 /// entry in the LRU list. 177 #[inline] raw_entry(&self) -> RawEntryBuilder<'_, K, V, S>178 pub fn raw_entry(&self) -> RawEntryBuilder<'_, K, V, S> { 179 self.map.raw_entry() 180 } 181 182 /// If the constructed raw entry is vacant, it will always have room to insert a single value. 183 /// By using the raw entry API, you can exceed the configured capacity by 1. 184 /// 185 /// The constructed raw entry is never automatically moved to the back of the LRU list. By 186 /// calling `Entry::to_back` / `Entry::to_front` you can manually control the position of this 187 /// entry in the LRU list. 188 #[inline] raw_entry_mut(&mut self) -> RawEntryBuilderMut<'_, K, V, S>189 pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut<'_, K, V, S> { 190 if self.len() > self.capacity() { 191 self.remove_lru(); 192 } 193 self.map.raw_entry_mut() 194 } 195 196 #[inline] remove<Q>(&mut self, k: &Q) -> Option<V> where K: Borrow<Q>, Q: Hash + Eq + ?Sized,197 pub fn remove<Q>(&mut self, k: &Q) -> Option<V> 198 where 199 K: Borrow<Q>, 200 Q: Hash + Eq + ?Sized, 201 { 202 self.map.remove(k) 203 } 204 205 #[inline] remove_entry<Q>(&mut self, k: &Q) -> Option<(K, V)> where K: Borrow<Q>, Q: Hash + Eq + ?Sized,206 pub fn remove_entry<Q>(&mut self, k: &Q) -> Option<(K, V)> 207 where 208 K: Borrow<Q>, 209 Q: Hash + Eq + ?Sized, 210 { 211 self.map.remove_entry(k) 212 } 213 214 /// Set the new cache capacity for the `LruCache`. 215 /// 216 /// If there are more entries in the `LruCache` than the new capacity will allow, they are 217 /// removed. 218 #[inline] set_capacity(&mut self, capacity: usize)219 pub fn set_capacity(&mut self, capacity: usize) { 220 for _ in capacity..self.len() { 221 self.remove_lru(); 222 } 223 self.max_size = capacity; 224 } 225 226 /// Remove the least recently used entry and return it. 227 /// 228 /// If the `LruCache` is empty this will return None. 229 #[inline] remove_lru(&mut self) -> Option<(K, V)>230 pub fn remove_lru(&mut self) -> Option<(K, V)> { 231 self.map.pop_front() 232 } 233 } 234 235 impl<K: Hash + Eq + Clone, V: Clone, S: BuildHasher + Clone> Clone for LruCache<K, V, S> { 236 #[inline] clone(&self) -> Self237 fn clone(&self) -> Self { 238 LruCache { 239 map: self.map.clone(), 240 max_size: self.max_size, 241 } 242 } 243 } 244 245 impl<K: Eq + Hash, V, S: BuildHasher> Extend<(K, V)> for LruCache<K, V, S> { 246 #[inline] extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I)247 fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) { 248 for (k, v) in iter { 249 self.insert(k, v); 250 } 251 } 252 } 253 254 impl<K, V, S> IntoIterator for LruCache<K, V, S> { 255 type Item = (K, V); 256 type IntoIter = IntoIter<K, V>; 257 258 #[inline] into_iter(self) -> IntoIter<K, V>259 fn into_iter(self) -> IntoIter<K, V> { 260 self.map.into_iter() 261 } 262 } 263 264 impl<'a, K, V, S> IntoIterator for &'a LruCache<K, V, S> { 265 type Item = (&'a K, &'a V); 266 type IntoIter = Iter<'a, K, V>; 267 268 #[inline] into_iter(self) -> Iter<'a, K, V>269 fn into_iter(self) -> Iter<'a, K, V> { 270 self.iter() 271 } 272 } 273 274 impl<'a, K, V, S> IntoIterator for &'a mut LruCache<K, V, S> { 275 type Item = (&'a K, &'a mut V); 276 type IntoIter = IterMut<'a, K, V>; 277 278 #[inline] into_iter(self) -> IterMut<'a, K, V>279 fn into_iter(self) -> IterMut<'a, K, V> { 280 self.iter_mut() 281 } 282 } 283 284 impl<K, V, S> fmt::Debug for LruCache<K, V, S> 285 where 286 K: fmt::Debug, 287 V: fmt::Debug, 288 { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result289 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 290 f.debug_map().entries(self.iter().rev()).finish() 291 } 292 } 293