Skip to content

Commit a2d9598

Browse files
committed
Cacher with Entry API
1 parent 10e42cb commit a2d9598

File tree

2 files changed

+27
-26
lines changed

2 files changed

+27
-26
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
language: rust
22
rust:
3-
- 1.42.0 # Version currently supported by Codeforces
3+
#- 1.51.0 # Version currently supported by Codeforces
44
- stable
55
- beta
66
- nightly

src/caching.rs

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ where
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);
@@ -85,9 +74,7 @@ where
8574

8675
#[cfg(test)]
8776
mod 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

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy