use std::{ borrow::Borrow, collections::{hash_map::Entry, HashMap}, hash::Hash, }; struct RecentlyUsedItem { entry_idx: usize, value: V, } pub struct RecentlyUsedMap { keys: Vec, map: HashMap>, } impl RecentlyUsedMap { pub fn new() -> Self { Self::with_capacity(0) } pub fn with_capacity(capacity: usize) -> Self { Self { keys: Vec::with_capacity(capacity), map: HashMap::with_capacity(capacity), } } pub fn insert(&mut self, key: K, value: V) { let new_idx = self.keys.len(); match self.map.entry(key) { Entry::Occupied(mut occupied) => { let old = occupied.insert(RecentlyUsedItem { entry_idx: new_idx, value, }); let removed = self.keys.remove(old.entry_idx); self.keys.push(removed); } Entry::Vacant(vacant) => { vacant.insert(RecentlyUsedItem { entry_idx: new_idx, value, }); self.keys.push(key); } } } pub fn remove(&mut self, key: &Q) where K: Borrow, Q: Hash + Eq, { if let Some(entry) = self.map.remove(key.borrow()) { self.keys.remove(entry.entry_idx); } } pub fn get(&self, k: &Q) -> Option<&V> where K: Borrow, Q: Hash + Eq, { self.map.get(k).map(|item| &item.value) } pub fn contains_key(&self, k: &Q) -> bool where K: Borrow, Q: Hash + Eq, { self.map.contains_key(k) } pub fn entries_least_recently_used(&self) -> impl Iterator + '_ { self.keys.iter().map(|k| (*k, &self.map[k].value)) } } #[cfg(test)] mod tests { use super::*; #[test] fn insert() { let mut rus = RecentlyUsedMap::new(); rus.insert("a", ()); rus.insert("b", ()); assert_eq!( rus.entries_least_recently_used() .map(|(k, _)| k) .collect::(), "ab" ); } #[test] fn reinsert() { let mut rus = RecentlyUsedMap::new(); rus.insert("a", ()); rus.insert("b", ()); rus.insert("c", ()); rus.insert("a", ()); assert_eq!( rus.entries_least_recently_used() .map(|(k, _)| k) .collect::(), "bca" ); } #[test] fn remove() { let mut rus = RecentlyUsedMap::new(); rus.insert("a", ()); rus.insert("b", ()); rus.remove("a"); rus.remove("c"); assert_eq!( rus.entries_least_recently_used() .map(|(k, _)| k) .collect::(), "b" ); } }