AssociativeCache

Struct AssociativeCache 

Source
pub struct AssociativeCache<K, V, C, I, R>
where C: Capacity, R: Replacement<V, C>,
{ /* private fields */ }
Expand description

A fixed-size associative cache mapping K keys to V values.

§Capacity

The cache has a constant, fixed-size capacity which is controlled by the C type parameter and the Capacity trait. The memory for the cache entries is eagerly allocated once and never resized.

§Associativity

The cache can be configured as direct-mapped, two-way associative, four-way associative, etc… via the I type parameter and Indices trait.

§Replacement Policy

Can be configured to replace the least-recently used entry, or a random entry via the R type parameter and the Replacement trait.

§Examples

use associative_cache::*;

// A two-way associative cache with random replacement mapping
// `String`s to `usize`s.
let cache = AssociativeCache::<
    String,
    usize,
    Capacity512,
    HashTwoWay,
    RandomReplacement
>::default();

// A four-way associative cache with random replacement mapping
// `*mut usize`s to `Vec<u8>`s.
let cache = AssociativeCache::<
    *mut usize,
    Vec<u8>,
    Capacity32,
    PointerFourWay,
    RandomReplacement
>::default();

// An eight-way associative, least recently used (LRU) cache mapping
// `std::path::PathBuf`s to `std::fs::File`s.
let cache = AssociativeCache::<
    std::path::PathBuf,
    WithLruTimestamp<std::fs::File>,
    Capacity128,
    HashEightWay,
    LruReplacement,
>::default();

Implementations§

Source§

impl<K, V, C, I, R> AssociativeCache<K, V, C, I, R>
where C: Capacity, R: Replacement<V, C>,

Source

pub fn with_replacement_policy(replacement_policy: R) -> Self

Construct an AssociativeCache with the given replacement policy.

§Example
use associative_cache::*;
use rand::{rngs::StdRng, SeedableRng};
use std::path::PathBuf;
use std::fs::File;

// Note: `RandomReplacement` requires the "rand" feature to be enabled.
let policy = RandomReplacement::with_rng(StdRng::seed_from_u64(42));

let cache = AssociativeCache::<
    PathBuf,
    File,
    Capacity128,
    HashEightWay,
    _,
>::with_replacement_policy(policy);
Source

pub fn replacement_policy(&self) -> &R

Get a shared reference to this cache’s replacement policy.

Source

pub fn replacement_policy_mut(&mut self) -> &mut R

Get an exclusive reference to this cache’s replacement policy.

Source

pub fn capacity(&self) -> usize

Get this cache’s constant capacity, aka C::CAPACITY.

Source

pub fn len(&self) -> usize

Get the number of entries in this cache.

This is always less than or equal to the capacity.

§Example
use associative_cache::*;

let mut cache = AssociativeCache::<
    String,
    usize,
    Capacity16,
    HashDirectMapped,
    RoundRobinReplacement,
>::default();

// Initially, the cache is empty.
assert_eq!(cache.len(), 0);

let old_entry = cache.insert("hi".to_string(), 2);

// We know the cache was empty, so there can't be an old entry that was
// replaced.
assert!(old_entry.is_none());

// And now the length is 1.
assert_eq!(cache.len(), 1);

// Insert another entry. If this doesn't conflict with the existing
// entry, then we should have a length of 2. If it did conflict, and we
// replaced the old entry, then we should still have a length of 1.
if cache.insert("bye".to_string(), 3).is_none() {
    assert_eq!(cache.len(), 2);
} else {
    assert_eq!(cache.len(), 1);
}
Source

pub fn is_empty(&self) -> bool

Return true if there are zero entries in the cache.

Source

pub fn insert(&mut self, key: K, value: V) -> Option<(K, V)>
where I: Indices<K, C>, K: PartialEq,

Insert a new entry into the cache.

If there is an old entry for this key, or if another entry ends up getting replaced by this new one, return the old entry.

§Example
use associative_cache::*;

let mut cache = AssociativeCache::<
    String,
    usize,
    Capacity1,
    HashDirectMapped,
    RoundRobinReplacement,
