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}