1use super::{CacheBuilder, IndexDeque, Iter, Slab, SlabEntry, SENTINEL};
2use crate::Policy;
3
4use hashbrown::HashTable;
5use std::{
6 borrow::Borrow,
7 collections::hash_map::RandomState,
8 fmt,
9 hash::{BuildHasher, Hash},
10};
11
12pub struct Cache<K, V, S = RandomState> {
86 max_capacity: Option<u64>,
87 entry_count: u64,
88 table: HashTable<u32>,
89 build_hasher: S,
90 slab: Slab<K, V>,
91 deque: IndexDeque,
92}
93
94impl<K, V, S> fmt::Debug for Cache<K, V, S>
95where
96 K: fmt::Debug + Eq + Hash,
97 V: fmt::Debug,
98 S: BuildHasher + Clone,
99{
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 let mut d_map = f.debug_map();
102
103 for (k, v) in self.iter() {
104 d_map.entry(&k, &v);
105 }
106
107 d_map.finish()
108 }
109}
110
111impl<K, V> Cache<K, V, RandomState>
112where
113 K: Hash + Eq,
114{
115 pub fn new(max_capacity: u64) -> Self {
122 let build_hasher = RandomState::default();
123 Self::with_everything(Some(max_capacity), None, build_hasher)
124 }
125
126 pub fn builder() -> CacheBuilder<K, V, Cache<K, V, RandomState>> {
131 CacheBuilder::default()
132 }
133}
134
135impl<K, V, S> Cache<K, V, S> {
139 pub fn policy(&self) -> Policy {
144 Policy::new(self.max_capacity)
145 }
146
147 pub fn entry_count(&self) -> u64 {
167 self.entry_count
168 }
169
170 pub fn weighted_size(&self) -> u64 {
174 self.entry_count
175 }
176}
177
178impl<K, V, S> Cache<K, V, S>
179where
180 K: Hash + Eq,
181 S: BuildHasher + Clone,
182{
183 pub(crate) fn with_everything(
184 max_capacity: Option<u64>,
185 initial_capacity: Option<usize>,
186 build_hasher: S,
187 ) -> Self {
188 let init_cap = initial_capacity.unwrap_or_default();
189
190 Self {
191 max_capacity,
192 entry_count: 0,
193 table: HashTable::with_capacity(init_cap),
194 build_hasher,
195 slab: if init_cap > 0 {
196 Slab::with_capacity(init_cap)
197 } else {
198 Slab::new()
199 },
200 deque: IndexDeque::default(),
201 }
202 }
203
204 #[inline]
212 pub fn contains_key<Q>(&self, key: &Q) -> bool
213 where
214 K: Borrow<Q>,
215 Q: Hash + Eq + ?Sized,
216 {
217 let hash = self.hash(key);
218 self.table
219 .find(hash, |&idx| self.slab.get(idx).key.borrow() == key)
220 .is_some()
221 }
222
223 #[inline]
228 pub fn get<Q>(&mut self, key: &Q) -> Option<&V>
229 where
230 K: Borrow<Q>,
231 Q: Hash + Eq + ?Sized,
232 {
233 let hash = self.hash(key);
234
235 let idx = match self
236 .table
237 .find(hash, |&idx| self.slab.get(idx).key.borrow() == key)
238 {
239 Some(&idx) => idx,
240 None => return None,
241 };
242
243 self.slab.get_mut(idx).visited = true;
244 Some(&self.slab.get(idx).value)
245 }
246
247 #[inline]
271 pub fn peek<Q>(&self, key: &Q) -> Option<&V>
272 where
273 K: Borrow<Q>,
274 Q: Hash + Eq + ?Sized,
275 {
276 let hash = self.hash(key);
277 let idx = self
278 .table
279 .find(hash, |&idx| self.slab.get(idx).key.borrow() == key)?;
280 Some(&self.slab.get(*idx).value)
281 }
282
283 #[inline]
287 pub fn insert(&mut self, key: K, value: V) {
288 let hash = self.hash(&key);
289
290 if let Some(&idx) = self
291 .table
292 .find(hash, |&idx| self.slab.get(idx).key.borrow() == &key)
293 {
294 let entry = self.slab.get_mut(idx);
295 entry.value = value;
296 entry.visited = true;
297 return;
298 }
299
300 if !self.has_enough_capacity(1, self.entry_count) {
301 if self.max_capacity == Some(0) {
302 return;
303 }
304
305 self.sieve_evict_one();
306 }
307
308 let slab_entry = SlabEntry {
309 key,
310 value,
311 hash,
312 visited: false,
313 prev: SENTINEL,
314 next: SENTINEL,
315 };
316 let idx = self.slab.allocate(slab_entry);
317
318 let slab = &self.slab;
319 self.table
320 .insert_unique(hash, idx, |&existing_idx| slab.get(existing_idx).hash);
321
322 self.deque.push_back(&mut self.slab, idx);
323 self.entry_count += 1;
324 }
325
326 #[inline]
331 pub fn invalidate<Q>(&mut self, key: &Q)
332 where
333 K: Borrow<Q>,
334 Q: Hash + Eq + ?Sized,
335 {
336 let hash = self.hash(key);
337 let slab = &self.slab;
338 if let Ok(entry) = self
339 .table
340 .find_entry(hash, |&idx| slab.get(idx).key.borrow() == key)
341 {
342 let (idx, _) = entry.remove();
343 self.deque.advance_hand_past(&self.slab, idx);
344 self.deque.unlink(&mut self.slab, idx);
345 self.slab.deallocate(idx);
346 self.entry_count -= 1;
347 }
348 }
349
350 #[inline]
355 pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
356 where
357 K: Borrow<Q>,
358 Q: Hash + Eq + ?Sized,
359 {
360 let hash = self.hash(key);
361 let slab = &self.slab;
362 if let Ok(entry) = self
363 .table
364 .find_entry(hash, |&idx| slab.get(idx).key.borrow() == key)
365 {
366 let (idx, _) = entry.remove();
367 self.deque.advance_hand_past(&self.slab, idx);
368 self.deque.unlink(&mut self.slab, idx);
369 let slab_entry = self.slab.deallocate(idx);
370 self.entry_count -= 1;
371 Some(slab_entry.value)
372 } else {
373 None
374 }
375 }
376
377 #[cold]
379 #[inline(never)]
380 pub fn invalidate_all(&mut self) {
381 let old_capacity = self.table.capacity();
382 let old_table = std::mem::replace(&mut self.table, HashTable::new());
383 let old_slab = std::mem::replace(&mut self.slab, Slab::new());
384 self.deque.clear();
385 self.entry_count = 0;
386
387 drop(old_table);
388 drop(old_slab);
389
390 self.table.reserve(old_capacity, |&idx| {
391 let _ = idx;
395 0
396 });
397 }
398
399 #[cold]
405 #[inline(never)]
406 pub fn invalidate_entries_if(&mut self, mut predicate: impl FnMut(&K, &V) -> bool) {
407 let indices_to_invalidate: Vec<u32> = self
408 .slab
409 .iter()
410 .filter(|(_, entry)| predicate(&entry.key, &entry.value))
411 .map(|(idx, _)| idx)
412 .collect();
413
414 let mut invalidated = 0u64;
415 for idx in indices_to_invalidate {
416 let hash = self.slab.get(idx).hash;
417 if let Ok(entry) = self.table.find_entry(hash, |&table_idx| table_idx == idx) {
418 entry.remove();
419 self.deque.advance_hand_past(&self.slab, idx);
420 self.deque.unlink(&mut self.slab, idx);
421 self.slab.deallocate(idx);
422 invalidated += 1;
423 }
424 }
425 self.entry_count -= invalidated;
426 }
427
428 pub fn iter(&self) -> Iter<'_, K, V> {
451 Iter::new(&self.slab.entries)
452 }
453}
454
455impl<K, V, S> Cache<K, V, S>
459where
460 K: Hash + Eq,
461 S: BuildHasher + Clone,
462{
463 #[inline]
464 fn hash<Q>(&self, key: &Q) -> u64
465 where
466 K: Borrow<Q>,
467 Q: Hash + Eq + ?Sized,
468 {
469 self.build_hasher.hash_one(key)
470 }
471
472 #[inline]
473 fn has_enough_capacity(&self, candidate_weight: u32, ws: u64) -> bool {
474 self.max_capacity
475 .map(|limit| ws + candidate_weight as u64 <= limit)
476 .unwrap_or(true)
477 }
478
479 #[cold]
480 #[inline(never)]
481 fn sieve_evict_one(&mut self) {
482 if let Some(victim_idx) = self.deque.sieve_evict(&mut self.slab) {
483 let victim_hash = self.slab.get(victim_idx).hash;
484 if let Ok(entry) = self
485 .table
486 .find_entry(victim_hash, |&table_idx| table_idx == victim_idx)
487 {
488 entry.remove();
489 }
490 self.slab.deallocate(victim_idx);
491 self.entry_count -= 1;
492 }
493 }
494}
495
496#[cfg(test)]
497mod tests {
498 use super::Cache;
499
500 #[test]
501 fn basic_single_thread() {
502 let mut cache = Cache::new(3);
503
504 cache.insert("a", "alice");
505 cache.insert("b", "bob");
506 assert_eq!(cache.get(&"a"), Some(&"alice"));
507 assert!(cache.contains_key(&"a"));
508 assert!(cache.contains_key(&"b"));
509 assert_eq!(cache.get(&"b"), Some(&"bob"));
510
511 cache.insert("c", "cindy");
512 assert_eq!(cache.get(&"c"), Some(&"cindy"));
513 assert!(cache.contains_key(&"c"));
514
515 assert!(cache.contains_key(&"a"));
516 assert_eq!(cache.get(&"a"), Some(&"alice"));
517 assert_eq!(cache.get(&"b"), Some(&"bob"));
518 assert!(cache.contains_key(&"b"));
519
520 cache.insert("d", "david");
523 assert_eq!(cache.entry_count(), 3);
524 assert!(cache.contains_key(&"d"));
525
526 cache.invalidate(&"b");
527 assert_eq!(cache.get(&"b"), None);
528 assert!(!cache.contains_key(&"b"));
529 }
530
531 #[test]
532 fn sieve_evicts_unvisited_entry() {
533 let mut cache = Cache::new(3);
534
535 cache.insert("a", "alice");
536 cache.insert("b", "bob");
537 cache.insert("c", "cindy");
538
539 cache.get(&"b");
541 cache.get(&"c");
542
543 cache.insert("d", "david");
546 assert_eq!(cache.entry_count(), 3);
547 assert_eq!(cache.get(&"a"), None);
548 assert!(cache.contains_key(&"b"));
549 assert!(cache.contains_key(&"c"));
550 assert!(cache.contains_key(&"d"));
551 }
552
553 #[test]
554 fn sieve_visited_entries_get_second_chance() {
555 let mut cache = Cache::new(3);
556
557 cache.insert("a", "alice");
558 cache.insert("b", "bob");
559 cache.insert("c", "cindy");
560
561 cache.get(&"a");
563 cache.get(&"b");
564 cache.get(&"c");
565
566 cache.insert("d", "david");
569 assert_eq!(cache.entry_count(), 3);
570 assert!(cache.contains_key(&"d"));
571 }
572
573 #[test]
574 fn sieve_new_entry_always_admitted() {
575 let mut cache = Cache::new(3);
576
577 cache.insert("a", "alice");
578 cache.insert("b", "bob");
579 cache.insert("c", "cindy");
580
581 for _ in 0..10 {
584 cache.get(&"a");
585 cache.get(&"b");
586 cache.get(&"c");
587 }
588
589 cache.insert("d", "david");
590 assert_eq!(cache.entry_count(), 3);
591 assert!(cache.contains_key(&"d"));
592 }
593
594 #[test]
595 fn invalidate_all() {
596 let mut cache = Cache::new(100);
597
598 cache.insert("a", "alice");
599 cache.insert("b", "bob");
600 cache.insert("c", "cindy");
601 assert_eq!(cache.get(&"a"), Some(&"alice"));
602 assert_eq!(cache.get(&"b"), Some(&"bob"));
603 assert_eq!(cache.get(&"c"), Some(&"cindy"));
604 assert!(cache.contains_key(&"a"));
605 assert!(cache.contains_key(&"b"));
606 assert!(cache.contains_key(&"c"));
607
608 cache.invalidate_all();
609
610 cache.insert("d", "david");
611
612 assert!(cache.get(&"a").is_none());
613 assert!(cache.get(&"b").is_none());
614 assert!(cache.get(&"c").is_none());
615 assert_eq!(cache.get(&"d"), Some(&"david"));
616 assert!(!cache.contains_key(&"a"));
617 assert!(!cache.contains_key(&"b"));
618 assert!(!cache.contains_key(&"c"));
619 assert!(cache.contains_key(&"d"));
620 }
621
622 #[test]
623 fn invalidate_entries_if() {
624 use std::collections::HashSet;
625
626 let mut cache = Cache::new(100);
627
628 cache.insert(0, "alice");
629 cache.insert(1, "bob");
630 cache.insert(2, "alex");
631
632 assert_eq!(cache.get(&0), Some(&"alice"));
633 assert_eq!(cache.get(&1), Some(&"bob"));
634 assert_eq!(cache.get(&2), Some(&"alex"));
635 assert!(cache.contains_key(&0));
636 assert!(cache.contains_key(&1));
637 assert!(cache.contains_key(&2));
638
639 let names = ["alice", "alex"].iter().cloned().collect::<HashSet<_>>();
640 cache.invalidate_entries_if(move |_k, &v| names.contains(v));
641
642 cache.insert(3, "alice");
643
644 assert!(cache.get(&0).is_none());
645 assert!(cache.get(&2).is_none());
646 assert_eq!(cache.get(&1), Some(&"bob"));
647 assert_eq!(cache.get(&3), Some(&"alice"));
648
649 assert!(!cache.contains_key(&0));
650 assert!(cache.contains_key(&1));
651 assert!(!cache.contains_key(&2));
652 assert!(cache.contains_key(&3));
653
654 assert_eq!(cache.table.len(), 2);
655
656 cache.invalidate_entries_if(|_k, &v| v == "alice");
657 cache.invalidate_entries_if(|_k, &v| v == "bob");
658
659 assert!(cache.get(&1).is_none());
660 assert!(cache.get(&3).is_none());
661
662 assert!(!cache.contains_key(&1));
663 assert!(!cache.contains_key(&3));
664
665 assert_eq!(cache.table.len(), 0);
666 }
667
668 #[test]
669 fn remove_decrements_entry_count() {
670 let mut cache = Cache::new(3);
671 cache.insert("a", "alice");
672 cache.insert("b", "bob");
673 assert_eq!(cache.entry_count(), 2);
674
675 let removed = cache.remove(&"a");
676 assert_eq!(removed, Some("alice"));
677 assert_eq!(cache.entry_count(), 1);
678
679 cache.remove(&"nonexistent");
680 assert_eq!(cache.entry_count(), 1);
681
682 cache.remove(&"b");
683 assert_eq!(cache.entry_count(), 0);
684 }
685
686 #[test]
687 fn invalidate_decrements_entry_count() {
688 let mut cache = Cache::new(3);
689 cache.insert("a", "alice");
690 cache.insert("b", "bob");
691 assert_eq!(cache.entry_count(), 2);
692
693 cache.invalidate(&"a");
694 assert_eq!(cache.entry_count(), 1);
695
696 cache.invalidate(&"nonexistent");
697 assert_eq!(cache.entry_count(), 1);
698
699 cache.invalidate(&"b");
700 assert_eq!(cache.entry_count(), 0);
701 }
702
703 #[test]
704 fn insert_after_remove_on_full_cache() {
705 let mut cache = Cache::new(2);
706 cache.insert("a", "alice");
707 cache.insert("b", "bob");
708 assert_eq!(cache.entry_count(), 2);
709
710 cache.remove(&"a");
711 assert_eq!(cache.entry_count(), 1);
712
713 cache.insert("c", "cindy");
714 assert_eq!(cache.entry_count(), 2);
715 assert_eq!(cache.get(&"c"), Some(&"cindy"));
716 assert_eq!(cache.get(&"b"), Some(&"bob"));
717 assert_eq!(cache.get(&"a"), None);
718 }
719
720 #[test]
721 fn insert_after_invalidate_on_full_cache() {
722 let mut cache = Cache::new(2);
723 cache.insert("a", "alice");
724 cache.insert("b", "bob");
725 assert_eq!(cache.entry_count(), 2);
726
727 cache.invalidate(&"a");
728 assert_eq!(cache.entry_count(), 1);
729
730 cache.insert("c", "cindy");
731 assert_eq!(cache.entry_count(), 2);
732 assert_eq!(cache.get(&"c"), Some(&"cindy"));
733 assert_eq!(cache.get(&"b"), Some(&"bob"));
734 assert_eq!(cache.get(&"a"), None);
735 }
736
737 #[test]
738 fn invalidate_all_panic_safety() {
739 use std::panic::catch_unwind;
740 use std::panic::AssertUnwindSafe;
741 use std::sync::atomic::{AtomicU32, Ordering};
742
743 static DROP_COUNT: AtomicU32 = AtomicU32::new(0);
744
745 struct PanicOnDrop {
746 id: u32,
747 should_panic: bool,
748 }
749
750 impl Drop for PanicOnDrop {
751 fn drop(&mut self) {
752 DROP_COUNT.fetch_add(1, Ordering::Relaxed);
753 if self.should_panic {
754 panic!("intentional panic in drop for id={}", self.id);
755 }
756 }
757 }
758
759 DROP_COUNT.store(0, Ordering::Relaxed);
760 let mut cache = Cache::new(10);
761 cache.insert(
762 1,
763 PanicOnDrop {
764 id: 1,
765 should_panic: false,
766 },
767 );
768 cache.insert(
769 2,
770 PanicOnDrop {
771 id: 2,
772 should_panic: true,
773 },
774 );
775 cache.insert(
776 3,
777 PanicOnDrop {
778 id: 3,
779 should_panic: false,
780 },
781 );
782 assert_eq!(cache.entry_count(), 3);
783
784 let result = catch_unwind(AssertUnwindSafe(|| {
785 cache.invalidate_all();
786 }));
787 assert!(result.is_err());
788
789 assert_eq!(cache.entry_count(), 0);
790 assert_eq!(cache.table.len(), 0);
791
792 cache.insert(
793 4,
794 PanicOnDrop {
795 id: 4,
796 should_panic: false,
797 },
798 );
799 assert_eq!(cache.entry_count(), 1);
800 assert!(cache.contains_key(&4));
801 }
802
803 #[test]
804 fn test_debug_format() {
805 let mut cache = Cache::new(10);
806 cache.insert('a', "alice");
807 cache.insert('b', "bob");
808 cache.insert('c', "cindy");
809
810 let debug_str = format!("{:?}", cache);
811 assert!(debug_str.starts_with('{'));
812 assert!(debug_str.contains(r#"'a': "alice""#));
813 assert!(debug_str.contains(r#"'b': "bob""#));
814 assert!(debug_str.contains(r#"'c': "cindy""#));
815 assert!(debug_str.ends_with('}'));
816 }
817
818 #[test]
819 fn sub_capacity_inserts_skip_eviction() {
820 let mut cache = Cache::new(10);
821 for i in 0u32..5 {
822 cache.insert(i, i * 10);
823 }
824 assert_eq!(cache.entry_count(), 5);
825 for i in 0u32..5 {
826 assert_eq!(cache.get(&i), Some(&(i * 10)));
827 }
828 }
829
830 #[test]
831 fn eviction_triggers_when_over_capacity() {
832 let mut cache = Cache::new(3);
833
834 cache.insert(1, "a");
835 cache.insert(2, "b");
836 cache.insert(3, "c");
837 assert_eq!(cache.entry_count(), 3);
838
839 cache.insert(4, "d");
840 assert!(cache.entry_count() <= 3);
841 }
842
843 #[test]
844 fn warmup_to_full_transition() {
845 let mut cache = Cache::new(4);
846
847 cache.insert(1, "a");
848 cache.insert(2, "b");
849 assert_eq!(cache.entry_count(), 2);
850
851 cache.insert(3, "c");
852 cache.insert(4, "d");
853 assert_eq!(cache.entry_count(), 4);
854
855 for _ in 0..5 {
856 cache.get(&1);
857 cache.get(&2);
858 cache.get(&3);
859 cache.get(&4);
860 }
861
862 cache.insert(5, "e");
863 assert!(cache.entry_count() <= 4);
864 }
865
866 #[test]
867 fn invalidate_and_remove_skip_eviction_below_capacity() {
868 let mut cache = Cache::new(10);
869 cache.insert(1, "a");
870 cache.insert(2, "b");
871 cache.insert(3, "c");
872 assert_eq!(cache.entry_count(), 3);
873
874 cache.invalidate(&1);
875 assert_eq!(cache.entry_count(), 2);
876
877 let val = cache.remove(&2);
878 assert_eq!(val, Some("b"));
879 assert_eq!(cache.entry_count(), 1);
880
881 assert_eq!(cache.get(&3), Some(&"c"));
882 }
883
884 #[test]
885 fn peek_returns_value() {
886 let mut cache = Cache::new(10);
887 cache.insert("a", "alice");
888 cache.insert("b", "bob");
889
890 assert_eq!(cache.peek(&"a"), Some(&"alice"));
891 assert_eq!(cache.peek(&"b"), Some(&"bob"));
892 }
893
894 #[test]
895 fn peek_returns_none_for_missing_key() {
896 let cache = Cache::<&str, &str>::new(10);
897 assert_eq!(cache.peek(&"missing"), None);
898 }
899
900 #[test]
901 fn peek_does_not_set_visited() {
902 let mut cache = Cache::new(3);
903
904 cache.insert("a", "alice");
905 cache.insert("b", "bob");
906 cache.insert("c", "cindy");
907
908 cache.peek(&"a");
910 cache.peek(&"b");
911 cache.peek(&"c");
912
913 cache.insert("d", "david");
916
917 assert_eq!(cache.entry_count(), 3);
919 assert!(cache.contains_key(&"d"));
920 }
921
922 #[test]
923 fn contains_key_with_shared_reference() {
924 let mut cache = Cache::new(10);
925 cache.insert("a", 1);
926 cache.insert("b", 2);
927 cache.insert("c", 3);
928
929 let cache_ref: &Cache<&str, i32> = &cache;
930 assert!(cache_ref.contains_key(&"a"));
931 assert!(cache_ref.contains_key(&"b"));
932 assert!(cache_ref.contains_key(&"c"));
933 assert!(!cache_ref.contains_key(&"d"));
934 }
935
936 #[test]
937 fn zero_capacity_insert_returns_immediately() {
938 let mut cache = Cache::new(0);
939 cache.insert("a", "alice");
940 assert_eq!(cache.entry_count(), 0);
941 assert!(!cache.contains_key(&"a"));
942 assert_eq!(cache.get(&"a"), None);
943 }
944
945 #[test]
946 fn update_existing_key_sets_visited() {
947 let mut cache = Cache::new(3);
948
949 cache.insert("a", "alice");
950 cache.insert("b", "bob");
951 cache.insert("c", "cindy");
952
953 cache.insert("a", "anna");
956 assert_eq!(cache.get(&"a"), Some(&"anna"));
957 assert_eq!(cache.entry_count(), 3);
958
959 cache.insert("d", "david");
962 assert_eq!(cache.entry_count(), 3);
963 assert!(cache.contains_key(&"a"));
964 assert!(cache.contains_key(&"d"));
965 }
966
967 #[test]
968 fn sieve_hand_advances_across_evictions() {
969 let mut cache = Cache::new(3);
970
971 cache.insert("a", "alice");
972 cache.insert("b", "bob");
973 cache.insert("c", "cindy");
974
975 cache.insert("d", "david");
977 assert_eq!(cache.entry_count(), 3);
978
979 cache.insert("e", "eve");
981 assert_eq!(cache.entry_count(), 3);
982
983 cache.insert("f", "frank");
985 assert_eq!(cache.entry_count(), 3);
986 }
987
988 #[test]
989 fn sieve_multiple_evictions_cycle() {
990 let mut cache = Cache::new(2);
991
992 for i in 0u32..20 {
993 cache.insert(i, i * 10);
994 assert!(cache.entry_count() <= 2);
995 }
996
997 assert_eq!(cache.entry_count(), 2);
999 assert!(cache.contains_key(&19));
1000 assert!(cache.contains_key(&18));
1001 }
1002
1003 #[test]
1004 fn update_below_capacity_no_eviction() {
1005 let mut cache = Cache::new(5);
1006
1007 cache.insert("a", "alice");
1008 cache.insert("b", "bob");
1009 cache.insert("c", "cindy");
1010 assert_eq!(cache.entry_count(), 3);
1011
1012 cache.insert("b", "betty");
1014 assert_eq!(cache.entry_count(), 3);
1015 assert_eq!(cache.get(&"b"), Some(&"betty"));
1016 assert!(cache.contains_key(&"a"));
1017 assert!(cache.contains_key(&"c"));
1018 }
1019}