use itertools::Itertools;
use std::collections::HashMap;
use std::hash::Hash;
use std::ops::Index;
#[derive(Debug, Clone)]
pub(crate) struct IndexedCache<T> {
pub(crate) cache: Vec<T>,
lookup: HashMap<T, usize>,
}
impl<T> PartialEq for IndexedCache<T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.cache == other.cache
}
}
impl<T> IndexedCache<T>
where
T: Clone + Eq + Hash + Ord,
{
pub(crate) fn new() -> Self {
IndexedCache {
cache: Default::default(),
lookup: Default::default(),
}
}
#[allow(dead_code)]
pub(crate) fn len(&self) -> usize {
self.cache.len()
}
#[allow(dead_code)]
pub(crate) fn sorted(&self) -> IndexedCache<T> {
let mut sorted = Self::new();
self.cache.iter().sorted().cloned().for_each(|item| {
let n = sorted.cache.len();
sorted.cache.push(item.clone());
sorted.lookup.insert(item, n);
});
sorted
}
}
impl<T> IntoIterator for IndexedCache<T> {
type Item = T;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.cache.into_iter()
}
}
impl<'a, T> IntoIterator for &'a IndexedCache<T> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.cache.iter()
}
}
impl<T> Index<usize> for IndexedCache<T> {
type Output = T;
fn index(&self, i: usize) -> &T {
&self.cache[i]
}
}
impl<A: Hash + Eq + Clone> FromIterator<A> for IndexedCache<A> {
fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
let mut cache = Vec::new();
let mut lookup = HashMap::new();
for (index, elem) in iter.into_iter().enumerate() {
cache.push(elem.clone());
lookup.insert(elem, index);
}
Self { cache, lookup }
}
}