1mod error;
2pub use error::WTinyLFUError;
3
4use crate::lfu::{
5 tinylfu::{TinyLFU, TinyLFUBuilder, TinyLFUError, DEFAULT_FALSE_POSITIVE_RATIO},
6 DefaultKeyHasher, KeyHasher,
7};
8use crate::lru::{SegmentedCache, SegmentedCacheBuilder};
9use crate::{Cache, DefaultHashBuilder, LRUCache, PutResult};
10use core::borrow::Borrow;
11use core::hash::{BuildHasher, Hash};
12use core::marker::PhantomData;
13
14const DEFAULT_WINDOW_CACHE_SIZE_RATIO: f64 = 0.01;
15const DEFAULT_HOT_ITEMS_CACHE_SIZE_RATIO: f64 = 0.80;
16
17pub struct WTinyLFUCacheBuilder<
21 K,
22 KH = DefaultKeyHasher<K>,
23 FH = DefaultHashBuilder,
24 RH = DefaultHashBuilder,
25 WH = DefaultHashBuilder,
26> {
27 samples: usize,
28 window_cache_size: usize,
29 main_cache_protected_size: usize,
30 main_cache_probationary_size: usize,
31 window_cache_hasher: Option<WH>,
32 key_hasher: Option<KH>,
33 main_cache_protected_hasher: Option<FH>,
34 main_cache_probationary_hasher: Option<RH>,
35 false_positive_ratio: Option<f64>,
36 marker: PhantomData<K>,
37}
38
39impl<
40 K: Hash + Eq,
41 KH: KeyHasher<K> + Default,
42 FH: BuildHasher + Default,
43 RH: BuildHasher + Default,
44 WH: BuildHasher + Default,
45 > Default for WTinyLFUCacheBuilder<K, KH, FH, RH, WH>
46{
47 fn default() -> Self {
48 Self {
49 samples: 0,
50 window_cache_size: 0,
51 main_cache_protected_size: 0,
52 main_cache_probationary_size: 0,
53 window_cache_hasher: Some(WH::default()),
54 main_cache_protected_hasher: Some(FH::default()),
55 main_cache_probationary_hasher: Some(RH::default()),
56 key_hasher: Some(KH::default()),
57 false_positive_ratio: Some(DEFAULT_FALSE_POSITIVE_RATIO),
58 marker: Default::default(),
59 }
60 }
61}
62
63impl<
64 K: Hash + Eq,
65 KH: KeyHasher<K> + Default,
66 FH: BuildHasher + Default,
67 RH: BuildHasher + Default,
68 WH: BuildHasher + Default,
69 > WTinyLFUCacheBuilder<K, KH, FH, RH, WH>
70{
71 pub fn new(
73 window_cache_size: usize,
74 protected_cache_size: usize,
75 probationary_cache_size: usize,
76 samples: usize,
77 ) -> Self {
78 Self::default()
79 .set_samples(samples)
80 .set_window_cache_size(window_cache_size)
81 .set_protected_cache_size(protected_cache_size)
82 .set_probationary_cache_size(probationary_cache_size)
83 }
84}
85
86impl<K: Hash + Eq, KH: KeyHasher<K>, FH: BuildHasher, RH: BuildHasher, WH: BuildHasher>
87 WTinyLFUCacheBuilder<K, KH, FH, RH, WH>
88{
89 pub fn with_hashers(
91 key_hasher: KH,
92 protected_hasher: FH,
93 probationary_hasher: RH,
94 window_hasher: WH,
95 ) -> Self {
96 Self {
97 samples: 0,
98 window_cache_size: 0,
99 main_cache_protected_size: 0,
100 main_cache_probationary_size: 0,
101 window_cache_hasher: Some(window_hasher),
102 main_cache_protected_hasher: Some(protected_hasher),
103 main_cache_probationary_hasher: Some(probationary_hasher),
104 key_hasher: Some(key_hasher),
105 false_positive_ratio: Some(DEFAULT_FALSE_POSITIVE_RATIO),
106 marker: Default::default(),
107 }
108 }
109
110 pub fn set_samples(self, samples: usize) -> Self {
112 Self {
113 samples,
114 window_cache_size: self.window_cache_size,
115 main_cache_protected_size: self.main_cache_protected_size,
116 main_cache_probationary_size: self.main_cache_probationary_size,
117 window_cache_hasher: self.window_cache_hasher,
118 key_hasher: self.key_hasher,
119 main_cache_protected_hasher: self.main_cache_protected_hasher,
120 main_cache_probationary_hasher: self.main_cache_probationary_hasher,
121 false_positive_ratio: self.false_positive_ratio,
122 marker: self.marker,
123 }
124 }
125
126 pub fn set_window_cache_size(self, sz: usize) -> Self {
128 Self {
129 samples: self.samples,
130 window_cache_size: sz,
131 main_cache_protected_size: self.main_cache_protected_size,
132 main_cache_probationary_size: self.main_cache_probationary_size,
133 window_cache_hasher: self.window_cache_hasher,
134 main_cache_protected_hasher: self.main_cache_protected_hasher,
135 main_cache_probationary_hasher: self.main_cache_probationary_hasher,
136 key_hasher: self.key_hasher,
137 false_positive_ratio: self.false_positive_ratio,
138 marker: self.marker,
139 }
140 }
141
142 pub fn set_protected_cache_size(self, sz: usize) -> Self {
144 Self {
145 samples: self.samples,
146 window_cache_size: self.window_cache_size,
147 main_cache_protected_size: sz,
148 main_cache_probationary_size: self.main_cache_probationary_size,
149 window_cache_hasher: self.window_cache_hasher,
150 main_cache_protected_hasher: self.main_cache_protected_hasher,
151 main_cache_probationary_hasher: self.main_cache_probationary_hasher,
152 key_hasher: self.key_hasher,
153 false_positive_ratio: self.false_positive_ratio,
154 marker: self.marker,
155 }
156 }
157
158 pub fn set_probationary_cache_size(self, sz: usize) -> Self {
160 Self {
161 samples: self.samples,
162 window_cache_size: self.window_cache_size,
163 main_cache_protected_size: self.main_cache_protected_size,
164 main_cache_probationary_size: sz,
165 window_cache_hasher: self.window_cache_hasher,
166 main_cache_protected_hasher: self.main_cache_protected_hasher,
167 main_cache_probationary_hasher: self.main_cache_probationary_hasher,
168 key_hasher: self.key_hasher,
169 false_positive_ratio: self.false_positive_ratio,
170 marker: self.marker,
171 }
172 }
173
174 pub fn set_false_positive_ratio(self, fpr: f64) -> Self {
176 Self {
177 samples: self.samples,
178 window_cache_size: self.window_cache_size,
179 main_cache_protected_size: self.main_cache_protected_size,
180 main_cache_probationary_size: self.main_cache_probationary_size,
181 window_cache_hasher: self.window_cache_hasher,
182 main_cache_protected_hasher: self.main_cache_protected_hasher,
183 main_cache_probationary_hasher: self.main_cache_probationary_hasher,
184 key_hasher: self.key_hasher,
185 false_positive_ratio: Some(fpr),
186 marker: self.marker,
187 }
188 }
189
190 pub fn set_window_hasher<NWH: BuildHasher>(
192 self,
193 hasher: NWH,
194 ) -> WTinyLFUCacheBuilder<K, KH, FH, RH, NWH> {
195 WTinyLFUCacheBuilder {
196 samples: self.samples,
197 window_cache_size: self.window_cache_size,
198 main_cache_protected_size: self.main_cache_protected_size,
199 main_cache_probationary_size: self.main_cache_probationary_size,
200 window_cache_hasher: Some(hasher),
201 main_cache_protected_hasher: self.main_cache_protected_hasher,
202 main_cache_probationary_hasher: self.main_cache_probationary_hasher,
203 key_hasher: self.key_hasher,
204 false_positive_ratio: self.false_positive_ratio,
205 marker: self.marker,
206 }
207 }
208
209 pub fn set_protected_hasher<NFH: BuildHasher>(
211 self,
212 hasher: NFH,
213 ) -> WTinyLFUCacheBuilder<K, KH, NFH, RH, WH> {
214 WTinyLFUCacheBuilder {
215 samples: self.samples,
216 window_cache_size: self.window_cache_size,
217 main_cache_protected_size: self.main_cache_protected_size,
218 main_cache_probationary_size: self.main_cache_probationary_size,
219 window_cache_hasher: self.window_cache_hasher,
220 main_cache_protected_hasher: Some(hasher),
221 main_cache_probationary_hasher: self.main_cache_probationary_hasher,
222 key_hasher: self.key_hasher,
223 false_positive_ratio: self.false_positive_ratio,
224 marker: self.marker,
225 }
226 }
227
228 pub fn set_probationary_hasher<NRH: BuildHasher>(
230 self,
231 hasher: NRH,
232 ) -> WTinyLFUCacheBuilder<K, KH, FH, NRH, WH> {
233 WTinyLFUCacheBuilder {
234 samples: self.samples,
235 window_cache_size: self.window_cache_size,
236 main_cache_protected_size: self.main_cache_protected_size,
237 main_cache_probationary_size: self.main_cache_probationary_size,
238 window_cache_hasher: self.window_cache_hasher,
239 main_cache_protected_hasher: self.main_cache_protected_hasher,
240 key_hasher: self.key_hasher,
241 main_cache_probationary_hasher: Some(hasher),
242 false_positive_ratio: self.false_positive_ratio,
243 marker: self.marker,
244 }
245 }
246
247 pub fn set_key_hasher<NKH: KeyHasher<K>>(
249 self,
250 hasher: NKH,
251 ) -> WTinyLFUCacheBuilder<K, NKH, FH, RH, WH> {
252 WTinyLFUCacheBuilder {
253 samples: self.samples,
254 window_cache_size: self.window_cache_size,
255 main_cache_protected_size: self.main_cache_protected_size,
256 main_cache_probationary_size: self.main_cache_probationary_size,
257 window_cache_hasher: self.window_cache_hasher,
258 main_cache_protected_hasher: self.main_cache_protected_hasher,
259 key_hasher: Some(hasher),
260 main_cache_probationary_hasher: self.main_cache_probationary_hasher,
261 false_positive_ratio: self.false_positive_ratio,
262 marker: self.marker,
263 }
264 }
265
266 pub fn finalize<V>(self) -> Result<WTinyLFUCache<K, V, KH, FH, RH, WH>, WTinyLFUError>
270 where
271 K: Eq,
272 {
273 if self.window_cache_size == 0 {
274 return Err(WTinyLFUError::InvalidWindowCacheSize(0));
275 }
276
277 if self.main_cache_protected_size == 0 {
278 return Err(WTinyLFUError::InvalidProtectedCacheSize(0));
279 }
280
281 if self.main_cache_probationary_size == 0 {
282 return Err(WTinyLFUError::InvalidProbationaryCacheSize(0));
283 }
284
285 if self.samples == 0 {
286 return Err(WTinyLFUError::InvalidSamples(self.samples));
287 }
288
289 let fp_ratio = self.false_positive_ratio.unwrap();
290 if fp_ratio <= 0.0 || fp_ratio >= 1.0 {
291 return Err(WTinyLFUError::InvalidFalsePositiveRatio(fp_ratio));
292 }
293
294 let lru = LRUCache::with_hasher(self.window_cache_size, self.window_cache_hasher.unwrap())
295 .unwrap();
296
297 let slru = SegmentedCacheBuilder::new(
298 self.main_cache_probationary_size,
299 self.main_cache_protected_size,
300 )
301 .set_probationary_hasher(self.main_cache_probationary_hasher.unwrap())
302 .set_protected_hasher(self.main_cache_protected_hasher.unwrap())
303 .finalize()
304 .unwrap();
305
306 let size = self.window_cache_size
307 + self.main_cache_protected_size
308 + self.main_cache_probationary_size;
309
310 let tinylfu = TinyLFUBuilder::new(size, self.samples)
311 .set_key_hasher(self.key_hasher.unwrap())
312 .set_false_positive_ratio(fp_ratio)
313 .finalize()
314 .map_err(|e| match e {
315 TinyLFUError::InvalidCountMinWidth(v) => WTinyLFUError::InvalidCountMinWidth(v),
316 TinyLFUError::InvalidSamples(v) => WTinyLFUError::InvalidSamples(v),
317 TinyLFUError::InvalidFalsePositiveRatio(v) => {
318 WTinyLFUError::InvalidFalsePositiveRatio(v)
319 }
320 })?;
321
322 Ok(WTinyLFUCache { tinylfu, lru, slru })
323 }
324}
325
326pub struct WTinyLFUCache<
393 K: Hash,
394 V,
395 KH = DefaultKeyHasher<K>,
396 FH = DefaultHashBuilder,
397 RH = DefaultHashBuilder,
398 WH = DefaultHashBuilder,
399> {
400 tinylfu: TinyLFU<K, KH>,
401 lru: LRUCache<K, V, WH>,
402 slru: SegmentedCache<K, V, FH, RH>,
403}
404
405impl<K: Hash + Eq, V> WTinyLFUCache<K, V, DefaultKeyHasher<K>> {
406 pub fn new(size: usize, samples: usize) -> Result<Self, WTinyLFUError> {
411 let wsz = ((size as f64) * DEFAULT_WINDOW_CACHE_SIZE_RATIO) as usize;
412 let hsz = ((size as f64) * DEFAULT_HOT_ITEMS_CACHE_SIZE_RATIO) as usize;
413 let csz = ((size as f64) * (1f64 - DEFAULT_HOT_ITEMS_CACHE_SIZE_RATIO)) as usize;
414
415 WTinyLFUCacheBuilder::new(wsz, hsz, csz, samples).finalize()
416 }
417
418 pub fn with_sizes(
425 window_cache_size: usize,
426 protected_cache_size: usize,
427 probationary_cache_size: usize,
428 samples: usize,
429 ) -> Result<Self, WTinyLFUError> {
430 WTinyLFUCacheBuilder::new(
431 window_cache_size,
432 protected_cache_size,
433 probationary_cache_size,
434 samples,
435 )
436 .finalize()
437 }
438}
439
440impl<K: Hash + Eq, V, KH: KeyHasher<K>, FH: BuildHasher, RH: BuildHasher, WH: BuildHasher>
441 WTinyLFUCache<K, V, KH, FH, RH, WH>
442{
443 pub fn from_builder(
447 builder: WTinyLFUCacheBuilder<K, KH, FH, RH, WH>,
448 ) -> Result<Self, WTinyLFUError> {
449 builder.finalize()
450 }
451
452 pub fn builder() -> WTinyLFUCacheBuilder<K> {
456 WTinyLFUCacheBuilder::default()
457 }
458
459 pub fn window_cache_len(&self) -> usize {
461 self.lru.len()
462 }
463
464 pub fn window_cache_cap(&self) -> usize {
466 self.lru.cap()
467 }
468
469 pub fn main_cache_len(&self) -> usize {
471 self.slru.len()
472 }
473
474 pub fn main_cache_cap(&self) -> usize {
476 self.slru.cap()
477 }
478}
479
480impl<K: Hash + Eq, V, KH: KeyHasher<K>, FH: BuildHasher, RH: BuildHasher, WH: BuildHasher>
481 Cache<K, V> for WTinyLFUCache<K, V, KH, FH, RH, WH>
482{
483 fn put(&mut self, k: K, v: V) -> PutResult<K, V> {
503 match self.lru.remove(&k) {
504 None => {
505 if self.slru.contains(&k) {
506 return self.slru.put(k, v);
507 }
508
509 match self.lru.put(k, v) {
510 PutResult::Put => PutResult::Put,
511 PutResult::Update(v) => PutResult::Update(v),
512 PutResult::Evicted { key, value } => {
513 if self.slru.len() < self.slru.cap() {
514 return self.slru.put(key, value);
515 }
516
517 match self.slru.peek_lru_from_probationary() {
518 None => self.slru.put(key, value),
519 Some((lruk, _)) => {
520 if self.tinylfu.lt(&key, lruk) {
521 PutResult::Evicted { key, value }
522 } else {
523 self.slru.put(key, value)
524 }
525 }
526 }
527 }
528 _ => PutResult::Put,
531 }
532 }
533 Some(old) => {
534 if self.slru.protected_len() >= self.slru.protected_cap() {
535 let ent = self.slru.remove_lru_from_protected().unwrap();
536 self.lru.put(ent.0, ent.1);
537 }
538
539 self.slru.put_protected(k, v);
540 PutResult::Update(old)
541 }
542 }
543 }
544
545 fn get<Q>(&mut self, k: &Q) -> Option<&V>
561 where
562 K: Borrow<Q>,
563 Q: Hash + Eq + ?Sized,
564 {
565 self.tinylfu.try_reset();
566 self.tinylfu.increment(k);
567
568 match self.lru.get(k) {
569 Some(v) => Some(v),
570 None => self.slru.get(k),
571 }
572 }
573
574 fn get_mut<Q>(&mut self, k: &Q) -> Option<&mut V>
590 where
591 K: Borrow<Q>,
592 Q: Hash + Eq + ?Sized,
593 {
594 self.tinylfu.try_reset();
595 self.tinylfu.increment(k);
596 match self.lru.get_mut(k) {
597 Some(v) => Some(v),
598 None => self.slru.get_mut(k),
599 }
600 }
601
602 fn peek<Q>(&self, k: &Q) -> Option<&V>
620 where
621 K: Borrow<Q>,
622 Q: Hash + Eq + ?Sized,
623 {
624 self.lru.peek(k).or_else(|| self.slru.peek(k))
625 }
626
627 fn peek_mut<Q>(&mut self, k: &Q) -> Option<&mut V>
645 where
646 K: Borrow<Q>,
647 Q: Hash + Eq + ?Sized,
648 {
649 match self.lru.peek_mut(k) {
650 Some(v) => Some(v),
651 None => self.slru.peek_mut(k),
652 }
653 }
654
655 fn contains<Q>(&self, k: &Q) -> bool
656 where
657 K: Borrow<Q>,
658 Q: Eq + Hash + ?Sized,
659 {
660 self.lru.contains(k) || self.slru.contains(k)
661 }
662
663 fn remove<Q>(&mut self, k: &Q) -> Option<V>
664 where
665 K: Borrow<Q>,
666 Q: Eq + Hash + ?Sized,
667 {
668 self.lru.remove(k).or_else(|| self.slru.remove(k))
669 }
670
671 fn purge(&mut self) {
672 self.lru.purge();
673 self.slru.purge();
674 self.tinylfu.clear();
675 }
676
677 fn len(&self) -> usize {
678 self.lru.len() + self.slru.len()
679 }
680
681 fn cap(&self) -> usize {
682 self.lru.cap() + self.slru.cap()
683 }
684
685 fn is_empty(&self) -> bool {
686 self.lru.is_empty() && self.slru.is_empty()
687 }
688}
689
690impl<
691 K: Hash + Eq + Clone,
692 V: Clone,
693 KH: KeyHasher<K> + Clone,
694 FH: BuildHasher + Clone,
695 RH: BuildHasher + Clone,
696 WH: BuildHasher + Clone,
697 > Clone for WTinyLFUCache<K, V, KH, FH, RH, WH>
698{
699 fn clone(&self) -> Self {
700 Self {
701 tinylfu: self.tinylfu.clone(),
702 lru: self.lru.clone(),
703 slru: self.slru.clone(),
704 }
705 }
706}
707
708#[cfg(test)]
709mod test {
710 use core::hash::BuildHasher;
711
712 use crate::lfu::tinylfu::test::{PassthroughU64Hasher, PassthroughU64KeyHasher};
713 use crate::lfu::WTinyLFUCache;
714 use crate::{Cache, PutResult, WTinyLFUCacheBuilder};
715
716 #[derive(Default)]
717 struct PassthroughBuilderU64Hasher {}
718
719 impl BuildHasher for PassthroughBuilderU64Hasher {
720 type Hasher = PassthroughU64Hasher;
721
722 fn build_hasher(&self) -> Self::Hasher {
723 Default::default()
724 }
725 }
726
727 #[test]
728 fn test_wtinylfu_custom_hasher() {
729 let mut cache: WTinyLFUCache<
730 u64,
731 u32,
732 PassthroughU64KeyHasher,
733 PassthroughBuilderU64Hasher,
734 PassthroughBuilderU64Hasher,
735 PassthroughBuilderU64Hasher,
736 > = WTinyLFUCacheBuilder::default()
737 .set_window_cache_size(1)
738 .set_protected_cache_size(2)
739 .set_probationary_cache_size(2)
740 .set_samples(5)
741 .finalize()
742 .unwrap();
743 assert_eq!(cache.cap(), 5);
744 assert_eq!(cache.window_cache_cap(), 1);
745 assert_eq!(cache.main_cache_cap(), 4);
746
747 assert_eq!(cache.put(1, 1), PutResult::Put);
748 assert!(cache.contains(&1));
749 assert_eq!(cache.put(2, 2), PutResult::Put);
750 assert!(cache.contains(&2));
751 assert_eq!(cache.put(3, 3), PutResult::Put);
752 assert!(cache.contains(&3));
753
754 assert_eq!(cache.window_cache_len(), 1);
759 assert_eq!(cache.main_cache_len(), 2);
760
761 assert_eq!(cache.put(2, 22), PutResult::Update(2));
762 assert_eq!(cache.put(1, 11), PutResult::Update(1));
763
764 assert_eq!(cache.slru.peek_lru_from_protected(), Some((&2, &22)));
769 assert_eq!(cache.slru.peek_mru_from_protected(), Some((&1, &11)));
770 assert_eq!(cache.window_cache_len(), 1);
771 assert_eq!(cache.slru.protected_len(), 2);
772 assert_eq!(cache.slru.probationary_len(), 0);
773
774 assert_eq!(cache.put(3, 33), PutResult::Update(3));
775
776 assert_eq!(cache.lru.peek_lru(), Some((&2, &22)));
781 assert_eq!(cache.slru.peek_lru_from_protected(), Some((&1, &11)));
782 assert_eq!(cache.slru.peek_mru_from_protected(), Some((&3, &33)));
783 assert_eq!(cache.window_cache_len(), 1);
784 assert_eq!(cache.slru.protected_len(), 2);
785 assert_eq!(cache.slru.probationary_len(), 0);
786
787 assert_eq!(cache.put(4, 4), PutResult::Put);
788 assert_eq!(cache.put(5, 5), PutResult::Put);
789
790 assert_eq!(cache.lru.peek_lru(), Some((&5, &5)));
795 assert_eq!(cache.slru.peek_lru_from_probationary(), Some((&2, &22)));
796 assert_eq!(cache.slru.peek_mru_from_probationary(), Some((&4, &4)));
797 assert_eq!(cache.lru.len(), 1);
798 assert_eq!(cache.slru.protected_len(), 2);
799 assert_eq!(cache.slru.probationary_len(), 2);
800
801 assert_eq!(cache.get(&4), Some(&4));
802 assert_eq!(cache.get_mut(&5), Some(&mut 5));
803
804 assert_eq!(cache.lru.peek_lru(), Some((&5, &5)));
809 assert_eq!(cache.slru.peek_lru_from_probationary(), Some((&2, &22)));
810 assert_eq!(cache.slru.peek_mru_from_probationary(), Some((&1, &11)));
811 assert_eq!(cache.slru.peek_lru_from_protected(), Some((&3, &33)));
812 assert_eq!(cache.slru.peek_mru_from_protected(), Some((&4, &4)));
813 assert_eq!(cache.lru.len(), 1);
814 assert_eq!(cache.slru.protected_len(), 2);
815 assert_eq!(cache.slru.probationary_len(), 2);
816
817 assert_eq!(cache.peek(&3), Some(&33));
818 assert_eq!(cache.peek_mut(&2), Some(&mut 22));
819
820 assert_eq!(cache.remove(&3), Some(33));
821 assert_eq!(cache.remove(&2), Some(22));
822 }
823
824 #[test]
825 fn test_wtinylfu() {
826 let mut cache = WTinyLFUCache::with_sizes(1, 2, 2, 5).unwrap();
827 assert_eq!(cache.cap(), 5);
828 assert_eq!(cache.window_cache_cap(), 1);
829 assert_eq!(cache.main_cache_cap(), 4);
830
831 assert_eq!(cache.put(1, 1), PutResult::Put);
832 assert!(cache.contains(&1));
833 assert_eq!(cache.put(2, 2), PutResult::Put);
834 assert!(cache.contains(&2));
835 assert_eq!(cache.put(3, 3), PutResult::Put);
836 assert!(cache.contains(&3));
837
838 assert_eq!(cache.window_cache_len(), 1);
843 assert_eq!(cache.main_cache_len(), 2);
844
845 assert_eq!(cache.put(2, 22), PutResult::Update(2));
846 assert_eq!(cache.put(1, 11), PutResult::Update(1));
847
848 assert_eq!(cache.slru.peek_lru_from_protected(), Some((&2, &22)));
853 assert_eq!(cache.slru.peek_mru_from_protected(), Some((&1, &11)));
854 assert_eq!(cache.window_cache_len(), 1);
855 assert_eq!(cache.slru.protected_len(), 2);
856 assert_eq!(cache.slru.probationary_len(), 0);
857
858 assert_eq!(cache.put(3, 33), PutResult::Update(3));
859
860 assert_eq!(cache.lru.peek_lru(), Some((&2, &22)));
865 assert_eq!(cache.slru.peek_lru_from_protected(), Some((&1, &11)));
866 assert_eq!(cache.slru.peek_mru_from_protected(), Some((&3, &33)));
867 assert_eq!(cache.window_cache_len(), 1);
868 assert_eq!(cache.slru.protected_len(), 2);
869 assert_eq!(cache.slru.probationary_len(), 0);
870
871 assert_eq!(cache.put(4, 4), PutResult::Put);
872 assert_eq!(cache.put(5, 5), PutResult::Put);
873
874 assert_eq!(cache.lru.peek_lru(), Some((&5, &5)));
879 assert_eq!(cache.slru.peek_lru_from_probationary(), Some((&2, &22)));
880 assert_eq!(cache.slru.peek_mru_from_probationary(), Some((&4, &4)));
881 assert_eq!(cache.lru.len(), 1);
882 assert_eq!(cache.slru.protected_len(), 2);
883 assert_eq!(cache.slru.probationary_len(), 2);
884
885 assert_eq!(cache.get(&4), Some(&4));
886 assert_eq!(cache.get_mut(&5), Some(&mut 5));
887
888 assert_eq!(cache.lru.peek_lru(), Some((&5, &5)));
893 assert_eq!(cache.slru.peek_lru_from_probationary(), Some((&2, &22)));
894 assert_eq!(cache.slru.peek_mru_from_probationary(), Some((&1, &11)));
895 assert_eq!(cache.slru.peek_lru_from_protected(), Some((&3, &33)));
896 assert_eq!(cache.slru.peek_mru_from_protected(), Some((&4, &4)));
897 assert_eq!(cache.lru.len(), 1);
898 assert_eq!(cache.slru.protected_len(), 2);
899 assert_eq!(cache.slru.probationary_len(), 2);
900
901 assert_eq!(cache.peek(&3), Some(&33));
902 assert_eq!(cache.peek_mut(&2), Some(&mut 22));
903
904 assert_eq!(cache.remove(&3), Some(33));
905 assert_eq!(cache.remove(&2), Some(22));
906 }
907
908 #[test]
909 fn test_wtinylfu_clone() {
910 let mut cache = WTinyLFUCache::with_sizes(1, 2, 2, 5).unwrap();
911 assert_eq!(cache.cap(), 5);
912 assert_eq!(cache.window_cache_cap(), 1);
913 assert_eq!(cache.main_cache_cap(), 4);
914
915 assert_eq!(cache.put(1, 1), PutResult::Put);
916 assert!(cache.contains(&1));
917 assert_eq!(cache.put(2, 2), PutResult::Put);
918 assert!(cache.contains(&2));
919 assert_eq!(cache.put(3, 3), PutResult::Put);
920 assert!(cache.contains(&3));
921
922 assert_eq!(cache.put(4, 3), PutResult::Evicted { key: 1, value: 1 });
923 }
924}