1#![doc(
12 html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
13 html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
14 issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
15)]
16#![cfg_attr(not(test), warn(unused_crate_dependencies))]
17#![cfg_attr(docsrs, feature(doc_cfg))]
18#![no_std]
19
20extern crate alloc;
21
22use alloc::vec::Vec;
23use alloy_primitives::map::DefaultHashBuilder;
24use core::{
25 borrow::Borrow,
26 fmt,
27 hash::{BuildHasher, Hash},
28 iter::FusedIterator,
29 mem::{self, MaybeUninit},
30};
31use hashbrown::HashTable;
32
33const NONE: u32 = u32::MAX;
35
36const TABLE_SLACK: usize = 2;
41
42pub struct LruMap<K, V, S = DefaultHashBuilder> {
47 table: HashTable<u32>,
49 nodes: Vec<Node<K, V>>,
50 hasher: S,
51 max_length: u32,
52 len: u32,
53 newest: u32,
54 oldest: u32,
55 free: u32,
57}
58
59impl<K, V> LruMap<K, V> {
60 pub fn new(max_length: u32) -> Self {
63 Self::with_hasher(max_length, DefaultHashBuilder::default())
64 }
65}
66
67impl<K, V, S> LruMap<K, V, S> {
68 pub const fn with_hasher(max_length: u32, hasher: S) -> Self {
71 Self {
72 table: HashTable::new(),
73 nodes: Vec::new(),
74 hasher,
75 max_length,
76 len: 0,
77 newest: NONE,
78 oldest: NONE,
79 free: NONE,
80 }
81 }
82
83 pub const fn max_length(&self) -> u32 {
85 self.max_length
86 }
87
88 pub const fn len(&self) -> usize {
90 self.len as usize
91 }
92
93 pub const fn is_empty(&self) -> bool {
95 self.len == 0
96 }
97
98 pub fn memory_usage(&self) -> usize {
101 self.table.allocation_size() + self.nodes.capacity() * size_of::<Node<K, V>>()
102 }
103
104 pub fn peek_oldest(&self) -> Option<(&K, &V)> {
106 (self.oldest != NONE).then(|| self.entry(self.oldest))
107 }
108
109 pub fn peek_newest(&self) -> Option<(&K, &V)> {
111 (self.newest != NONE).then(|| self.entry(self.newest))
112 }
113
114 pub const fn iter(&self) -> Iter<'_, K, V, S> {
116 Iter { map: self, next: self.newest, remaining: self.len() }
117 }
118
119 pub fn clear(&mut self) {
121 self.table.clear();
122 let newest = mem::replace(&mut self.newest, NONE);
123 self.oldest = NONE;
124 self.free = NONE;
125 self.len = 0;
126 let mut nodes = mem::take(&mut self.nodes);
128 drop_linked(&mut nodes, newest);
129 nodes.clear();
130 self.nodes = nodes;
131 }
132
133 #[inline]
134 fn node(&self, index: u32) -> &Node<K, V> {
135 debug_assert!((index as usize) < self.nodes.len());
136 unsafe { self.nodes.get_unchecked(index as usize) }
138 }
139
140 #[inline]
141 fn node_mut(&mut self, index: u32) -> &mut Node<K, V> {
142 debug_assert!((index as usize) < self.nodes.len());
143 unsafe { self.nodes.get_unchecked_mut(index as usize) }
145 }
146
147 #[inline]
149 fn entry(&self, index: u32) -> (&K, &V) {
150 let node = self.node(index);
151 unsafe { (node.key.assume_init_ref(), node.value.assume_init_ref()) }
153 }
154
155 #[inline]
156 fn unlink(&mut self, index: u32) {
157 let Node { older, newer, .. } = *self.node(index);
158 if older == NONE {
159 self.oldest = newer
160 } else {
161 self.node_mut(older).newer = newer
162 }
163 if newer == NONE {
164 self.newest = older
165 } else {
166 self.node_mut(newer).older = older
167 }
168 }
169
170 #[inline]
171 fn link_newest(&mut self, index: u32) {
172 let prev = self.newest;
173 let node = self.node_mut(index);
174 node.older = prev;
175 node.newer = NONE;
176 if prev == NONE {
177 self.oldest = index
178 } else {
179 self.node_mut(prev).newer = index
180 }
181 self.newest = index;
182 }
183
184 #[inline]
185 fn promote(&mut self, index: u32) {
186 if self.newest != index {
187 self.unlink(index);
188 self.link_newest(index);
189 }
190 }
191}
192
193impl<K, V, S> LruMap<K, V, S>
194where
195 K: Hash + Eq,
196 S: BuildHasher,
197{
198 #[inline]
200 pub fn get<Q>(&mut self, key: &Q) -> Option<&mut V>
201 where
202 K: Borrow<Q>,
203 Q: Hash + Eq + ?Sized,
204 {
205 let index = self.find(key)?;
206 self.promote(index);
207 Some(unsafe { self.node_mut(index).value.assume_init_mut() })
209 }
210
211 #[inline]
213 pub fn peek<Q>(&self, key: &Q) -> Option<&V>
214 where
215 K: Borrow<Q>,
216 Q: Hash + Eq + ?Sized,
217 {
218 self.find(key).map(|index| self.entry(index).1)
219 }
220
221 #[inline]
223 pub fn peek_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
224 where
225 K: Borrow<Q>,
226 Q: Hash + Eq + ?Sized,
227 {
228 let index = self.find(key)?;
229 Some(unsafe { self.node_mut(index).value.assume_init_mut() })
231 }
232
233 #[inline]
235 pub fn contains<Q>(&self, key: &Q) -> bool
236 where
237 K: Borrow<Q>,
238 Q: Hash + Eq + ?Sized,
239 {
240 self.find(key).is_some()
241 }
242
243 #[inline]
249 pub fn insert(&mut self, key: K, value: V) -> Option<(K, V)> {
250 let hash = self.hasher.hash_one(&key);
251 if let Some(index) = self.find_hashed(hash, &key) {
252 self.promote(index);
253 *unsafe { self.node_mut(index).value.assume_init_mut() } = value;
255 return None
256 }
257 self.insert_new(hash, key, value).1
258 }
259
260 #[inline]
265 pub fn get_or_insert(&mut self, key: K, f: impl FnOnce() -> V) -> Option<&mut V> {
266 let hash = self.hasher.hash_one(&key);
267 let index = if let Some(index) = self.find_hashed(hash, &key) {
268 self.promote(index);
269 index
270 } else {
271 let index = self.insert_new(hash, key, f()).0;
272 if index == NONE {
273 return None
274 }
275 index
276 };
277 Some(unsafe { self.node_mut(index).value.assume_init_mut() })
279 }
280
281 #[inline]
283 pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
284 where
285 K: Borrow<Q>,
286 Q: Hash + Eq + ?Sized,
287 {
288 let index = self.find(key)?;
289 Some(self.take(index).1)
290 }
291
292 #[inline]
294 pub fn pop_oldest(&mut self) -> Option<(K, V)> {
295 (self.oldest != NONE).then(|| self.take(self.oldest))
296 }
297
298 #[inline]
299 fn find<Q>(&self, key: &Q) -> Option<u32>
300 where
301 K: Borrow<Q>,
302 Q: Hash + Eq + ?Sized,
303 {
304 self.find_hashed(self.hasher.hash_one(key), key)
305 }
306
307 #[inline]
308 fn find_hashed<Q>(&self, hash: u64, key: &Q) -> Option<u32>
309 where
310 K: Borrow<Q>,
311 Q: Hash + Eq + ?Sized,
312 {
313 let nodes = &self.nodes;
314 self.table
315 .find(hash, |&index| {
316 let node = unsafe { nodes.get_unchecked(index as usize) };
318 unsafe { node.key.assume_init_ref() }.borrow() == key
319 })
320 .copied()
321 }
322
323 fn take(&mut self, index: u32) -> (K, V) {
326 let hash = self.hasher.hash_one(unsafe { self.node(index).key.assume_init_ref() });
329 match self.table.find_entry(hash, |&i| i == index) {
330 Ok(slot) => {
331 slot.remove();
332 }
333 Err(_) => self.table.retain(|&mut i| i != index),
336 }
337 self.unlink(index);
338 let free = self.free;
339 let node = self.node_mut(index);
340 node.newer = free;
341 let entry = unsafe { (node.key.assume_init_read(), node.value.assume_init_read()) };
343 self.free = index;
344 self.len -= 1;
345 entry
346 }
347
348 fn insert_new(&mut self, hash: u64, key: K, value: V) -> (u32, Option<(K, V)>) {
357 if self.max_length == 0 {
358 return (NONE, Some((key, value)))
359 }
360 let evicted = (self.len >= self.max_length).then(|| self.take(self.oldest));
361 let index = if self.free == NONE {
362 if self.nodes.len() == self.nodes.capacity() {
363 self.grow();
364 }
365 self.nodes.push(Node {
366 key: MaybeUninit::new(key),
367 value: MaybeUninit::new(value),
368 older: NONE,
369 newer: NONE,
370 });
371 self.nodes.len() as u32 - 1
372 } else {
373 let index = self.free;
374 let node = self.node_mut(index);
375 let next = node.newer;
376 node.key.write(key);
377 node.value.write(value);
378 self.free = next;
379 index
380 };
381 self.link_newest(index);
382 self.len += 1;
383 let (nodes, hasher) = (&self.nodes, &self.hasher);
384 self.table.insert_unique(hash, index, |&i| hash_node(hasher, nodes, i));
385 (index, evicted)
386 }
387
388 #[cold]
390 fn grow(&mut self) {
391 let target =
392 (self.nodes.len() * 2).clamp(4.min(self.max_length as usize), self.max_length as usize);
393 self.nodes.reserve_exact(target - self.nodes.len());
394 let (nodes, hasher) = (&self.nodes, &self.hasher);
395 let additional = target.saturating_mul(TABLE_SLACK).saturating_sub(self.table.len());
396 self.table.reserve(additional, |&i| hash_node(hasher, nodes, i));
397 }
398}
399
400impl<K, V, S: Default> Default for LruMap<K, V, S> {
401 fn default() -> Self {
403 Self::with_hasher(0, S::default())
404 }
405}
406
407impl<K, V, S> Drop for LruMap<K, V, S> {
408 fn drop(&mut self) {
409 drop_linked(&mut self.nodes, self.newest);
410 }
411}
412
413impl<K, V, S> fmt::Debug for LruMap<K, V, S> {
414 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
415 f.debug_struct("LruMap")
416 .field("len", &self.len)
417 .field("max_length", &self.max_length)
418 .finish_non_exhaustive()
419 }
420}
421
422impl<'a, K, V, S> IntoIterator for &'a LruMap<K, V, S> {
423 type Item = (&'a K, &'a V);
424 type IntoIter = Iter<'a, K, V, S>;
425
426 fn into_iter(self) -> Self::IntoIter {
427 self.iter()
428 }
429}
430
431#[derive(Debug)]
433pub struct Iter<'a, K, V, S> {
434 map: &'a LruMap<K, V, S>,
435 next: u32,
436 remaining: usize,
437}
438
439impl<'a, K, V, S> Iterator for Iter<'a, K, V, S> {
440 type Item = (&'a K, &'a V);
441
442 fn next(&mut self) -> Option<Self::Item> {
443 if self.next == NONE {
444 return None
445 }
446 let map = self.map;
447 let entry = map.entry(self.next);
448 self.next = map.node(self.next).older;
449 self.remaining -= 1;
450 Some(entry)
451 }
452
453 fn size_hint(&self) -> (usize, Option<usize>) {
454 (self.remaining, Some(self.remaining))
455 }
456}
457
458impl<K, V, S> ExactSizeIterator for Iter<'_, K, V, S> {}
459
460impl<K, V, S> FusedIterator for Iter<'_, K, V, S> {}
461
462struct Node<K, V> {
464 key: MaybeUninit<K>,
465 value: MaybeUninit<V>,
466 older: u32,
468 newer: u32,
470}
471
472fn drop_linked<K, V>(nodes: &mut [Node<K, V>], newest: u32) {
476 if !mem::needs_drop::<(K, V)>() {
477 return
478 }
479 let mut index = newest;
480 while index != NONE {
481 let node = &mut nodes[index as usize];
482 index = node.older;
483 unsafe {
486 node.key.assume_init_drop();
487 node.value.assume_init_drop();
488 }
489 }
490}
491
492#[inline]
494fn hash_node<K: Hash, V, S: BuildHasher>(hasher: &S, nodes: &[Node<K, V>], index: u32) -> u64 {
495 hasher.hash_one(unsafe { nodes.get_unchecked(index as usize).key.assume_init_ref() })
497}
498
499#[cfg(test)]
500mod tests {
501 use super::*;
502 use alloc::{
503 string::{String, ToString},
504 sync::Arc,
505 vec,
506 };
507
508 fn keys<K: Copy, V, S>(map: &LruMap<K, V, S>) -> Vec<K> {
509 map.iter().map(|(k, _)| *k).collect()
510 }
511
512 #[test]
513 fn evicts_least_recently_used() {
514 let mut map = LruMap::<u64, u64>::new(3);
515 assert_eq!(map.insert(1, 10), None);
516 assert_eq!(map.insert(2, 20), None);
517 assert_eq!(map.insert(3, 30), None);
518 assert_eq!(map.get(&1), Some(&mut 10));
519 assert_eq!(map.peek(&2), Some(&20));
520 assert_eq!(map.insert(4, 40), Some((2, 20)));
521 assert_eq!(keys(&map), [4, 1, 3]);
522 assert_eq!(map.peek_oldest(), Some((&3, &30)));
523 assert_eq!(map.peek_newest(), Some((&4, &40)));
524 assert_eq!(map.insert(3, 31), None);
525 assert_eq!(keys(&map), [3, 4, 1]);
526 assert_eq!(map.remove(&4), Some(40));
527 assert_eq!(map.get_or_insert(5, || 50), Some(&mut 50));
528 assert_eq!(map.get_or_insert(1, || 0), Some(&mut 10));
529 assert_eq!(keys(&map), [1, 5, 3]);
530 assert_eq!(map.pop_oldest(), Some((3, 31)));
531 assert_eq!(map.len(), 2);
532 assert_eq!(map.iter().len(), 2);
533 }
534
535 #[test]
536 fn zero_length_stores_nothing() {
537 let mut map = LruMap::<u64, u64>::default();
538 assert_eq!(map.insert(1, 1), Some((1, 1)));
539 assert_eq!(map.get_or_insert(1, || 1), None);
540 assert!(map.is_empty());
541 assert_eq!(map.memory_usage(), 0);
542 }
543
544 #[test]
545 fn borrowed_lookups() {
546 let mut map = LruMap::<String, u64>::new(2);
547 map.insert("a".to_string(), 1);
548 assert_eq!(map.get("a"), Some(&mut 1));
549 assert!(map.contains("a"));
550 assert_eq!(map.peek_mut("a"), Some(&mut 1));
551 assert_eq!(map.remove("a"), Some(1));
552 assert!(!map.contains("a"));
553 }
554
555 #[test]
556 fn never_grows_past_max_length() {
557 let mut map = LruMap::<u64, ()>::new(5);
558 for i in 0..100 {
559 map.insert(i, ());
560 if i % 7 == 6 {
561 map.remove(&(i - 1));
562 }
563 }
564 assert_eq!(map.nodes.capacity(), 5);
565 assert_eq!(map.len(), 5);
566 }
567
568 #[test]
571 fn drops_each_value_once() {
572 let token = Arc::new(());
573 {
574 let mut map = LruMap::<u64, Arc<()>>::new(4);
575 for i in 0..64u64 {
576 map.insert(i % 9, Arc::clone(&token));
577 if i % 3 == 0 {
578 map.remove(&(i % 7));
579 }
580 if i % 5 == 0 {
581 map.pop_oldest();
582 }
583 map.get_or_insert(i % 11, || Arc::clone(&token));
584 assert_eq!(Arc::strong_count(&token), 1 + map.len());
585 if i == 32 {
586 map.clear();
587 assert_eq!(Arc::strong_count(&token), 1);
588 }
589 }
590 }
591 assert_eq!(Arc::strong_count(&token), 1);
592 }
593
594 #[test]
596 fn matches_model() {
597 let steps = if cfg!(miri) { 2_000 } else { 100_000 };
598 for max_length in [1u32, 2, 3, 7, 64, 333] {
599 let mut map = LruMap::<u64, u64>::new(max_length);
600 let mut model: Vec<(u64, u64)> = vec![];
601 let mut x = 0x9e37_79b9_7f4a_7c15u64;
602 for step in 0..steps {
603 x ^= x << 13;
604 x ^= x >> 7;
605 x ^= x << 17;
606 let key = x % (max_length as u64 * 3 + 1);
607 let position = model.iter().position(|e| e.0 == key);
608 match x >> 61 {
609 0..=2 => {
610 let expected = match position {
611 Some(p) => {
612 model.remove(p);
613 None
614 }
615 None if model.len() == max_length as usize => model.pop(),
616 None => None,
617 };
618 model.insert(0, (key, step));
619 assert_eq!(map.insert(key, step), expected);
620 }
621 3 | 4 => {
622 let expected = position.map(|p| {
623 let entry = model.remove(p);
624 model.insert(0, entry);
625 entry.1
626 });
627 assert_eq!(map.get(&key).copied(), expected);
628 }
629 5 => assert_eq!(map.remove(&key), position.map(|p| model.remove(p).1)),
630 6 => assert_eq!(map.pop_oldest(), model.pop()),
631 _ => assert_eq!(map.peek(&key).copied(), position.map(|p| model[p].1)),
632 }
633 assert_eq!(map.len(), model.len());
634 if step % 997 == 0 {
635 assert_eq!(map.iter().map(|(k, v)| (*k, *v)).collect::<Vec<_>>(), model);
636 }
637 }
638 }
639 }
640}