use memo_cache::MemoCache;
use rand_distr::{Distribution, Normal};
use std::{collections::HashMap, thread, time};
fn some_expensive_calculation(_: i32) -> f32 {
thread::sleep(time::Duration::from_millis(20)); std::f32::consts::PI
}
fn calculation_wrapper(input: &i32) -> f32 {
some_expensive_calculation(*input)
}
fn calculation_wrapper_result(input: &i32) -> Result<f32, ()> {
Ok(some_expensive_calculation(*input))
}
struct Process {
pub cache1: HashMap<i32, f32>,
pub cache2: MemoCache<i32, f32, 32>,
}
impl Process {
fn new() -> Self {
Self {
cache1: HashMap::new(),
cache2: MemoCache::new(),
}
}
fn regular(&self, input: i32) -> f32 {
some_expensive_calculation(input)
}
fn memoized1(&mut self, input: i32) -> f32 {
if let Some(value) = self.cache1.get(&input) {
*value
} else {
let result = some_expensive_calculation(input);
self.cache1.insert(input, result);
result
}
}
fn memoized2a(&mut self, input: i32) -> f32 {
if let Some(value) = self.cache2.get(&input) {
*value
} else {
let result = some_expensive_calculation(input);
self.cache2.insert(input, result);
result
}
}
fn memoized2b(&mut self, input: i32) -> f32 {
*self.cache2.get_or_insert_with(&input, calculation_wrapper)
}
fn memoized2c(&mut self, input: i32) -> f32 {
*self
.cache2
.get_or_try_insert_with(&input, calculation_wrapper_result)
.unwrap()
}
}
fn main() {
let mut rng = rand::rng();
let normal = Normal::new(0.0, 30.0).unwrap();
let inputs = (0..100)
.map(|_| normal.sample(&mut rng) as i32)
.collect::<Vec<_>>();
let mut p = Process::new();
println!("Running tests..");
let now = time::Instant::now();
inputs.iter().fold(0.0, |sum, &i| sum + p.regular(i));
let d_regular = now.elapsed();
let now = time::Instant::now();
inputs.iter().fold(0.0, |sum, &i| sum + p.memoized1(i));
let d_memoized1 = now.elapsed();
let now = time::Instant::now();
inputs.iter().fold(0.0, |sum, &i| sum + p.memoized2a(i));
let d_memoized2a = now.elapsed();
p.cache2.clear();
let now = time::Instant::now();
inputs.iter().fold(0.0, |sum, &i| sum + p.memoized2b(i));
let d_memoized2b = now.elapsed();
p.cache2.clear();
let now = time::Instant::now();
inputs.iter().fold(0.0, |sum, &i| sum + p.memoized2c(i));
let d_memoized2c = now.elapsed();
println!("Done. Timing results:");
println!("Regular: {} ms", d_regular.as_millis());
println!("Memoized (hash): {} ms", d_memoized1.as_millis());
println!("Memoized (MemoCache A): {} ms", d_memoized2a.as_millis());
println!("Memoized (MemoCache B): {} ms", d_memoized2b.as_millis());
println!("Memoized (MemoCache C): {} ms", d_memoized2c.as_millis());
println!("Post-test occupied cache sizes:");
println!(" Hash: {} elements", p.cache1.capacity());
println!(" MemoCache: {} elements", p.cache2.capacity());
}