use sha2::{Digest, Sha256};
use std::collections::HashMap;
pub trait Hasher {
fn hash(&self) -> String;
}
struct Entry<T> {
#[allow(dead_code)]
key: String,
value: T,
}
pub struct MemoCache<T> {
capacity: usize,
cache: HashMap<String, Entry<T>>,
order: Vec<String>,
}
pub fn new_memo_cache<T>(capacity: usize) -> MemoCache<T> {
MemoCache {
capacity,
cache: HashMap::new(),
order: Vec::new(),
}
}
impl<T> MemoCache<T> {
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn size(&self) -> usize {
self.order.len()
}
pub fn get<H: Hasher>(&mut self, h: &H) -> Option<&T> {
let hashed_key = h.hash();
if let Some(entry) = self.cache.get(&hashed_key) {
if let Some(pos) = self.order.iter().position(|k| *k == hashed_key) {
let k = self.order.remove(pos);
self.order.push(k);
}
return Some(&entry.value);
}
None
}
pub fn set<H: Hasher>(&mut self, h: &H, value: T) {
let hashed_key = h.hash();
if let Some(entry) = self.cache.get_mut(&hashed_key) {
entry.value = value;
if let Some(pos) = self.order.iter().position(|k| *k == hashed_key) {
let k = self.order.remove(pos);
self.order.push(k);
}
return;
}
if self.order.len() >= self.capacity {
if let Some(oldest) = self.order.first().cloned() {
self.order.remove(0);
self.cache.remove(&oldest);
}
}
let entry = Entry {
key: hashed_key.clone(),
value,
};
self.cache.insert(hashed_key.clone(), entry);
self.order.push(hashed_key);
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HString(pub String);
impl Hasher for HString {
fn hash(&self) -> String {
let digest = Sha256::digest(self.0.as_bytes());
let mut s = String::new();
for b in digest.iter() {
s.push_str(&format!("{:02x}", b));
}
s
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct HInt(pub i64);
impl Hasher for HInt {
fn hash(&self) -> String {
let digest = Sha256::digest(self.0.to_string().as_bytes());
let mut s = String::new();
for b in digest.iter() {
s.push_str(&format!("{:02x}", b));
}
s
}
}