use std::fs::File;
use std::io::prelude::*;
+use std::collections::HashMap;
pub fn read_file(path: &str) -> Result<String, std::io::Error> {
let mut s = String::new();
y
}
}
+
+/// Wrap and cache an expensive calculation
+///
+/// This calls a closure just once for every distinct argument. Any subsequent
+/// call to `.value()` with the same argument uses the cached value.
+pub struct Cacher<T, A, V>
+where
+ T: Fn(A) -> V,
+ A: Eq + Copy + std::hash::Hash,
+ V: Copy,
+{
+ calc: T,
+ values: HashMap<A, V>,
+}
+
+impl<T, A, V> Cacher<T, A, V>
+where
+ T: Fn(A) -> V,
+ A: Eq + Copy + std::hash::Hash,
+ V: Copy,
+{
+ pub fn new(calc: T) -> Cacher<T, A, V> {
+ Cacher { calc, values: HashMap::new() }
+ }
+
+ pub fn value(&mut self, arg: A) -> V {
+ match self.values.get(&arg) {
+ Some(v) => *v,
+ None => {
+ let v = (self.calc)(arg);
+ self.values.insert(arg, v);
+ v
+ }
+ }
+ }
+}
println!("longest string: {}", l);
}
+fn test_closures() {
+ let mut expensive_int_result = Cacher::new(|x| {
+ println!("calculating expensive int result for {}", x);
+ 2 * x
+ });
+
+ println!("1st int call for value 1: {}", expensive_int_result.value(1));
+ println!("2nd int call for value 1: {}", expensive_int_result.value(1));
+ println!("1st int call for value 2: {}", expensive_int_result.value(2));
+
+ let mut expensive_str_result = Cacher::new(|x: &str| {
+ println!("calculating expensive str result for {}", x);
+ x.len()
+ });
+
+ println!("1st int call for value abc: {}", expensive_str_result.value("abc"));
+ println!("2nd int call for value abc: {}", expensive_str_result.value("abc"));
+ println!("1st int call for value defg: {}", expensive_str_result.value("defg"));
+}
+
fn main() {
test_strings();
test_vectors();
test_hashmaps();
test_files();
test_generics();
+ test_closures();
}
assert_eq!(longest("abc", "def"), "def");
assert_eq!(longest("abc", "defg"), "defg");
}
+
+// FIXME: How to make this not unsafe?
+static mut CALLED: u32 = 0;
+
+#[test]
+fn test_cacher_int_int() {
+ unsafe { CALLED = 0; }
+ let mut cacher = Cacher::new(|x| {
+ unsafe { CALLED += 1; }
+ 2 * x
+ });
+ assert_eq!(cacher.value(1), 2);
+ unsafe { assert_eq!(CALLED, 1); }
+ // second time cached
+ assert_eq!(cacher.value(1), 2);
+ unsafe { assert_eq!(CALLED, 1); }
+ // re-evaluated for new value
+ assert_eq!(cacher.value(-2), -4);
+ unsafe { assert_eq!(CALLED, 2); }
+ // old arg still cached
+ assert_eq!(cacher.value(1), 2);
+ unsafe { assert_eq!(CALLED, 2); }
+}
+
+#[test]
+fn test_cacher_str_usize() {
+ unsafe { CALLED = 0; }
+ let mut cacher = Cacher::new(|x: &str| {
+ unsafe { CALLED += 1; }
+ x.len()
+ });
+ assert_eq!(cacher.value("abc"), 3);
+ unsafe { assert_eq!(CALLED, 1); }
+ // second time cached
+ assert_eq!(cacher.value("abc"), 3);
+ unsafe { assert_eq!(CALLED, 1); }
+ // re-evaluated for new value
+ assert_eq!(cacher.value("defg"), 4);
+ unsafe { assert_eq!(CALLED, 2); }
+ // old arg still cached
+ assert_eq!(cacher.value("abc"), 3);
+ unsafe { assert_eq!(CALLED, 2); }
+}