use ahash::HashSet;
use std::sync::Mutex;
pub struct SharedFifoSet {
inner: Mutex<FifoSet>,
}
impl SharedFifoSet {
pub fn new(capacity: usize) -> Self {
Self {
inner: Mutex::new(FifoSet::new(capacity)),
}
}
pub fn insert(&self, value: u64) -> bool {
let mut inner = self
.inner
.lock()
.expect("Failed to acquire lock on SharedFifoSet");
inner.insert(value)
}
}
pub struct FifoSet {
eviction_order: Vec<u64>,
seen: HashSet<u64>, next_evict: u32,
capacity: u32,
}
impl FifoSet {
pub fn new(capacity: usize) -> Self {
assert!(
capacity > 0 && capacity < 10_000_000_usize,
"capacity must be between 1 and 10M"
);
Self {
eviction_order: Vec::new(),
seen: HashSet::default(),
next_evict: 0,
capacity: capacity as u32,
}
}
#[inline]
pub fn insert(&mut self, value: u64) -> bool {
if self.seen.contains(&value) {
return false;
}
if self.seen.len() == self.capacity as usize {
self.seen
.remove(&self.eviction_order[self.next_evict as usize]);
self.eviction_order[self.next_evict as usize] = value;
} else {
self.eviction_order.push(value);
}
self.seen.insert(value);
self.next_evict = (self.next_evict + 1) % self.capacity;
true
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fifo_set_overflow() {
let capacity = 3;
let mut set = FifoSet::new(capacity);
assert!(set.insert(1));
assert!(set.insert(2));
assert!(set.insert(3));
assert!(!set.insert(3));
assert_eq!(set.seen.len(), 3);
assert!(set.insert(4));
assert!(!set.seen.contains(&1));
assert!(set.seen.contains(&4));
assert!(set.insert(5));
assert!(!set.seen.contains(&2));
assert!(set.seen.contains(&5));
}
}