use std::hash::Hash;
use crate::CachePolicy;
pub mod lru;
pub mod mru;
pub mod fifo;
pub mod lfu;
pub mod random;
pub use lru::LruCache;
pub use mru::MruCache;
pub use fifo::FifoCache;
pub use lfu::LfuCache;
pub use random::RandomCache;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PolicyType {
Lru,
Mru,
Fifo,
Lfu,
Random,
}
impl PolicyType {
pub fn name(&self) -> &'static str {
match self {
PolicyType::Lru => "LRU",
PolicyType::Mru => "MRU",
PolicyType::Fifo => "FIFO",
PolicyType::Lfu => "LFU",
PolicyType::Random => "Random",
}
}
pub fn description(&self) -> &'static str {
match self {
PolicyType::Lru => "Evicts the least recently used item",
PolicyType::Mru => "Evicts the most recently used item",
PolicyType::Fifo => "Evicts items in first-in-first-out order",
PolicyType::Lfu => "Evicts the least frequently used item",
PolicyType::Random => "Evicts a random item",
}
}
pub fn all() -> &'static [PolicyType] {
&[
PolicyType::Lru,
PolicyType::Mru,
PolicyType::Fifo,
PolicyType::Lfu,
PolicyType::Random,
]
}
}
pub fn create_cache_policy<K, V>(
policy_type: PolicyType,
capacity: usize,
) -> Box<dyn CachePolicy<K, V>>
where
K: Hash + Eq + Clone + Send + Sync + 'static,
V: Clone + Send + Sync + 'static,
{
match policy_type {
PolicyType::Lru => Box::new(LruCache::new(capacity)),
PolicyType::Mru => Box::new(MruCache::new(capacity)),
PolicyType::Fifo => Box::new(FifoCache::new(capacity)),
PolicyType::Lfu => Box::new(LfuCache::new(capacity)),
PolicyType::Random => Box::new(RandomCache::new(capacity)), }
}
pub trait BenchmarkablePolicy<K, V>: CachePolicy<K, V>
where
K: Hash + Eq + Clone,
V: Clone,
{
fn policy_type(&self) -> PolicyType;
fn benchmark_name(&self) -> String {
format!("{}_cap_{}", self.policy_type().name(), self.capacity())
}
fn reset_for_benchmark(&mut self) {
self.clear();
}
fn benchmark_operations(&mut self, operations: &[(K, Option<V>)]) {
for (key, maybe_value) in operations {
if let Some(value) = maybe_value {
self.insert(key.clone(), value.clone());
} else {
self.get(key);
}
}
}
fn characteristics(&self) -> PolicyCharacteristics {
match self.policy_type() {
PolicyType::Lru => PolicyCharacteristics {
avg_get_complexity: "O(1)",
avg_insert_complexity: "O(1)",
memory_overhead: "High",
cache_friendly: true,
temporal_locality: true,
spatial_locality: false,
},
PolicyType::Mru => PolicyCharacteristics {
avg_get_complexity: "O(1)",
avg_insert_complexity: "O(1)",
memory_overhead: "High",
cache_friendly: false,
temporal_locality: false,
spatial_locality: false,
},
_ => PolicyCharacteristics::default(),
}
}
}
#[derive(Debug, Clone)]
pub struct PolicyCharacteristics {
pub avg_get_complexity: &'static str,
pub avg_insert_complexity: &'static str,
pub memory_overhead: &'static str,
pub cache_friendly: bool,
pub temporal_locality: bool,
pub spatial_locality: bool,
}
impl Default for PolicyCharacteristics {
fn default() -> Self {
Self {
avg_get_complexity: "Unknown",
avg_insert_complexity: "Unknown",
memory_overhead: "Unknown",
cache_friendly: false,
temporal_locality: false,
spatial_locality: false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_policy_type_enum() {
assert_eq!(PolicyType::Lru.name(), "LRU");
assert_eq!(PolicyType::Mru.name(), "MRU");
assert!(PolicyType::Lru.description().contains("least recently"));
assert!(PolicyType::Mru.description().contains("most recently"));
let all_policies = PolicyType::all();
assert!(all_policies.contains(&PolicyType::Lru));
assert!(all_policies.contains(&PolicyType::Mru));
}
#[test]
fn test_factory_pattern() {
let lru_cache = create_cache_policy::<i32, String>(PolicyType::Lru, 100);
let mru_cache = create_cache_policy::<i32, String>(PolicyType::Mru, 50);
let fifo_cache = create_cache_policy::<i32, String>(PolicyType::Fifo, 30);
let lfu_cache = create_cache_policy::<i32, String>(PolicyType::Lfu, 20);
let random_cache = create_cache_policy::<i32, String>(PolicyType::Random, 10);
assert_eq!(lru_cache.capacity(), 100);
assert_eq!(mru_cache.capacity(), 50);
assert_eq!(fifo_cache.capacity(), 30);
assert_eq!(lfu_cache.capacity(), 20);
assert_eq!(random_cache.capacity(), 10);
}
}