use crate::RafxResult;
use fnv::FnvHashMap;
use std::collections::hash_map::Entry;
pub struct LruCacheEntry<T: Clone> {
value: T,
last_usage: u64,
}
pub struct LruCache<T: Clone> {
entries: FnvHashMap<u64, LruCacheEntry<T>>,
next_usage_index: u64,
max_count: usize,
}
impl<T: Clone> LruCache<T> {
pub fn new(max_count: usize) -> Self {
LruCache {
entries: Default::default(),
next_usage_index: 0,
max_count,
}
}
pub fn clear(&mut self) {
self.entries.clear();
self.next_usage_index = 0;
}
pub fn get_or_create<CreateFn: FnOnce() -> RafxResult<T>>(
&mut self,
hash: u64,
create_fn: CreateFn,
) -> RafxResult<T> {
let value = match self.entries.entry(hash) {
Entry::Occupied(mut x) => {
let entry = x.get_mut();
entry.last_usage = self.next_usage_index;
entry.value.clone()
}
Entry::Vacant(x) => {
let entry = LruCacheEntry {
value: (create_fn)()?,
last_usage: self.next_usage_index,
};
x.insert(entry).value.clone()
}
};
self.next_usage_index += 1;
if self.entries.len() > self.max_count {
let mut min_usage = u64::MAX;
let mut min_usage_hash = 0;
for (&hash, entry) in &self.entries {
if entry.last_usage < min_usage {
min_usage = entry.last_usage;
min_usage_hash = hash;
}
}
self.entries.remove(&min_usage_hash);
}
Ok(value)
}
}