use std::collections::{hash_map::Entry, HashMap};
use std::hash::Hash;
use std::rc::Rc;
#[derive(Debug, Clone)]
pub struct SortedInsertHashmap<K, V> {
map: HashMap<Rc<K>, usize>,
last_entry: Option<usize>,
order: Vec<(Rc<K>, V)>,
}
impl<K, V> Default for SortedInsertHashmap<K, V> {
fn default() -> Self {
Self {
map: HashMap::new(),
last_entry: None,
order: Vec::new(),
}
}
}
impl<K: Eq + Hash, V> SortedInsertHashmap<K, V> {
pub fn new() -> Self {
Self::default()
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn insert_with_or_else<I, U>(
&mut self,
key: K,
callback_insert: I,
callback_update: U,
) -> bool
where
I: FnOnce() -> V,
U: FnOnce(&mut V),
{
if let Some(item_index) = self.last_entry {
let (last_key, value) = &mut self.order[item_index];
if last_key.as_ref() == &key {
callback_update(value);
return false;
}
}
let key = Rc::new(key);
let mut key_was_inserted = false;
let item_index = match self.map.entry(key.clone()) {
Entry::Occupied(entry) => {
let item_index = *entry.get();
let value = &mut self.order[item_index].1;
callback_update(value);
item_index
}
Entry::Vacant(entry) => {
key_was_inserted = true;
let item_index = self.order.len();
entry.insert(item_index);
self.order.push((key, callback_insert()));
item_index
}
};
self.last_entry = Some(item_index);
key_was_inserted
}
pub fn insert_with<F>(&mut self, key: K, callback: F) -> &mut V
where
F: FnOnce() -> V,
{
self.insert_with_or_else(key, callback, |_| {});
&mut self.order[self.last_entry.unwrap()].1
}
pub fn get(&self, key: &K) -> Option<&V> {
self.map.get(key).map(|index| &self.order[*index].1)
}
pub fn values(&self) -> impl Iterator<Item = &V> {
self.order.iter().map(|(_, cell)| cell)
}
pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
self.order.iter().map(|(k, cell)| (k.as_ref(), cell))
}
pub fn into_iter(self) -> impl Iterator<Item = (K, V)> {
self.order
.into_iter()
.map(|(k, v)| (Rc::into_inner(k).unwrap(), v))
}
pub fn into_values(self) -> impl Iterator<Item = V> {
self.order.into_iter().map(|(_, v)| v)
}
}