use std::collections::{HashSet, VecDeque};
use std::hash::Hash;
#[derive(Clone, Debug)]
pub struct BoundedSeen<T> {
set: HashSet<T>,
order: VecDeque<T>,
cap: usize,
}
impl<T: Eq + Hash + Clone> BoundedSeen<T> {
pub fn new(cap: usize) -> Self {
Self {
set: HashSet::with_capacity(cap.min(1024)),
order: VecDeque::with_capacity(cap.min(1024)),
cap,
}
}
pub fn insert(&mut self, item: T) -> bool {
if !self.set.insert(item.clone()) {
return false;
}
self.order.push_back(item);
if self.order.len() > self.cap {
if let Some(old) = self.order.pop_front() {
self.set.remove(&old);
}
}
true
}
pub fn len(&self) -> usize {
self.set.len()
}
pub fn is_empty(&self) -> bool {
self.set.is_empty()
}
pub fn clear(&mut self) {
self.set.clear();
self.order.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn insert_new_returns_true() {
let mut s = BoundedSeen::new(10);
assert!(s.insert(1));
}
#[test]
fn insert_duplicate_returns_false() {
let mut s = BoundedSeen::new(10);
s.insert(1);
assert!(!s.insert(1));
}
#[test]
fn evicts_oldest_on_overflow() {
let mut s = BoundedSeen::new(3);
s.insert(1);
s.insert(2);
s.insert(3);
s.insert(4);
assert!(s.insert(1));
assert!(!s.insert(4));
assert_eq!(s.len(), 3);
}
#[test]
fn clear_resets() {
let mut s = BoundedSeen::new(100);
s.insert("a");
s.clear();
assert!(s.is_empty());
assert!(s.insert("a")); }
}