>::default();

// Insert an entry for "hi" into the cache.
let old_entry = cache.insert("hi".to_string(), 42);

// The cache was empty, so no old entry.
assert!(old_entry.is_none());

// Insert an entry for "bye" into the cache.
let old_entry = cache.insert("bye".to_string(), 1337);

// Because the cache only has a capacity of one, we replaced "hi" when
// inserting "bye".
assert_eq!(old_entry, Some(("hi".to_string(), 42)));
Source

pub fn get<Q>(&self, key: &Q) -> Option<&V>
where K: Borrow<Q>, I: Indices<Q, C>, Q: ?Sized + PartialEq,

Get a shared reference to the value for a given key, if it exists in the cache.

§Example
use associative_cache::*;

let mut cache = AssociativeCache::<
    String,
    usize,
    Capacity1,
    HashDirectMapped,
    RoundRobinReplacement,
>::default();

// Returns `None` if there is no cache entry for the key.
assert!(cache.get("hi").is_none());

cache.insert("hi".to_string(), 1234);

// Otherwise, returns the value if there is an entry for the key.
assert_eq!(cache.get("hi"), Some(&1234));
Source

pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
where K: Borrow<Q>, I: Indices<Q, C>, Q: ?Sized + PartialEq,

Get an exclusive reference to the value for a given key, if it exists in the cache.

§Example
use associative_cache::*;

let mut cache = AssociativeCache::<
    String,
    usize,
    Capacity1,
    HashDirectMapped,
    RoundRobinReplacement,
>::default();

// Returns `None` if there is no cache entry for the key.
assert!(cache.get_mut("hi").is_none());

cache.insert("hi".to_string(), 1234);

// Otherwise, returns the value if there is an entry for the key.
let val = cache.get_mut("hi").unwrap();
assert_eq!(*val, 1234);

// And we can assign to the cache value.
*val = 5678;
Source

pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
where K: Borrow<Q>, I: Indices<Q, C>, Q: ?Sized + PartialEq,

Remove an entry from the cache.

If an entry for the key existed in the cache, it is removed and Some is returned. Otherwise, None is returned.

§Example
use associative_cache::*;

let mut cache = AssociativeCache::<
    String,
    usize,
    Capacity1,
    HashDirectMapped,
    RoundRobinReplacement,
>::default();

// Returns `None` if there is no cache entry for the key and therefore
// nothing was removed.
assert!(cache.remove("hi").is_none());

cache.insert("hi".to_string(), 1234);

// Otherwise, returns the value that was removed if there was an entry
// for the key.
assert_eq!(cache.remove("hi"), Some(1234));
Source

pub fn retain(&mut self, f: impl FnMut(&K, &mut V) -> bool)

Retain only the cache entries specified by the predicate.

Calls f with each entry in the cache, and removes all entries where f returned false.

§Example
use associative_cache::*;

let mut cache = AssociativeCache::<
    char,
    usize,
    Capacity8,
    HashDirectMapped,
    RoundRobinReplacement,
>::default();

for (i, ch) in "I let my tape rock, 'til my tape popped".char_indices() {
    cache.insert(ch, i);
}

for (key, val) in cache.iter() {
    println!("Last saw character '{}' at index {}", key, val);
}
Source

pub fn entry<Q>(&mut self, key: &Q) -> Entry<'_, K, V, C, I, R>
where K: Borrow<Q>, I: Indices<Q, C>, Q: ?Sized + PartialEq,

Get the key’s corresponding slot within the cache for in-place mutation and performing get-or-create operations.

§Example
use associative_cache::*;

let mut cache = AssociativeCache::<
    String,
    usize,
    Capacity4,
    HashTwoWay,
    RoundRobinReplacement,
>::default();

for word in "she sells sea shells down by the sea shore".split_whitespace() {
    let count = cache.entry(word).or_insert_with(
        || word.to_string(),
        || 0,
    );
    *count += 1;
}
Source

pub fn iter(&self) -> Iter<'_, K, V>

Iterate over shared references to this cache’s keys and values.

§Example
use associative_cache::*;

