use crate::utilities::*;
use hashbrown::HashMap;
use std::cmp::min;
use std::fmt::Debug;
use std::hash::Hash;
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
pub struct Stored<I: IndexLike> {
pub id: I,
pub is_new: bool,
}
pub struct Memoize<T: KeyLike, I: IndexLike> {
id_by_value: HashMap<T, I>,
max_count: usize,
value_by_id: Vec<(T, I)>,
}
impl<T: KeyLike + Default, I: IndexLike> Memoize<T, I> {
pub fn new(max_count: usize) -> Self {
Self::with_capacity(max_count, max_count)
}
pub fn with_capacity(max_count: usize, capacity: usize) -> Self {
let capacity = min(capacity, max_count);
Self {
max_count,
id_by_value: HashMap::with_capacity(capacity),
value_by_id: Vec::with_capacity(capacity),
}
}
pub fn len(&self) -> usize {
self.value_by_id.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn store(&mut self, value: T) -> Stored<I> {
let mut is_new = false;
let next_id = self.value_by_id.len();
let max_count = self.max_count;
let id = *self.id_by_value.entry(value).or_insert_with(|| {
is_new = true;
assert!(
next_id < max_count,
"too many ({}) memoized objects",
next_id + 1 );
I::from_usize(next_id)
});
if is_new {
self.value_by_id.push((value, I::from_usize(0)));
}
Stored { id, is_new }
}
pub fn get(&self, id: I) -> T {
debug_assert!(id.to_usize() < self.len());
self.value_by_id[id.to_usize()].0
}
}