associative_cache/lib.rs
1//! This crate provides a generic, fixed-size, N-way associative cache data
2//! structure that supports random and least recently used replacement (or your
3//! own custom algorithm).
4//!
5//! Dive into the documentation for
6//! [`AssociativeCache`](./struct.AssociativeCache.html) to begin.
7
8#![deny(missing_docs, missing_debug_implementations)]
9
10pub mod capacity;
11pub mod entry;
12pub mod indices;
13pub mod iter;
14pub mod replacement;
15
16pub use capacity::*;
17pub use entry::*;
18pub use indices::*;
19pub use iter::*;
20pub use replacement::*;
21
22use std::borrow::Borrow;
23use std::cmp::max;
24use std::marker::PhantomData;
25use std::mem;
26
27/// A constant cache capacity.
28///
29/// ## Provided `Capacity` Implementations
30///
31/// This crate defines all power-of-two capacities up to 8192 as
32/// `associative_cache::CapacityN`.
33///
34/// ```
35/// use associative_cache::Capacity256;
36/// ```
37///
38/// ## Defining Custom Cache Capacities
39///
40/// You may implement this trait yourself to define your own custom cache
41/// capacities:
42///
43/// ```
44/// use associative_cache::Capacity;
45///
46/// pub struct Capacity42;
47///
48/// impl Capacity for Capacity42 {
49/// const CAPACITY: usize = 42;
50/// }
51/// ```
52pub trait Capacity {
53 /// The constant capacity for a cache.
54 ///
55 /// Must be greater than zero.
56 const CAPACITY: usize;
57}
58
59/// Given a cache key, return all the slots within the cache where its entry
60/// might be.
61///
62/// ## Associativity
63///
64/// The associativity of a cache is how many slots in the cache a key might
65/// reside in. There are generally many more possible values than there is
66/// capacity in the cache. Allowing a entry to be in one of multiple slots
67/// within the cache raises the cache hit rate, but takes a little extra time
68/// when querying the cache because each of those multiple slots need to be
69/// considered.
70///
71/// * **Direct-mapped:** A cache key corresponds to only one possible slot in
72/// the cache.
73///
74/// * **Two-way:** A cache key corresponds to two possible slots in the cache.
75///
76/// * **Four-way:** A cache key corresponds to four possible slots in the cache.
77///
78/// * Etc...
79///
80/// [Wikipedia has more details on cache
81/// associativity.](https://en.wikipedia.org/wiki/CPU_cache#Associativity)
82///
83/// ## Provided Implementations
84///
85/// This crate provides two flavors of associativity out of the box:
86///
87/// 1. `Hash`-based implementations: `HashDirectMapped` and
88/// `Hash{Two,Four,Eight,Sixteen,ThirtyTwo}Way` provide various associativity
89/// levels based on the key's `Hash` implementation.
90///
91/// 2. Pointer-based implementations: `PointerDirectMapped` and
92/// `Pointer{Two,Four,Eight,Sixteen,ThirtyTwo}Way` provide various
93/// associativity levels based on the pointer value, taking advantage of its
94/// referenced type's alignment. This will generally provide faster lookups
95/// than hashing, but is less general.
96///
97/// ## Custom Implementation Requirements
98///
99/// Implementations must be determinisitc.
100///
101/// All indices yielded must be within the capacity.
102///
103/// The iterator must always be non-empty.
104///
105/// For example, to implement a two-way cache, return an iterator of two
106/// indices.
107pub trait Indices<K, C>
108where
109 K: ?Sized,
110 C: Capacity,
111{
112 /// The iterator over indices within the range `0..C::CAPACITY` yielding the
113 /// slots in the cache where the key's entry might reside.
114 type Indices: ExactSizeIterator<Item = usize>;
115
116 /// Get the indices within the range `0..C::CAPACITY` representing slots in
117 /// the cache where the given key's entry might reside.
118 fn indices(key: &K) -> Self::Indices;
119}
120
121/// Given that we need to replace a cache entry when inserting a new one, consider
122/// each `(index, entry)` pair and return the index whose entry should be
123/// replaced.
124///
125/// The given iterator will always be non-empty, and its indices will always be
126/// within the capacity, assuming the `Indices` that this is paired with is
127/// conformant.
128pub trait Replacement<V, C: Capacity> {
129 /// Choose which of the given cache entries will be replaced.
130 fn choose_for_replacement<'a>(
131 &mut self,
132 candidates: impl ExactSizeIterator<Item = (usize, &'a V)>,
133 ) -> usize
134 where
135 V: 'a;
136
137 /// Called whenever an existing cache entry is hit.
138 fn on_hit(&self, value: &V) {
139 let _ = value;
140 }
141
142 /// Called whenever a new cache entry is inserted.
143 fn on_insert(&self, value: &V) {
144 let _ = value;
145 }
146}
147
148/// A fixed-size associative cache mapping `K` keys to `V` values.
149///
150/// ## Capacity
151///
152/// The cache has a constant, fixed-size capacity which is controlled by the `C`
153/// type parameter and the `Capacity` trait. The memory for the cache entries is
154/// eagerly allocated once and never resized.
155///
156/// ## Associativity
157///
158/// The cache can be configured as direct-mapped, two-way associative, four-way
159/// associative, etc... via the `I` type parameter and `Indices` trait.
160///
161/// ## Replacement Policy
162///
163/// Can be configured to replace the least-recently used entry, or a random
164/// entry via the `R` type parameter and the `Replacement` trait.
165///
166/// ## Examples
167///
168/// ```
169/// # #[cfg(feature = "rand")]
170/// # {
171/// use associative_cache::*;
172///
173/// // A two-way associative cache with random replacement mapping
174/// // `String`s to `usize`s.
175/// let cache = AssociativeCache::<
176/// String,
177/// usize,
178/// Capacity512,
179/// HashTwoWay,
180/// RandomReplacement
181/// >::default();
182///
183/// // A four-way associative cache with random replacement mapping
184/// // `*mut usize`s to `Vec<u8>`s.
185/// let cache = AssociativeCache::<
186/// *mut usize,
187/// Vec<u8>,
188/// Capacity32,
189/// PointerFourWay,
190/// RandomReplacement
191/// >::default();
192///
193/// // An eight-way associative, least recently used (LRU) cache mapping
194/// // `std::path::PathBuf`s to `std::fs::File`s.
195/// let cache = AssociativeCache::<
196/// std::path::PathBuf,
197/// WithLruTimestamp<std::fs::File>,
198/// Capacity128,
199/// HashEightWay,
200/// LruReplacement,
201/// >::default();
202/// # }
203/// ```
204#[derive(Debug)]
205pub struct AssociativeCache<K, V, C, I, R>
206where
207 C: Capacity,
208 R: Replacement<V, C>,
209{
210 entries: Vec<Option<(K, V)>>,
211 len: usize,
212 replacement_policy: R,
213 _capacity: PhantomData<C>,
214 _indices: PhantomData<I>,
215}
216
217impl<K, V, C, I, R> Default for AssociativeCache<K, V, C, I, R>
218where
219 C: Capacity,
220 R: Default + Replacement<V, C>,
221{
222 fn default() -> Self {
223 AssociativeCache::with_replacement_policy(R::default())
224 }
225}
226
227impl<K, V, C, I, R> AssociativeCache<K, V, C, I, R>
228where
229 C: Capacity,
230 R: Replacement<V, C>,
231{
232 /// Construct an `AssociativeCache` with the given replacement policy.
233 ///
234 /// ## Example
235 ///
236 /// ```
237 /// # #[cfg(feature = "rand")]
238 /// # {
239 /// use associative_cache::*;
240 /// use rand::{rngs::StdRng, SeedableRng};
241 /// use std::path::PathBuf;
242 /// use std::fs::File;
243 ///
244 /// // Note: `RandomReplacement` requires the "rand" feature to be enabled.
245 /// let policy = RandomReplacement::with_rng(StdRng::seed_from_u64(42));
246 ///
247 /// let cache = AssociativeCache::<
248 /// PathBuf,
249 /// File,
250 /// Capacity128,
251 /// HashEightWay,
252 /// _,
253 /// >::with_replacement_policy(policy);
254 /// # }
255 /// ```
256 pub fn with_replacement_policy(replacement_policy: R) -> Self {
257 assert!(C::CAPACITY > 0);
258 let mut entries = Vec::with_capacity(C::CAPACITY);
259 for _ in 0..C::CAPACITY {
260 entries.push(None);
261 }
262 AssociativeCache {
263 entries,
264 len: 0,
265 replacement_policy,
266 _capacity: PhantomData,
267 _indices: PhantomData,
268 }
269 }
270
271 /// Get a shared reference to this cache's replacement policy.
272 #[inline]
273 pub fn replacement_policy(&self) -> &R {
274 &self.replacement_policy
275 }
276
277 /// Get an exclusive reference to this cache's replacement policy.
278 #[inline]
279 pub fn replacement_policy_mut(&mut self) -> &mut R {
280 &mut self.replacement_policy
281 }
282
283 /// Get this cache's constant capacity, aka `C::CAPACITY`.
284 #[inline]
285 pub fn capacity(&self) -> usize {
286 assert_eq!(self.entries.len(), C::CAPACITY);
287 C::CAPACITY
288 }
289
290 /// Get the number of entries in this cache.
291 ///
292 /// This is always less than or equal to the capacity.
293 ///
294 /// ## Example
295 ///
296 /// ```
297 /// use associative_cache::*;
298 ///
299 /// let mut cache = AssociativeCache::<
300 /// String,
301 /// usize,
302 /// Capacity16,
303 /// HashDirectMapped,
304 /// RoundRobinReplacement,
305 /// >::default();
306 ///
307 /// // Initially, the cache is empty.
308 /// assert_eq!(cache.len(), 0);
309 ///
310 /// let old_entry = cache.insert("hi".to_string(), 2);
311 ///
312 /// // We know the cache was empty, so there can't be an old entry that was
313 /// // replaced.
314 /// assert!(old_entry.is_none());
315 ///
316 /// // And now the length is 1.
317 /// assert_eq!(cache.len(), 1);
318 ///
319 /// // Insert another entry. If this doesn't conflict with the existing
320 /// // entry, then we should have a length of 2. If it did conflict, and we
321 /// // replaced the old entry, then we should still have a length of 1.
322 /// if cache.insert("bye".to_string(), 3).is_none() {
323 /// assert_eq!(cache.len(), 2);
324 /// } else {
325 /// assert_eq!(cache.len(), 1);
326 /// }
327 /// ```
328 #[inline]
329 pub fn len(&self) -> usize {
330 debug_assert!(self.len <= self.capacity());
331 self.len
332 }
333
334 /// Return `true` if there are zero entries in the cache.
335 #[inline]
336 pub fn is_empty(&self) -> bool {
337 self.len == 0
338 }
339
340 /// Insert a new entry into the cache.
341 ///
342 /// If there is an old entry for this key, or if another entry ends up
343 /// getting replaced by this new one, return the old entry.
344 ///
345 /// ## Example
346 ///
347 /// ```
348 /// use associative_cache::*;
349 ///
350 /// let mut cache = AssociativeCache::<
351 /// String,
352 /// usize,
353 /// Capacity1,
354 /// HashDirectMapped,
355 /// RoundRobinReplacement,
356 /// >::default();
357 ///
358 /// // Insert an entry for "hi" into the cache.
359 /// let old_entry = cache.insert("hi".to_string(), 42);
360 ///
361 /// // The cache was empty, so no old entry.
362 /// assert!(old_entry.is_none());
363 ///
364 /// // Insert an entry for "bye" into the cache.
365 /// let old_entry = cache.insert("bye".to_string(), 1337);
366 ///
367 /// // Because the cache only has a capacity of one, we replaced "hi" when
368 /// // inserting "bye".
369 /// assert_eq!(old_entry, Some(("hi".to_string(), 42)));
370 /// ```
371 pub fn insert(&mut self, key: K, value: V) -> Option<(K, V)>
372 where
373 I: Indices<K, C>,
374 K: PartialEq,
375 {
376 let capacity = self.capacity();
377
378 #[derive(Ord, PartialOrd, Eq, PartialEq)]
379 enum InsertionCandidate {
380 New(usize),
381 Replace(usize),
382 }
383 assert!(None < Some(InsertionCandidate::New(0)));
384 assert!(InsertionCandidate::New(0) < InsertionCandidate::Replace(0));
385
386 // First see if we can insert the value to an existing entry for this
387 // key, or without replaceing any other entry.
388 let mut best = None;
389 for index in I::indices(&key) {
390 assert!(
391 index < capacity,
392 "`Indices::indices` must always yield indices within the capacity"
393 );
394 match self.entries[index] {
395 None => {
396 best = max(best, Some(InsertionCandidate::New(index)));
397 }
398 Some((ref k, _)) if *k == key => {
399 best = max(best, Some(InsertionCandidate::Replace(index)));
400 }
401 _ => continue,
402 }
403 }
404
405 match best {
406 None => {}
407 Some(InsertionCandidate::New(index)) => {
408 self.entries[index] = Some((key, value));
409 self.len += 1;
410 return None;
411 }
412 Some(InsertionCandidate::Replace(index)) => {
413 return mem::replace(&mut self.entries[index], Some((key, value)));
414 }
415 }
416
417 // Okay, we have to replace an entry. Let the `ReplacementPolicy` decide
418 // which one.
419 let AssociativeCache {
420 ref entries,
421 ref mut replacement_policy,
422 ..
423 } = self;
424 let candidates = I::indices(&key).map(|index| {
425 assert!(
426 index < capacity,
427 "`I::indices` must always yield indices within the capacity"
428 );
429 let value = &entries[index]
430 .as_ref()
431 // We know that all the indices we saw above are full, so the
432 // only way this `expect` would fail is if `Indices::indices` is
433 // non-deterministic.
434 .expect(
435 "`Indices::indices` must always yield the same indices for the same entries",
436 )
437 .1;
438 (index, value)
439 });
440 let index = replacement_policy.choose_for_replacement(candidates);
441 debug_assert!(
442 I::indices(&key).any(|i| i == index),
443 "`ReplacementPolicy::choose_for_replacement` must return a candidate index"
444 );
445 assert!(index < capacity);
446 assert!(self.entries[index].is_some());
447 mem::replace(&mut self.entries[index], Some((key, value)))
448 }
449
450 /// Get a shared reference to the value for a given key, if it exists in the
451 /// cache.
452 ///
453 /// ## Example
454 ///
455 /// ```
456 /// use associative_cache::*;
457 ///
458 /// let mut cache = AssociativeCache::<
459 /// String,
460 /// usize,
461 /// Capacity1,
462 /// HashDirectMapped,
463 /// RoundRobinReplacement,
464 /// >::default();
465 ///
466 /// // Returns `None` if there is no cache entry for the key.
467 /// assert!(cache.get("hi").is_none());
468 ///
469 /// cache.insert("hi".to_string(), 1234);
470 ///
471 /// // Otherwise, returns the value if there is an entry for the key.
472 /// assert_eq!(cache.get("hi"), Some(&1234));
473 /// ```
474 #[inline]
475 pub fn get<Q>(&self, key: &Q) -> Option<&V>
476 where
477 K: Borrow<Q>,
478 I: Indices<Q, C>,
479 Q: ?Sized + PartialEq,
480 {
481 assert_eq!(self.entries.len(), C::CAPACITY);
482
483 for index in I::indices(key) {
484 assert!(
485 index < self.entries.len(),
486 "`Indices::indices` must always yield indices within the capacity"
487 );
488 match &self.entries[index] {
489 Some((k, v)) if k.borrow() == key => {
490 self.replacement_policy.on_hit(v);
491 return Some(v);
492 }
493 _ => continue,
494 }
495 }
496
497 None
498 }
499
500 /// Get an exclusive reference to the value for a given key, if it exists in
501 /// the cache.
502 ///
503 /// ## Example
504 ///
505 /// ```
506 /// use associative_cache::*;
507 ///
508 /// let mut cache = AssociativeCache::<
509 /// String,
510 /// usize,
511 /// Capacity1,
512 /// HashDirectMapped,
513 /// RoundRobinReplacement,
514 /// >::default();
515 ///
516 /// // Returns `None` if there is no cache entry for the key.
517 /// assert!(cache.get_mut("hi").is_none());
518 ///
519 /// cache.insert("hi".to_string(), 1234);
520 ///
521 /// // Otherwise, returns the value if there is an entry for the key.
522 /// let val = cache.get_mut("hi").unwrap();
523 /// assert_eq!(*val, 1234);
524 ///
525 /// // And we can assign to the cache value.
526 /// *val = 5678;
527 /// ```
528 #[inline]
529 pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
530 where
531 K: Borrow<Q>,
532 I: Indices<Q, C>,
533 Q: ?Sized + PartialEq,
534 {
535 assert_eq!(self.entries.len(), C::CAPACITY);
536
537 for index in I::indices(key) {
538 assert!(
539 index < C::CAPACITY,
540 "`Indices::indices` must always yield indices within the capacity"
541 );
542 match &self.entries[index] {
543 Some((k, _)) if k.borrow() == key => {
544 let v = &mut self.entries[index].as_mut().unwrap().1;
545 self.replacement_policy.on_hit(v);
546 return Some(v);
547 }
548 _ => continue,
549 }
550 }
551
552 None
553 }
554
555 /// Remove an entry from the cache.
556 ///
557 /// If an entry for the key existed in the cache, it is removed and `Some`
558 /// is returned. Otherwise, `None` is returned.
559 ///
560 /// ## Example
561 ///
562 /// ```
563 /// use associative_cache::*;
564 ///
565 /// let mut cache = AssociativeCache::<
566 /// String,
567 /// usize,
568 /// Capacity1,
569 /// HashDirectMapped,
570 /// RoundRobinReplacement,
571 /// >::default();
572 ///
573 /// // Returns `None` if there is no cache entry for the key and therefore
574 /// // nothing was removed.
575 /// assert!(cache.remove("hi").is_none());
576 ///
577 /// cache.insert("hi".to_string(), 1234);
578 ///
579 /// // Otherwise, returns the value that was removed if there was an entry
580 /// // for the key.
581 /// assert_eq!(cache.remove("hi"), Some(1234));
582
583 /// ```
584 #[inline]
585 pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
586 where
587 K: Borrow<Q>,
588 I: Indices<Q, C>,
589 Q: ?Sized + PartialEq,
590 {
591 assert_eq!(self.entries.len(), C::CAPACITY);
592
593 for index in I::indices(key) {
594 assert!(
595 index < self.entries.len(),
596 "`Indices::indices` must always yield indices within the capacity"
597 );
598 match &self.entries[index] {
599 Some((k, _)) if k.borrow() == key => {
600 self.len -= 1;
601 return self.entries[index].take().map(|(_, v)| v);
602 }
603 _ => continue,
604 }
605 }
606
607 None
608 }
609
610 /// Retain only the cache entries specified by the predicate.
611 ///
612 /// Calls `f` with each entry in the cache, and removes all entries where
613 /// `f` returned false.
614 ///
615 /// ## Example
616 ///
617 /// ```
618 /// use associative_cache::*;
619 ///
620 /// let mut cache = AssociativeCache::<
621 /// char,
622 /// usize,
623 /// Capacity8,
624 /// HashDirectMapped,
625 /// RoundRobinReplacement,
626 /// >::default();
627 ///
628 /// for (i, ch) in "I let my tape rock, 'til my tape popped".char_indices() {
629 /// cache.insert(ch, i);
630 /// }
631 ///
632 /// for (key, val) in cache.iter() {
633 /// println!("Last saw character '{}' at index {}", key, val);
634 /// }
635 /// ```
636 pub fn retain(&mut self, mut f: impl FnMut(&K, &mut V) -> bool) {
637 for e in &mut self.entries {
638 if let Some((k, v)) = e {
639 if !f(k, v) {
640 *e = None;
641 self.len -= 1;
642 }
643 }
644 }
645 }
646
647 /// Get the key's corresponding slot within the cache for in-place mutation
648 /// and performing get-or-create operations.
649 ///
650 /// ## Example
651 ///
652 /// ```
653 /// use associative_cache::*;
654 ///
655 /// let mut cache = AssociativeCache::<
656 /// String,
657 /// usize,
658 /// Capacity4,
659 /// HashTwoWay,
660 /// RoundRobinReplacement,
661 /// >::default();
662 ///
663 /// for word in "she sells sea shells down by the sea shore".split_whitespace() {
664 /// let count = cache.entry(word).or_insert_with(
665 /// || word.to_string(),
666 /// || 0,
667 /// );
668 /// *count += 1;
669 /// }
670 /// ```
671 #[inline]
672 pub fn entry<Q>(&mut self, key: &Q) -> Entry<K, V, C, I, R>
673 where
674 K: Borrow<Q>,
675 I: Indices<Q, C>,
676 Q: ?Sized + PartialEq,
677 {
678 let capacity = self.capacity();
679
680 // First, see if we have an entry for this key, or if we have an empty
681 // slot where an entry could be placed without replaceing another entry.
682 let mut empty_index = None;
683 for index in I::indices(key) {
684 assert!(
685 index < capacity,
686 "`Indices::indices` must always yield indices within the capacity"
687 );
688 match &mut self.entries[index] {
689 None => {
690 empty_index = Some(index);
691 }
692 Some((k, v)) if (*k).borrow() == key => {
693 self.replacement_policy.on_hit(v);
694 return Entry {
695 cache: self,
696 kind: EntryKind::Occupied,
697 index,
698 };
699 }
700 _ => continue,
701 }
702 }
703 if let Some(index) = empty_index {
704 return Entry {
705 cache: self,
706 kind: EntryKind::Vacant,
707 index,
708 };
709 }
710
711 // Okay, we have to return an already-in-use entry, which will be
712 // replaced if the user inserts anything.
713 let AssociativeCache {
714 ref entries,
715 ref mut replacement_policy,
716 ..
717 } = self;
718 let candidates = I::indices(key).map(|index| {
719 assert!(
720 index < capacity,
721 "`I::indices` must always yield indices within the capacity"
722 );
723 let value = &entries[index]
724 .as_ref()
725 // We know that all the indices we saw above are full, so the
726 // only way this `expect` would fail is if `Indices::indices` is
727 // non-deterministic.
728 .expect(
729 "`Indices::indices` must always yield the same indices for the same entries",
730 )
731 .1;
732 (index, value)
733 });
734 let index = replacement_policy.choose_for_replacement(candidates);
735 Entry {
736 cache: self,
737 kind: EntryKind::Replace,
738 index,
739 }
740 }
741
742 /// Iterate over shared references to this cache's keys and values.
743 ///
744 /// ## Example
745 ///
746 /// ```
747 /// use associative_cache::*;
748 ///
749 /// let mut cache = AssociativeCache::<
750 /// String,
751 /// usize,
752 /// Capacity4,
753 /// HashTwoWay,
754 /// RoundRobinReplacement,
755 /// >::default();
756 ///
757 /// // First, insert some entries into the cache. Note that this is more
758 /// // entries than the cache has capacity for.
759 /// for s in vec!["red", "blue", "green", "pink", "purple", "orange"] {
760 /// cache.insert(s.to_string(), s.len());
761 /// }
762 ///
763 /// // Now iterate over the entries that are still in the cache:
764 /// for (k, v) in cache.iter() {
765 /// println!("{} -> {}", k, v);
766 /// }
767 /// ```
768 #[inline]
769 pub fn iter(&self) -> Iter<K, V> {
770 <&Self as IntoIterator>::into_iter(self)
771 }
772
773 /// Iterate over shared references to this cache's keys and exclusive
774 /// references to its values.
775 ///
776 /// ## Example
777 ///
778 /// ```
779 /// use associative_cache::*;
780 ///
781 /// let mut cache = AssociativeCache::<
782 /// String,
783 /// usize,
784 /// Capacity4,
785 /// HashTwoWay,
786 /// RoundRobinReplacement,
787 /// >::default();
788 ///
789 /// // First, insert some entries into the cache. Note that this is more
790 /// // entries than the cache has capacity for.
791 /// for s in vec!["red", "blue", "green", "pink", "purple", "orange"] {
792 /// cache.insert(s.to_string(), s.len());
793 /// }
794 ///
795 /// // Now iterate over the entries that are still in the cache and mutate
796 /// // them:
797 /// for (k, v) in cache.iter_mut() {
798 /// println!("{} was {}...", k, v);
799 /// *v += 1;
800 /// println!("...but now it's {}!", v);
801 /// }
802 /// ```
803 #[inline]
804 pub fn iter_mut(&mut self) -> IterMut<K, V> {
805 <&mut Self as IntoIterator>::into_iter(self)
806 }
807
808 /// Consume this cache, and iterate over its keys and values.
809 ///
810 /// ## Example
811 ///
812 /// ```
813 /// use associative_cache::*;
814 ///
815 /// let mut cache = AssociativeCache::<
816 /// String,
817 /// usize,
818 /// Capacity4,
819 /// HashTwoWay,
820 /// RoundRobinReplacement,
821 /// >::default();
822 ///
823 /// // First, insert some entries into the cache. Note that this is more
824 /// // entries than the cache has capacity for.
825 /// for s in vec!["red", "blue", "green", "pink", "purple", "orange"] {
826 /// cache.insert(s.to_string(), s.len());
827 /// }
828 ///
829 /// // Not possible with `iter` or `iter_mut` without cloning.
830 /// let v: Vec<(String, usize)> = cache.into_iter().collect();
831 /// ```
832 #[inline]
833 #[allow(clippy::should_implement_trait)]
834 pub fn into_iter(self) -> IntoIter<K, V> {
835 <Self as IntoIterator>::into_iter(self)
836 }
837}
838
839#[cfg(test)]
840mod tests {
841 use super::*;
842
843 #[test]
844 fn replacement_policy() {
845 let mut policy = RoundRobinReplacement::default();
846 let mut cache = AssociativeCache::<usize, usize, Capacity4, HashDirectMapped,_>::with_replacement_policy(policy.clone());
847 assert_eq!(cache.replacement_policy(), &policy);
848 assert_eq!(cache.replacement_policy_mut(), &mut policy);
849 }
850
851 #[test]
852 fn capacity() {
853 let cache = AssociativeCache::<
854 usize,
855 usize,
856 Capacity2,
857 HashDirectMapped,
858 RoundRobinReplacement,
859 >::default();
860 assert_eq!(cache.capacity(), 2);
861
862 let cache = AssociativeCache::<
863 usize,
864 usize,
865 Capacity4,
866 HashDirectMapped,
867 RoundRobinReplacement,
868 >::default();
869 assert_eq!(cache.capacity(), 4);
870
871 let cache = AssociativeCache::<
872 usize,
873 usize,
874 Capacity8,
875 HashDirectMapped,
876 RoundRobinReplacement,
877 >::default();
878 assert_eq!(cache.capacity(), 8);
879 }
880
881 #[test]
882 fn len() {
883 let mut cache = AssociativeCache::<
884 usize,
885 usize,
886 Capacity512,
887 HashDirectMapped,
888 RoundRobinReplacement,
889 >::default();
890
891 assert_eq!(cache.insert(1, 2), None);
892 assert_eq!(cache.len(), 1);
893 assert_eq!(cache.insert(3, 4), None);
894 assert_eq!(cache.len(), 2);
895 assert_eq!(cache.insert(5, 6), None);
896 assert_eq!(cache.len(), 3);
897
898 cache.insert(1, 7).unwrap();
899 assert_eq!(cache.len(), 3);
900 cache.insert(3, 8).unwrap();
901 assert_eq!(cache.len(), 3);
902 cache.insert(5, 9).unwrap();
903 assert_eq!(cache.len(), 3);
904 }
905
906 #[test]
907 fn insert() {
908 let mut cache = AssociativeCache::<
909 *mut u8,
910 usize,
911 Capacity4,
912 PointerTwoWay,
913 RoundRobinReplacement,
914 >::default();
915
916 // Fill all the cache slots.
917 assert_eq!(cache.insert(0 as *mut u8, 0), None);
918 assert_eq!(cache.insert(1 as *mut u8, 1), None);
919 assert_eq!(cache.insert(2 as *mut u8, 2), None);
920 assert_eq!(cache.insert(3 as *mut u8, 3), None);
921
922 // Start replacing old entries with new insertions.
923 assert_eq!(cache.insert(4 as *mut u8, 4), Some((2 as *mut u8, 2)));
924 assert_eq!(cache.insert(6 as *mut u8, 6), Some((0 as *mut u8, 0)));
925 assert_eq!(cache.insert(5 as *mut u8, 5), Some((3 as *mut u8, 3)));
926 assert_eq!(cache.insert(7 as *mut u8, 7), Some((1 as *mut u8, 1)));
927 }
928
929 #[test]
930 fn get() {
931 let mut cache = AssociativeCache::<
932 *mut u8,
933 usize,
934 Capacity4,
935 PointerTwoWay,
936 RoundRobinReplacement,
937 >::default();
938
939 cache.insert(0 as *mut _, 0);
940 assert_eq!(cache.get(&(0 as *mut _)), Some(&0));
941 assert_eq!(cache.get(&(1 as *mut _)), None);
942
943 cache.insert(4 as *mut _, 4);
944 assert_eq!(cache.get(&(0 as *mut _)), Some(&0));
945 assert_eq!(cache.get(&(4 as *mut _)), Some(&4));
946 assert_eq!(cache.get(&(1 as *mut _)), None);
947
948 assert_eq!(cache.insert(8 as *mut _, 8), Some((4 as *mut _, 4)));
949 assert_eq!(cache.get(&(0 as *mut _)), Some(&0));
950 assert_eq!(cache.get(&(8 as *mut _)), Some(&8));
951 assert_eq!(cache.get(&(1 as *mut _)), None);
952 }
953
954 #[test]
955 fn get_mut() {
956 let mut cache = AssociativeCache::<
957 *mut u8,
958 usize,
959 Capacity4,
960 PointerTwoWay,
961 RoundRobinReplacement,
962 >::default();
963
964 cache.insert(0 as *mut _, 0);
965 assert_eq!(cache.get_mut(&(0 as *mut _)), Some(&mut 0));
966 assert_eq!(cache.get_mut(&(1 as *mut _)), None);
967
968 cache.insert(4 as *mut _, 4);
969 assert_eq!(cache.get_mut(&(0 as *mut _)), Some(&mut 0));
970 assert_eq!(cache.get_mut(&(4 as *mut _)), Some(&mut 4));
971 assert_eq!(cache.get_mut(&(1 as *mut _)), None);
972
973 assert_eq!(cache.insert(8 as *mut _, 8), Some((4 as *mut _, 4)));
974 assert_eq!(cache.get_mut(&(0 as *mut _)), Some(&mut 0));
975 assert_eq!(cache.get_mut(&(8 as *mut _)), Some(&mut 8));
976 assert_eq!(cache.get_mut(&(1 as *mut _)), None);
977 }
978
979 #[test]
980 fn remove() {
981 let mut cache = AssociativeCache::<
982 *mut u8,
983 usize,
984 Capacity4,
985 PointerTwoWay,
986 RoundRobinReplacement,
987 >::default();
988
989 cache.insert(0 as *mut _, 0);
990 cache.insert(4 as *mut _, 4);
991 assert_eq!(cache.len(), 2);
992
993 assert_eq!(cache.remove(&(4 as *mut _)), Some(4));
994 assert_eq!(cache.remove(&(4 as *mut _)), None);
995 assert_eq!(cache.remove(&(0 as *mut _)), Some(0));
996 assert_eq!(cache.remove(&(0 as *mut _)), None);
997 }
998
999 #[test]
1000 fn retain() {
1001 let mut cache = AssociativeCache::<
1002 *mut u8,
1003 usize,
1004 Capacity4,
1005 PointerTwoWay,
1006 RoundRobinReplacement,
1007 >::default();
1008
1009 cache.insert(0 as *mut _, 0);
1010 cache.insert(1 as *mut _, 1);
1011 cache.insert(2 as *mut _, 2);
1012 cache.insert(3 as *mut _, 3);
1013 assert_eq!(cache.len(), 4);
1014
1015 cache.retain(|_, v| *v % 2 == 0);
1016 assert_eq!(cache.len(), 2);
1017 assert_eq!(cache.get(&(0 as *mut _)), Some(&0));
1018 assert_eq!(cache.get(&(1 as *mut _)), None);
1019 assert_eq!(cache.get(&(2 as *mut _)), Some(&2));
1020 assert_eq!(cache.get(&(3 as *mut _)), None);
1021 }
1022
1023 #[test]
1024 fn entry() {
1025 let mut cache = AssociativeCache::<
1026 *mut u8,
1027 usize,
1028 Capacity1,
1029 PointerDirectMapped,
1030 RoundRobinReplacement,
1031 >::default();
1032
1033 // Vacant
1034 assert_eq!(
1035 cache
1036 .entry(&(0 as *mut _))
1037 .or_insert_with(|| 0 as *mut _, || 0),
1038 &mut 0
1039 );
1040 assert_eq!(cache.len(), 1);
1041
1042 // Occupied
1043 assert_eq!(
1044 cache
1045 .entry(&(0 as *mut _))
1046 .or_insert_with(|| unreachable!(), || unreachable!()),
1047 &mut 0
1048 );
1049 assert_eq!(cache.len(), 1);
1050
1051 // Replace
1052 let mut entry = cache.entry(&(1 as *mut _));
1053 assert_eq!(
1054 entry.take_entry_that_will_be_replaced(),
1055 Some((0 as *mut _, 0))
1056 );
1057 assert_eq!(entry.or_insert_with(|| 1 as *mut _, || 1), &mut 1);
1058 assert_eq!(cache.len(), 1);
1059 }
1060
1061 #[test]
1062 fn iter() {
1063 let mut cache = AssociativeCache::<
1064 *mut u8,
1065 usize,
1066 Capacity4,
1067 PointerDirectMapped,
1068 RoundRobinReplacement,
1069 >::default();
1070
1071 cache.insert(0 as *mut _, 0);
1072 cache.insert(1 as *mut _, 1);
1073 cache.insert(2 as *mut _, 2);
1074 cache.insert(3 as *mut _, 3);
1075 assert_eq!(cache.len(), 4);
1076
1077 let mut seen = vec![false; 4];
1078 for (&k, &v) in &cache {
1079 assert!(!seen[v]);
1080 seen[v] = true;
1081 assert_eq!(k as usize, v);
1082 }
1083 assert!(seen.iter().all(|&b| b));
1084 }
1085
1086 #[test]
1087 fn iter_mut() {
1088 let mut cache = AssociativeCache::<
1089 *mut u8,
1090 usize,
1091 Capacity4,
1092 PointerDirectMapped,
1093 RoundRobinReplacement,
1094 >::default();
1095
1096 cache.insert(0 as *mut _, 0);
1097 cache.insert(1 as *mut _, 1);
1098 cache.insert(2 as *mut _, 2);
1099 cache.insert(3 as *mut _, 3);
1100 assert_eq!(cache.len(), 4);
1101
1102 let mut seen = vec![false; 4];
1103 for (&k, v) in &mut cache {
1104 assert!(!seen[*v]);
1105 seen[*v] = true;
1106 assert_eq!(k as usize, *v);
1107 *v += 1;
1108 }
1109 assert!(seen.iter().all(|&b| b));
1110
1111 assert_eq!(cache.get(&(0 as *mut _)), Some(&1));
1112 assert_eq!(cache.get(&(1 as *mut _)), Some(&2));
1113 assert_eq!(cache.get(&(2 as *mut _)), Some(&3));
1114 assert_eq!(cache.get(&(3 as *mut _)), Some(&4));
1115 }
1116
1117 #[test]
1118 fn into_iter() {
1119 let mut cache = AssociativeCache::<
1120 *mut u8,
1121 usize,
1122 Capacity4,
1123 PointerDirectMapped,
1124 RoundRobinReplacement,
1125 >::default();
1126
1127 cache.insert(0 as *mut _, 0);
1128 cache.insert(1 as *mut _, 1);
1129 cache.insert(2 as *mut _, 2);
1130 cache.insert(3 as *mut _, 3);
1131 assert_eq!(cache.len(), 4);
1132
1133 let mut seen = vec![false; 4];
1134 for (k, v) in cache {
1135 assert!(!seen[v]);
1136 seen[v] = true;
1137 assert_eq!(k as usize, v);
1138 }
1139 assert!(seen.iter().all(|&b| b));
1140 }
1141}