let mut cache = AssociativeCache::<
    String,
    usize,
    Capacity4,
    HashTwoWay,
    RoundRobinReplacement,
>::default();

// First, insert some entries into the cache. Note that this is more
// entries than the cache has capacity for.
for s in vec!["red", "blue", "green", "pink", "purple", "orange"] {
    cache.insert(s.to_string(), s.len());
}

// Now iterate over the entries that are still in the cache:
for (k, v) in cache.iter() {
    println!("{} -> {}", k, v);
}
Source

pub fn iter_mut(&mut self) -> IterMut<'_, K, V>

Iterate over shared references to this cache’s keys and exclusive references to its values.

§Example
use associative_cache::*;

let mut cache = AssociativeCache::<
    String,
    usize,
    Capacity4,
    HashTwoWay,
    RoundRobinReplacement,
>::default();

// First, insert some entries into the cache. Note that this is more
// entries than the cache has capacity for.
for s in vec!["red", "blue", "green", "pink", "purple", "orange"] {
    cache.insert(s.to_string(), s.len());
}

// Now iterate over the entries that are still in the cache and mutate
// them:
for (k, v) in cache.iter_mut() {
    println!("{} was {}...", k, v);
    *v += 1;
    println!("...but now it's {}!", v);
}
Source

pub fn into_iter(self) -> IntoIter<K, V>

Consume this cache, and iterate over its keys and values.

§Example
use associative_cache::*;

let mut cache = AssociativeCache::<
    String,
    usize,
    Capacity4,
    HashTwoWay,
    RoundRobinReplacement,
>::default();

// First, insert some entries into the cache. Note that this is more
// entries than the cache has capacity for.
for s in vec!["red", "blue", "green", "pink", "purple", "orange"] {
    cache.insert(s.to_string(), s.len());
}

// Not possible with `iter` or `iter_mut` without cloning.
let v: Vec<(String, usize)> = cache.into_iter().collect();

Trait Implementations§

Source§

impl<K: Debug, V: Debug, C, I: Debug, R> Debug for AssociativeCache<K, V, C, I, R>
where C: Capacity + Debug, R: Replacement<V, C> + Debug,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<K, V, C, I, R> Default for AssociativeCache<K, V, C, I, R>
where C: Capacity, R: Default + Replacement<V, C>,

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<'a, K, V, C, I, R> IntoIterator for &'a AssociativeCache<K, V, C, I, R>
where C: Capacity, R: Replacement<V, C>,

Source§

type Item = (&'a K, &'a V)

The type of the elements being iterated over.
Source§

type IntoIter = Iter<'a, K, V>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl<'a, K, V, C, I, R> IntoIterator for &'a mut AssociativeCache<K, V, C, I, R>
where C: Capacity, R: Replacement<V, C>,

Source§

type Item = (&'a K, &'a mut V)

The type of the elements being iterated over.
Source§

type IntoIter = IterMut<'a, K, V>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl<K, V, C, I, R> IntoIterator for AssociativeCache<K, V, C, I, R>
where C: Capacity, R: Replacement<V, C>,

Source§

type Item = (K, V)

The type of the elements being iterated over.
Source§

type IntoIter = IntoIter<K, V>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more

Auto Trait Implementations§

§

impl<K, V, C, I, R> Freeze for AssociativeCache<K, V, C, I, R>
where R: Freeze,

§

impl<K, V, C, I, R> RefUnwindSafe for AssociativeCache<K, V, C, I, R>

§

impl<K, V, C, I, R> Send for AssociativeCache<K, V, C, I, R>
where R: Send, C: Send, I: Send, K: Send, V: Send,

§

impl<K, V, C, I, R> Sync for AssociativeCache<K, V, C, I, R>
where R: Sync, C: Sync, I: Sync, K: Sync, V: Sync,

§

impl<K, V, C, I, R> Unpin for AssociativeCache<K, V, C, I, R>
where R: Unpin, C: Unpin, I: Unpin, K: Unpin, V: Unpin,

§

impl<K, V, C, I, R> UnwindSafe for AssociativeCache<K, V, C, I, R>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V