use std::borrow::Borrow;
use std::cmp::Ord;
use std::collections::HashMap;
use std::hash::Hash;
#[derive(Debug)]
pub struct HashMapWithOrderedKeys<K: Ord, V> {
map: HashMap<K, V>,
keys: Vec<K>,
}
impl<K: Ord + Hash + Clone, V> Default for HashMapWithOrderedKeys<K, V> {
fn default() -> Self {
Self::new()
}
}
impl<K: Ord + Hash + Clone, V> HashMapWithOrderedKeys<K, V> {
pub fn new() -> Self {
Self {
map: HashMap::new(),
keys: vec![],
}
}
pub fn get<Q>(&self, k: &Q) -> Option<&V>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
self.map.get(k)
}
pub fn get_mut<Q>(&mut self, k: &Q) -> Option<&mut V>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
self.map.get_mut(k)
}
pub fn contains_key<Q>(&self, k: &Q) -> bool
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
self.map.contains_key(k)
}
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
self.map.insert(k.clone(), v).or_else(|| {
self.keys.push(k);
self.keys.sort();
None
})
}
pub fn remove(&mut self, k: &K) -> Option<V> {
if let Ok(index) = self.keys.binary_search(k) {
self.keys.remove(index);
}
self.map.remove(k)
}
pub fn drain_all(&mut self) -> Vec<(K, V)> {
let entries: Vec<(K, V)> = self.map.drain().collect();
self.keys.clear();
entries
}
pub fn ordered_keys(&self) -> &Vec<K> {
&self.keys
}
pub fn remove_if<F>(&mut self, predicate: F)
where
F: Fn(&mut V) -> bool,
{
let mut keys_to_remove = Vec::new();
for key in &self.keys {
if let Some(value) = self.map.get_mut(key) {
if !predicate(value) {
keys_to_remove.push(key.clone());
}
}
}
for key in &keys_to_remove {
self.map.remove(key);
self.keys.retain(|k| k != key);
}
}
pub fn remove_if_and_return<F>(&mut self, predicate: F) -> Vec<(K, V)>
where
F: Fn(&mut V) -> bool,
{
let mut keys_to_remove = Vec::new();
for key in &self.keys {
if let Some(value) = self.map.get_mut(key) {
if !predicate(value) {
keys_to_remove.push(key.clone());
}
}
}
let mut removed = Vec::with_capacity(keys_to_remove.len());
for key in &keys_to_remove {
if let Some(value) = self.map.remove(key) {
removed.push((key.clone(), value));
}
self.keys.retain(|k| k != key);
}
removed
}
}