use std::collections::HashMap;
use std::hash::Hash;
use std::time::{Duration, SystemTime};
#[allow(unused)]
pub struct BlueGreenHashMap<K: Send, V: Send> {
expiration: Duration,
hashmap_blue: (HashMap<K, V>, SystemTime),
hashmap_green: (HashMap<K, V>, SystemTime),
}
impl<K, V> BlueGreenHashMap<K, V>
where
K: Eq + Hash + Send,
V: Send,
{
#[must_use]
pub fn new(expiration: Duration, now: SystemTime) -> Self {
Self {
expiration,
hashmap_blue: (HashMap::new(), now),
hashmap_green: (HashMap::new(), now - expiration),
}
}
pub fn insert(&mut self, key: K, value: V, now: SystemTime) {
self.get_unexpired_hashmap(now).insert(key, value);
}
pub fn remove(&mut self, key: &K) -> Option<V> {
if let Some(x) = self.hashmap_blue.0.remove(key) {
Some(x)
} else {
self.hashmap_green.0.remove(key)
}
}
fn get_unexpired_hashmap(&mut self, now: SystemTime) -> &mut HashMap<K, V> {
let blue_creation_time = self.hashmap_blue.1;
let green_creation_time = self.hashmap_green.1;
if blue_creation_time + self.expiration > now && blue_creation_time < green_creation_time {
return &mut self.hashmap_blue.0;
} else if green_creation_time + self.expiration > now {
return &mut self.hashmap_green.0;
}
if green_creation_time > blue_creation_time {
self.hashmap_blue = (HashMap::new(), now);
&mut self.hashmap_blue.0
} else {
self.hashmap_green = (HashMap::new(), now);
&mut self.hashmap_green.0
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn can_access_after_writing() {
let mut hashmap = BlueGreenHashMap::new(Duration::from_secs(10), SystemTime::now());
hashmap.insert("a", 1234, SystemTime::now());
assert_eq!(Some(1234), hashmap.remove(&"a"));
}
#[test]
pub fn removes_expired_entries() {
let start_time = SystemTime::now();
let mut hashmap = BlueGreenHashMap::new(Duration::from_secs(10), start_time);
hashmap.insert("a".to_string(), "b", start_time.clone());
hashmap.insert(
"b".to_string(),
"c",
start_time.clone() + Duration::from_secs(20),
);
assert_eq!(None, hashmap.remove(&"a".to_string()));
assert_eq!(Some("c"), hashmap.remove(&"b".to_string()));
}
}