use std::fmt;
use std::fmt::Debug;
use std::hash::Hash;
use std::sync::Arc;
#[cfg(feature = "policy-lfu")]
use crate::ds::frequency_buckets::DEFAULT_BUCKET_PREALLOC;
#[cfg(feature = "policy-arc")]
use crate::policy::arc::ArcCore;
#[cfg(feature = "policy-clock")]
use crate::policy::clock::ClockCache;
#[cfg(feature = "policy-clock-pro")]
use crate::policy::clock_pro::ClockProCache;
#[cfg(feature = "policy-fast-lru")]
use crate::policy::fast_lru::FastLru;
#[cfg(feature = "policy-fifo")]
use crate::policy::fifo::FifoCache;
#[cfg(feature = "policy-heap-lfu")]
use crate::policy::heap_lfu::HeapLfuCache;
#[cfg(feature = "policy-lfu")]
use crate::policy::lfu::LfuCache;
#[cfg(feature = "policy-lifo")]
use crate::policy::lifo::LifoCore;
#[cfg(feature = "policy-lru")]
use crate::policy::lru::LruCore;
#[cfg(feature = "policy-lru-k")]
use crate::policy::lru_k::LrukCache;
#[cfg(feature = "policy-mfu")]
use crate::policy::mfu::MfuCore;
#[cfg(feature = "policy-mru")]
use crate::policy::mru::MruCore;
#[cfg(feature = "policy-nru")]
use crate::policy::nru::NruCache;
#[cfg(feature = "policy-random")]
use crate::policy::random::RandomCore;
#[cfg(feature = "policy-s3-fifo")]
use crate::policy::s3_fifo::S3FifoCache;
#[cfg(feature = "policy-slru")]
use crate::policy::slru::SlruCore;
#[cfg(feature = "policy-two-q")]
use crate::policy::two_q::TwoQCore;
use crate::traits::Cache as CacheTrait;
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CachePolicy {
#[cfg(feature = "policy-fifo")]
Fifo,
#[cfg(feature = "policy-lru")]
Lru,
#[cfg(feature = "policy-fast-lru")]
FastLru,
#[cfg(feature = "policy-lru-k")]
LruK { k: usize },
#[cfg(feature = "policy-lfu")]
Lfu {
bucket_hint: Option<usize>,
},
#[cfg(feature = "policy-heap-lfu")]
HeapLfu,
#[cfg(feature = "policy-two-q")]
TwoQ { probation_frac: f64 },
#[cfg(feature = "policy-s3-fifo")]
S3Fifo {
small_ratio: f64,
ghost_ratio: f64,
},
#[cfg(feature = "policy-arc")]
Arc,
#[cfg(feature = "policy-lifo")]
Lifo,
#[cfg(feature = "policy-mfu")]
Mfu,
#[cfg(feature = "policy-mru")]
Mru,
#[cfg(feature = "policy-random")]
Random,
#[cfg(feature = "policy-slru")]
Slru {
probationary_frac: f64,
},
#[cfg(feature = "policy-clock")]
Clock,
#[cfg(feature = "policy-clock-pro")]
ClockPro,
#[cfg(feature = "policy-nru")]
Nru,
}
pub struct DynCache<K, V>
where
K: Copy + Eq + Hash + Ord,
V: Clone + Debug,
{
inner: CacheInner<K, V>,
}
enum CacheInner<K, V>
where
K: Copy + Eq + Hash + Ord,
V: Clone + Debug,
{
#[cfg(feature = "policy-fifo")]
Fifo(FifoCache<K, V>),
#[cfg(feature = "policy-lru")]
Lru(LruCore<K, V>),
#[cfg(feature = "policy-fast-lru")]
FastLru(FastLru<K, V>),
#[cfg(feature = "policy-lru-k")]
LruK(LrukCache<K, V>),
#[cfg(feature = "policy-lfu")]
Lfu(LfuCache<K, V>),
#[cfg(feature = "policy-heap-lfu")]
HeapLfu(HeapLfuCache<K, V>),
#[cfg(feature = "policy-two-q")]
TwoQ(TwoQCore<K, V>),
#[cfg(feature = "policy-s3-fifo")]
S3Fifo(S3FifoCache<K, V>),
#[cfg(feature = "policy-arc")]
Arc(ArcCore<K, V>),
#[cfg(feature = "policy-lifo")]
Lifo(LifoCore<K, V>),
#[cfg(feature = "policy-mfu")]
Mfu(MfuCore<K, V>),
#[cfg(feature = "policy-mru")]
Mru(MruCore<K, V>),
#[cfg(feature = "policy-random")]
Random(RandomCore<K, V>),
#[cfg(feature = "policy-slru")]
Slru(SlruCore<K, V>),
#[cfg(feature = "policy-clock")]
Clock(ClockCache<K, V>),
#[cfg(feature = "policy-clock-pro")]
ClockPro(ClockProCache<K, V>),
#[cfg(feature = "policy-nru")]
Nru(NruCache<K, V>),
}
impl<K, V> DynCache<K, V>
where
K: Copy + Eq + Hash + Ord,
V: Clone + Debug,
{
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
match &mut self.inner {
#[cfg(feature = "policy-fifo")]
CacheInner::Fifo(fifo) => fifo.insert(key, value),
#[cfg(feature = "policy-lru")]
CacheInner::Lru(lru) => {
let arc_value = Arc::new(value);
lru.insert(key, arc_value)
.map(|arc| Arc::try_unwrap(arc).unwrap_or_else(|arc| (*arc).clone()))
},
#[cfg(feature = "policy-fast-lru")]
CacheInner::FastLru(fast_lru) => fast_lru.insert(key, value),
#[cfg(feature = "policy-lru-k")]
CacheInner::LruK(lruk) => lruk.insert(key, value),
#[cfg(feature = "policy-lfu")]
CacheInner::Lfu(lfu) => {
let arc_value = Arc::new(value);
lfu.insert(key, arc_value)
.map(|arc| Arc::try_unwrap(arc).unwrap_or_else(|arc| (*arc).clone()))
},
#[cfg(feature = "policy-heap-lfu")]
CacheInner::HeapLfu(heap_lfu) => {
let arc_value = Arc::new(value);
heap_lfu
.insert(key, arc_value)
.map(|arc| Arc::try_unwrap(arc).unwrap_or_else(|arc| (*arc).clone()))
},
#[cfg(feature = "policy-two-q")]
CacheInner::TwoQ(twoq) => twoq.insert(key, value),
#[cfg(feature = "policy-s3-fifo")]
CacheInner::S3Fifo(s3fifo) => s3fifo.insert(key, value),
#[cfg(feature = "policy-arc")]
CacheInner::Arc(arc) => arc.insert(key, value),
#[cfg(feature = "policy-lifo")]
CacheInner::Lifo(lifo) => lifo.insert(key, value),
#[cfg(feature = "policy-mfu")]
CacheInner::Mfu(mfu) => mfu.insert(key, value),
#[cfg(feature = "policy-mru")]
CacheInner::Mru(mru) => mru.insert(key, value),
#[cfg(feature = "policy-random")]
CacheInner::Random(random) => random.insert(key, value),
#[cfg(feature = "policy-slru")]
CacheInner::Slru(slru) => slru.insert(key, value),
#[cfg(feature = "policy-clock")]
CacheInner::Clock(clock) => clock.insert(key, value),
#[cfg(feature = "policy-clock-pro")]
CacheInner::ClockPro(clock_pro) => clock_pro.insert(key, value),
#[cfg(feature = "policy-nru")]
CacheInner::Nru(nru) => nru.insert(key, value),
}
}
pub fn get(&mut self, key: &K) -> Option<&V> {
match &mut self.inner {
#[cfg(feature = "policy-fifo")]
CacheInner::Fifo(fifo) => fifo.get(key),
#[cfg(feature = "policy-lru")]
CacheInner::Lru(lru) => lru.get(key).map(|arc| arc.as_ref()),
#[cfg(feature = "policy-fast-lru")]
CacheInner::FastLru(fast_lru) => fast_lru.get(key),
#[cfg(feature = "policy-lru-k")]
CacheInner::LruK(lruk) => lruk.get(key),
#[cfg(feature = "policy-lfu")]
CacheInner::Lfu(lfu) => lfu.get(key).map(|arc| arc.as_ref()),
#[cfg(feature = "policy-heap-lfu")]
CacheInner::HeapLfu(heap_lfu) => heap_lfu.get(key).map(|arc| arc.as_ref()),
#[cfg(feature = "policy-two-q")]
CacheInner::TwoQ(twoq) => twoq.get(key),
#[cfg(feature = "policy-s3-fifo")]
CacheInner::S3Fifo(s3fifo) => s3fifo.get(key),
#[cfg(feature = "policy-arc")]
CacheInner::Arc(arc) => arc.get(key),
#[cfg(feature = "policy-lifo")]
CacheInner::Lifo(lifo) => lifo.get(key),
#[cfg(feature = "policy-mfu")]
CacheInner::Mfu(mfu) => mfu.get(key),
#[cfg(feature = "policy-mru")]
CacheInner::Mru(mru) => mru.get(key),
#[cfg(feature = "policy-random")]
CacheInner::Random(random) => random.get(key),
#[cfg(feature = "policy-slru")]
CacheInner::Slru(slru) => slru.get(key),
#[cfg(feature = "policy-clock")]
CacheInner::Clock(clock) => clock.get(key),
#[cfg(feature = "policy-clock-pro")]
CacheInner::ClockPro(clock_pro) => clock_pro.get(key),
#[cfg(feature = "policy-nru")]
CacheInner::Nru(nru) => nru.get(key),
}
}
pub fn contains(&self, key: &K) -> bool {
match &self.inner {
#[cfg(feature = "policy-fifo")]
CacheInner::Fifo(fifo) => fifo.contains(key),
#[cfg(feature = "policy-lru")]
CacheInner::Lru(lru) => lru.contains(key),
#[cfg(feature = "policy-fast-lru")]
CacheInner::FastLru(fast_lru) => fast_lru.contains(key),
#[cfg(feature = "policy-lru-k")]
CacheInner::LruK(lruk) => lruk.contains(key),
#[cfg(feature = "policy-lfu")]
CacheInner::Lfu(lfu) => lfu.contains(key),
#[cfg(feature = "policy-heap-lfu")]
CacheInner::HeapLfu(heap_lfu) => heap_lfu.contains(key),
#[cfg(feature = "policy-two-q")]
CacheInner::TwoQ(twoq) => twoq.contains(key),
#[cfg(feature = "policy-s3-fifo")]
CacheInner::S3Fifo(s3fifo) => s3fifo.contains(key),
#[cfg(feature = "policy-arc")]
CacheInner::Arc(arc) => arc.contains(key),
#[cfg(feature = "policy-lifo")]
CacheInner::Lifo(lifo) => lifo.contains(key),
#[cfg(feature = "policy-mfu")]
CacheInner::Mfu(mfu) => mfu.contains(key),
#[cfg(feature = "policy-mru")]
CacheInner::Mru(mru) => mru.contains(key),
#[cfg(feature = "policy-random")]
CacheInner::Random(random) => random.contains(key),
#[cfg(feature = "policy-slru")]
CacheInner::Slru(slru) => slru.contains(key),
#[cfg(feature = "policy-clock")]
CacheInner::Clock(clock) => clock.contains(key),
#[cfg(feature = "policy-clock-pro")]
CacheInner::ClockPro(clock_pro) => clock_pro.contains(key),
#[cfg(feature = "policy-nru")]
CacheInner::Nru(nru) => nru.contains(key),
}
}
pub fn len(&self) -> usize {
match &self.inner {
#[cfg(feature = "policy-fifo")]
CacheInner::Fifo(fifo) => fifo.len(),
#[cfg(feature = "policy-lru")]
CacheInner::Lru(lru) => lru.len(),
#[cfg(feature = "policy-fast-lru")]
CacheInner::FastLru(fast_lru) => fast_lru.len(),
#[cfg(feature = "policy-lru-k")]
CacheInner::LruK(lruk) => lruk.len(),
#[cfg(feature = "policy-lfu")]
CacheInner::Lfu(lfu) => lfu.len(),
#[cfg(feature = "policy-heap-lfu")]
CacheInner::HeapLfu(heap_lfu) => heap_lfu.len(),
#[cfg(feature = "policy-two-q")]
CacheInner::TwoQ(twoq) => twoq.len(),
#[cfg(feature = "policy-s3-fifo")]
CacheInner::S3Fifo(s3fifo) => s3fifo.len(),
#[cfg(feature = "policy-arc")]
CacheInner::Arc(arc) => arc.len(),
#[cfg(feature = "policy-lifo")]
CacheInner::Lifo(lifo) => lifo.len(),
#[cfg(feature = "policy-mfu")]
CacheInner::Mfu(mfu) => mfu.len(),
#[cfg(feature = "policy-mru")]
CacheInner::Mru(mru) => mru.len(),
#[cfg(feature = "policy-random")]
CacheInner::Random(random) => random.len(),
#[cfg(feature = "policy-slru")]
CacheInner::Slru(slru) => slru.len(),
#[cfg(feature = "policy-clock")]
CacheInner::Clock(clock) => clock.len(),
#[cfg(feature = "policy-clock-pro")]
CacheInner::ClockPro(clock_pro) => clock_pro.len(),
#[cfg(feature = "policy-nru")]
CacheInner::Nru(nru) => nru.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn capacity(&self) -> usize {
match &self.inner {
#[cfg(feature = "policy-fifo")]
CacheInner::Fifo(fifo) => fifo.capacity(),
#[cfg(feature = "policy-lru")]
CacheInner::Lru(lru) => lru.capacity(),
#[cfg(feature = "policy-fast-lru")]
CacheInner::FastLru(fast_lru) => fast_lru.capacity(),
#[cfg(feature = "policy-lru-k")]
CacheInner::LruK(lruk) => lruk.capacity(),
#[cfg(feature = "policy-lfu")]
CacheInner::Lfu(lfu) => lfu.capacity(),
#[cfg(feature = "policy-heap-lfu")]
CacheInner::HeapLfu(heap_lfu) => heap_lfu.capacity(),
#[cfg(feature = "policy-two-q")]
CacheInner::TwoQ(twoq) => twoq.capacity(),
#[cfg(feature = "policy-s3-fifo")]
CacheInner::S3Fifo(s3fifo) => s3fifo.capacity(),
#[cfg(feature = "policy-arc")]
CacheInner::Arc(arc) => arc.capacity(),
#[cfg(feature = "policy-lifo")]
CacheInner::Lifo(lifo) => lifo.capacity(),
#[cfg(feature = "policy-mfu")]
CacheInner::Mfu(mfu) => mfu.capacity(),
#[cfg(feature = "policy-mru")]
CacheInner::Mru(mru) => mru.capacity(),
#[cfg(feature = "policy-random")]
CacheInner::Random(random) => random.capacity(),
#[cfg(feature = "policy-slru")]
CacheInner::Slru(slru) => slru.capacity(),
#[cfg(feature = "policy-clock")]
CacheInner::Clock(clock) => clock.capacity(),
#[cfg(feature = "policy-clock-pro")]
CacheInner::ClockPro(clock_pro) => clock_pro.capacity(),
#[cfg(feature = "policy-nru")]
CacheInner::Nru(nru) => nru.capacity(),
}
}
pub fn clear(&mut self) {
match &mut self.inner {
#[cfg(feature = "policy-fifo")]
CacheInner::Fifo(fifo) => fifo.clear(),
#[cfg(feature = "policy-lru")]
CacheInner::Lru(lru) => lru.clear(),
#[cfg(feature = "policy-fast-lru")]
CacheInner::FastLru(fast_lru) => fast_lru.clear(),
#[cfg(feature = "policy-lru-k")]
CacheInner::LruK(lruk) => lruk.clear(),
#[cfg(feature = "policy-lfu")]
CacheInner::Lfu(lfu) => lfu.clear(),
#[cfg(feature = "policy-heap-lfu")]
CacheInner::HeapLfu(heap_lfu) => heap_lfu.clear(),
#[cfg(feature = "policy-two-q")]
CacheInner::TwoQ(twoq) => twoq.clear(),
#[cfg(feature = "policy-s3-fifo")]
CacheInner::S3Fifo(s3fifo) => s3fifo.clear(),
#[cfg(feature = "policy-arc")]
CacheInner::Arc(arc) => arc.clear(),
#[cfg(feature = "policy-lifo")]
CacheInner::Lifo(lifo) => lifo.clear(),
#[cfg(feature = "policy-mfu")]
CacheInner::Mfu(mfu) => mfu.clear(),
#[cfg(feature = "policy-mru")]
CacheInner::Mru(mru) => mru.clear(),
#[cfg(feature = "policy-random")]
CacheInner::Random(random) => random.clear(),
#[cfg(feature = "policy-slru")]
CacheInner::Slru(slru) => slru.clear(),
#[cfg(feature = "policy-clock")]
CacheInner::Clock(clock) => clock.clear(),
#[cfg(feature = "policy-clock-pro")]
CacheInner::ClockPro(clock_pro) => clock_pro.clear(),
#[cfg(feature = "policy-nru")]
CacheInner::Nru(nru) => nru.clear(),
}
}
pub fn peek(&self, key: &K) -> Option<&V> {
match &self.inner {
#[cfg(feature = "policy-fifo")]
CacheInner::Fifo(fifo) => CacheTrait::peek(fifo, key),
#[cfg(feature = "policy-lru")]
CacheInner::Lru(lru) => CacheTrait::peek(lru, key).map(|arc| arc.as_ref()),
#[cfg(feature = "policy-fast-lru")]
CacheInner::FastLru(fast_lru) => fast_lru.peek(key),
#[cfg(feature = "policy-lru-k")]
CacheInner::LruK(lruk) => CacheTrait::peek(lruk, key),
#[cfg(feature = "policy-lfu")]
CacheInner::Lfu(lfu) => CacheTrait::peek(lfu, key).map(|arc| arc.as_ref()),
#[cfg(feature = "policy-heap-lfu")]
CacheInner::HeapLfu(heap_lfu) => {
CacheTrait::peek(heap_lfu, key).map(|arc| arc.as_ref())
},
#[cfg(feature = "policy-two-q")]
CacheInner::TwoQ(twoq) => CacheTrait::peek(twoq, key),
#[cfg(feature = "policy-s3-fifo")]
CacheInner::S3Fifo(s3fifo) => s3fifo.peek(key),
#[cfg(feature = "policy-arc")]
CacheInner::Arc(arc) => CacheTrait::peek(arc, key),
#[cfg(feature = "policy-lifo")]
CacheInner::Lifo(lifo) => lifo.peek(key),
#[cfg(feature = "policy-mfu")]
CacheInner::Mfu(mfu) => CacheTrait::peek(mfu, key),
#[cfg(feature = "policy-mru")]
CacheInner::Mru(mru) => CacheTrait::peek(mru, key),
#[cfg(feature = "policy-random")]
CacheInner::Random(random) => random.peek(key),
#[cfg(feature = "policy-slru")]
CacheInner::Slru(slru) => slru.peek(key),
#[cfg(feature = "policy-clock")]
CacheInner::Clock(clock) => CacheTrait::peek(clock, key),
#[cfg(feature = "policy-clock-pro")]
CacheInner::ClockPro(clock_pro) => CacheTrait::peek(clock_pro, key),
#[cfg(feature = "policy-nru")]
CacheInner::Nru(nru) => CacheTrait::peek(nru, key),
}
}
pub fn remove(&mut self, key: &K) -> Option<V> {
match &mut self.inner {
#[cfg(feature = "policy-fifo")]
CacheInner::Fifo(fifo) => CacheTrait::remove(fifo, key),
#[cfg(feature = "policy-lru")]
CacheInner::Lru(lru) => CacheTrait::remove(lru, key)
.map(|arc| Arc::try_unwrap(arc).unwrap_or_else(|arc| (*arc).clone())),
#[cfg(feature = "policy-fast-lru")]
CacheInner::FastLru(fast_lru) => fast_lru.remove(key),
#[cfg(feature = "policy-lru-k")]
CacheInner::LruK(lruk) => CacheTrait::remove(lruk, key),
#[cfg(feature = "policy-lfu")]
CacheInner::Lfu(lfu) => CacheTrait::remove(lfu, key)
.map(|arc| Arc::try_unwrap(arc).unwrap_or_else(|arc| (*arc).clone())),
#[cfg(feature = "policy-heap-lfu")]
CacheInner::HeapLfu(heap_lfu) => CacheTrait::remove(heap_lfu, key)
.map(|arc| Arc::try_unwrap(arc).unwrap_or_else(|arc| (*arc).clone())),
#[cfg(feature = "policy-two-q")]
CacheInner::TwoQ(twoq) => CacheTrait::remove(twoq, key),
#[cfg(feature = "policy-s3-fifo")]
CacheInner::S3Fifo(s3fifo) => s3fifo.remove(key),
#[cfg(feature = "policy-arc")]
CacheInner::Arc(arc) => CacheTrait::remove(arc, key),
#[cfg(feature = "policy-lifo")]
CacheInner::Lifo(lifo) => CacheTrait::remove(lifo, key),
#[cfg(feature = "policy-mfu")]
CacheInner::Mfu(mfu) => mfu.remove(key),
#[cfg(feature = "policy-mru")]
CacheInner::Mru(mru) => CacheTrait::remove(mru, key),
#[cfg(feature = "policy-random")]
CacheInner::Random(random) => random.remove(key),
#[cfg(feature = "policy-slru")]
CacheInner::Slru(slru) => CacheTrait::remove(slru, key),
#[cfg(feature = "policy-clock")]
CacheInner::Clock(clock) => CacheTrait::remove(clock, key),
#[cfg(feature = "policy-clock-pro")]
CacheInner::ClockPro(clock_pro) => CacheTrait::remove(clock_pro, key),
#[cfg(feature = "policy-nru")]
CacheInner::Nru(nru) => CacheTrait::remove(nru, key),
}
}
}
impl<K, V> fmt::Debug for DynCache<K, V>
where
K: Copy + Eq + Hash + Ord,
V: Clone + Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let policy = match &self.inner {
#[cfg(feature = "policy-fifo")]
CacheInner::Fifo(_) => "Fifo",
#[cfg(feature = "policy-lru")]
CacheInner::Lru(_) => "Lru",
#[cfg(feature = "policy-fast-lru")]
CacheInner::FastLru(_) => "FastLru",
#[cfg(feature = "policy-lru-k")]
CacheInner::LruK(_) => "LruK",
#[cfg(feature = "policy-lfu")]
CacheInner::Lfu(_) => "Lfu",
#[cfg(feature = "policy-heap-lfu")]
CacheInner::HeapLfu(_) => "HeapLfu",
#[cfg(feature = "policy-two-q")]
CacheInner::TwoQ(_) => "TwoQ",
#[cfg(feature = "policy-s3-fifo")]
CacheInner::S3Fifo(_) => "S3Fifo",
#[cfg(feature = "policy-arc")]
CacheInner::Arc(_) => "Arc",
#[cfg(feature = "policy-lifo")]
CacheInner::Lifo(_) => "Lifo",
#[cfg(feature = "policy-mfu")]
CacheInner::Mfu(_) => "Mfu",
#[cfg(feature = "policy-mru")]
CacheInner::Mru(_) => "Mru",
#[cfg(feature = "policy-random")]
CacheInner::Random(_) => "Random",
#[cfg(feature = "policy-slru")]
CacheInner::Slru(_) => "Slru",
#[cfg(feature = "policy-clock")]
CacheInner::Clock(_) => "Clock",
#[cfg(feature = "policy-clock-pro")]
CacheInner::ClockPro(_) => "ClockPro",
#[cfg(feature = "policy-nru")]
CacheInner::Nru(_) => "Nru",
};
f.debug_struct("DynCache")
.field("policy", &policy)
.field("len", &self.len())
.field("capacity", &self.capacity())
.finish()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CacheBuilder {
capacity: usize,
}
impl CacheBuilder {
pub fn new(capacity: usize) -> Self {
Self { capacity }
}
pub fn build<K, V>(self, policy: CachePolicy) -> DynCache<K, V>
where
K: Copy + Eq + Hash + Ord,
V: Clone + Debug,
{
assert!(self.capacity > 0, "cache capacity must be greater than 0");
self.validate_policy(&policy);
let inner = match policy {
#[cfg(feature = "policy-fifo")]
CachePolicy::Fifo => CacheInner::Fifo(FifoCache::new(self.capacity)),
#[cfg(feature = "policy-lru")]
CachePolicy::Lru => CacheInner::Lru(LruCore::new(self.capacity)),
#[cfg(feature = "policy-fast-lru")]
CachePolicy::FastLru => CacheInner::FastLru(FastLru::new(self.capacity)),
#[cfg(feature = "policy-lru-k")]
CachePolicy::LruK { k } => CacheInner::LruK(LrukCache::with_k(self.capacity, k)),
#[cfg(feature = "policy-lfu")]
CachePolicy::Lfu { bucket_hint } => {
let hint = bucket_hint.unwrap_or(DEFAULT_BUCKET_PREALLOC);
CacheInner::Lfu(LfuCache::with_bucket_hint(self.capacity, hint))
},
#[cfg(feature = "policy-heap-lfu")]
CachePolicy::HeapLfu => CacheInner::HeapLfu(HeapLfuCache::new(self.capacity)),
#[cfg(feature = "policy-two-q")]
CachePolicy::TwoQ { probation_frac } => {
CacheInner::TwoQ(TwoQCore::new(self.capacity, probation_frac))
},
#[cfg(feature = "policy-s3-fifo")]
CachePolicy::S3Fifo {
small_ratio,
ghost_ratio,
} => CacheInner::S3Fifo(S3FifoCache::with_ratios(
self.capacity,
small_ratio,
ghost_ratio,
)),
#[cfg(feature = "policy-arc")]
CachePolicy::Arc => CacheInner::Arc(ArcCore::new(self.capacity)),
#[cfg(feature = "policy-lifo")]
CachePolicy::Lifo => CacheInner::Lifo(LifoCore::new(self.capacity)),
#[cfg(feature = "policy-mfu")]
CachePolicy::Mfu => CacheInner::Mfu(MfuCore::new(self.capacity)),
#[cfg(feature = "policy-mru")]
CachePolicy::Mru => CacheInner::Mru(MruCore::new(self.capacity)),
#[cfg(feature = "policy-random")]
CachePolicy::Random => CacheInner::Random(RandomCore::new(self.capacity)),
#[cfg(feature = "policy-slru")]
CachePolicy::Slru { probationary_frac } => {
CacheInner::Slru(SlruCore::new(self.capacity, probationary_frac))
},
#[cfg(feature = "policy-clock")]
CachePolicy::Clock => CacheInner::Clock(ClockCache::new(self.capacity)),
#[cfg(feature = "policy-clock-pro")]
CachePolicy::ClockPro => CacheInner::ClockPro(ClockProCache::new(self.capacity)),
#[cfg(feature = "policy-nru")]
CachePolicy::Nru => CacheInner::Nru(NruCache::new(self.capacity)),
};
DynCache { inner }
}
fn validate_policy(&self, policy: &CachePolicy) {
fn check_frac(name: &str, value: f64) {
assert!(
value.is_finite() && (0.0..=1.0).contains(&value),
"{name} must be a finite value in 0.0..=1.0, got {value}"
);
}
match policy {
#[cfg(feature = "policy-lru-k")]
CachePolicy::LruK { k } => {
assert!(*k > 0, "LruK: k must be greater than 0");
},
#[cfg(feature = "policy-two-q")]
CachePolicy::TwoQ { probation_frac } => {
check_frac("TwoQ: probation_frac", *probation_frac);
},
#[cfg(feature = "policy-s3-fifo")]
CachePolicy::S3Fifo {
small_ratio,
ghost_ratio,
} => {
check_frac("S3Fifo: small_ratio", *small_ratio);
check_frac("S3Fifo: ghost_ratio", *ghost_ratio);
},
#[cfg(feature = "policy-slru")]
CachePolicy::Slru { probationary_frac } => {
check_frac("Slru: probationary_frac", *probationary_frac);
},
_ => {},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn all_enabled_policies() -> Vec<CachePolicy> {
vec![
#[cfg(feature = "policy-fifo")]
CachePolicy::Fifo,
#[cfg(feature = "policy-lru")]
CachePolicy::Lru,
#[cfg(feature = "policy-fast-lru")]
CachePolicy::FastLru,
#[cfg(feature = "policy-lru-k")]
CachePolicy::LruK { k: 2 },
#[cfg(feature = "policy-lfu")]
CachePolicy::Lfu { bucket_hint: None },
#[cfg(feature = "policy-heap-lfu")]
CachePolicy::HeapLfu,
#[cfg(feature = "policy-two-q")]
CachePolicy::TwoQ {
probation_frac: 0.25,
},
#[cfg(feature = "policy-s3-fifo")]
CachePolicy::S3Fifo {
small_ratio: 0.1,
ghost_ratio: 0.9,
},
#[cfg(feature = "policy-arc")]
CachePolicy::Arc,
#[cfg(feature = "policy-lifo")]
CachePolicy::Lifo,
#[cfg(feature = "policy-mfu")]
CachePolicy::Mfu,
#[cfg(feature = "policy-mru")]
CachePolicy::Mru,
#[cfg(feature = "policy-random")]
CachePolicy::Random,
#[cfg(feature = "policy-slru")]
CachePolicy::Slru {
probationary_frac: 0.25,
},
#[cfg(feature = "policy-clock")]
CachePolicy::Clock,
#[cfg(feature = "policy-clock-pro")]
CachePolicy::ClockPro,
#[cfg(feature = "policy-nru")]
CachePolicy::Nru,
]
}
#[test]
fn test_all_policies_basic_ops() {
let policies = all_enabled_policies();
assert!(
!policies.is_empty(),
"At least one policy feature must be enabled"
);
for policy in policies {
let mut cache = CacheBuilder::new(10).build::<u64, String>(policy);
assert_eq!(cache.insert(1, "one".to_string()), None);
assert_eq!(cache.insert(2, "two".to_string()), None);
assert_eq!(cache.get(&1), Some(&"one".to_string()));
assert_eq!(cache.get(&2), Some(&"two".to_string()));
assert_eq!(cache.get(&3), None);
assert!(cache.contains(&1));
assert!(!cache.contains(&99));
assert_eq!(cache.len(), 2);
assert!(!cache.is_empty());
assert_eq!(cache.insert(1, "ONE".to_string()), Some("one".to_string()));
assert_eq!(cache.get(&1), Some(&"ONE".to_string()));
cache.clear();
assert!(cache.is_empty());
}
}
#[test]
#[cfg(feature = "policy-lru")]
fn test_capacity_enforcement() {
let mut cache = CacheBuilder::new(2).build::<u64, String>(CachePolicy::Lru);
cache.insert(1, "one".to_string());
cache.insert(2, "two".to_string());
cache.insert(3, "three".to_string());
assert_eq!(cache.len(), 2);
assert!(!cache.contains(&1)); assert!(cache.contains(&2));
assert!(cache.contains(&3));
}
#[test]
#[cfg(feature = "policy-lru")]
fn test_debug_output() {
let mut cache = CacheBuilder::new(10).build::<u64, String>(CachePolicy::Lru);
cache.insert(1, "one".to_string());
let debug = format!("{:?}", cache);
assert!(debug.contains("DynCache"));
assert!(debug.contains("Lru"));
assert!(debug.contains("len: 1"));
}
#[test]
#[cfg(feature = "policy-lru")]
#[should_panic(expected = "cache capacity must be greater than 0")]
fn test_zero_capacity_panics() {
let _ = CacheBuilder::new(0).build::<u64, String>(CachePolicy::Lru);
}
#[test]
#[cfg(feature = "policy-lru-k")]
#[should_panic(expected = "LruK: k must be greater than 0")]
fn test_lru_k_zero_panics() {
let _ = CacheBuilder::new(10).build::<u64, String>(CachePolicy::LruK { k: 0 });
}
#[test]
#[cfg(feature = "policy-two-q")]
#[should_panic(expected = "TwoQ: probation_frac must be a finite value in 0.0..=1.0")]
fn test_two_q_invalid_frac_panics() {
let _ = CacheBuilder::new(10).build::<u64, String>(CachePolicy::TwoQ {
probation_frac: 1.5,
});
}
#[cfg(all(feature = "policy-lru", not(feature = "policy-fast-lru")))]
#[allow(dead_code)]
const _: () = {
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
fn check() {
assert_send::<DynCache<u64, String>>();
assert_sync::<DynCache<u64, String>>();
}
};
#[allow(dead_code)]
const _: () = {
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
fn check() {
assert_send::<CacheBuilder>();
assert_sync::<CacheBuilder>();
}
};
}