4343
4444 /// Performs a lookup into the HashMap to see if the value has already
4545 /// been calculated. If it has, returns the value. If it has not,
46- /// calls the function, stores the value, then returns the value
46+ /// calls the function, stores the value, then returns the value.
4747 /// # Examples
4848 /// ```
4949 /// # use contest_algorithms::caching::Cacher;
@@ -52,30 +52,19 @@ where
5252 /// // This is where we call the function
5353 /// let sixteen = squared.call(4);
5454 /// ```
55+ // TODO: whenever Rust's Entry API gains the ability to take ownership of
56+ // arg only when necessary, this method should follow the same practice.
57+ // Also, Cacher should implement Fn(U)->V once this is possible.
5558 pub fn call ( & mut self , arg : U ) -> V {
56- // This is basically the magic of the whole
57- // structure. You can do this with the entry
58- // api, but I like how readable this particular
59- // block of code is.
60- if let Some ( & val) = self . values . get ( & arg) {
61- val
62- } else {
63- let val = ( self . calculation ) ( arg) ;
64- self . values . insert ( arg, val) ;
65- val
66- }
59+ let calc = & self . calculation ;
60+ * self . values . entry ( arg) . or_insert_with_key ( |& key| calc ( key) )
6761 }
6862
6963 /// Calls the function without performing a lookup and replaces
70- /// the old calculation with the new one, then returns the value
71- ///
72- /// # Use Case
73- /// If you're wondering, this is for if some sort of "state" has changed
74- /// underneath you, so your same function call with the same input
75- /// might now have different output. For instance, if part of your function
76- /// reads from a file and
77- /// you think the contents of that file have changed even though the name
78- /// has not.
64+ /// the old return value with the new one, and returns it.
65+ /// Potentially useful if the function reads from a file or RNG
66+ /// whose state may have changed.
67+ // TODO: if there's state, FnMut seems more appropriate.
7968 pub fn call_and_replace ( & mut self , arg : U ) -> V {
8069 let new_val = ( self . calculation ) ( arg) ;
8170 self . values . insert ( arg, new_val) ;
8574
8675#[ cfg( test) ]
8776mod tests {
88-
89- use super :: Cacher ;
90- use std:: collections:: HashMap ;
77+ use super :: * ;
9178
9279 #[ test]
9380 fn test_cacher_basically_works ( ) {
@@ -116,7 +103,21 @@ mod tests {
116103 }
117104
118105 #[ test]
119- fn call_and_replace ( ) {
106+ fn test_cacher_speed ( ) {
107+ // Simulate a function that takes 1 second to complete
108+ let mut func = Cacher :: new ( |x| {
109+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 100 ) ) ;
110+ x * x
111+ } ) ;
112+
113+ // Would take 10 minutes without caching
114+ for _ in 0 ..6000 {
115+ assert_eq ! ( 25 , func. call( 5 ) ) ;
116+ }
117+ }
118+
119+ #[ test]
120+ fn test_call_and_replace ( ) {
120121 use std:: time:: Instant ;
121122
122123 let mut func = Cacher :: new ( |_param : usize | Instant :: now ( ) ) ;
0 commit comments