use std::collections::{hash_map::Entry, HashMap, HashSet, VecDeque};
#[derive(Debug, Default)]
pub(crate) enum GroupIterState {
#[default]
Precursor,
Product(usize),
Done,
}
#[derive(Default, Debug)]
pub(crate) struct GenerationTracker {
generation_to_id: HashMap<usize, HashSet<String>>,
id_to_generation: HashMap<String, usize>,
generations: VecDeque<usize>,
}
impl GenerationTracker {
fn add_generation(&mut self, generation: usize) {
match self.generations.binary_search(&generation) {
Ok(i) => {
self.generations.insert(i, generation);
}
Err(i) => {
self.generations.insert(i, generation);
}
}
}
pub fn clear(&mut self) {
self.generation_to_id.clear();
self.id_to_generation.clear();
self.generations.clear();
}
pub fn add(&mut self, identifier: String, generation: usize) {
if !self.generation_to_id.contains_key(&generation) {
self.add_generation(generation);
}
self.generation_to_id
.entry(generation)
.or_default()
.insert(identifier.clone());
match self.id_to_generation.entry(identifier) {
Entry::Occupied(mut e) => {
e.insert(generation);
}
Entry::Vacant(e) => {
e.insert(generation);
}
}
}
#[allow(unused)]
pub fn remove(&mut self, identifier: String) -> bool {
match self.id_to_generation.entry(identifier.clone()) {
Entry::Occupied(ent) => {
let generation = ent.get();
let id_set = self
.generation_to_id
.get_mut(generation)
.unwrap_or_else(|| {
panic!("Generation {} did not contain {}", generation, identifier)
});
id_set.remove(&identifier);
if id_set.is_empty() {
self.generations.remove(*generation);
}
true
}
Entry::Vacant(_ent) => false,
}
}
pub fn older_than(&mut self, generation: usize) -> Vec<String> {
let mut result = Vec::new();
for gen in self.generations.iter() {
if *gen < generation {
if let Some(members) = self.generation_to_id.remove(gen) {
result.extend(members);
}
} else {
break;
}
}
for r in result.iter() {
self.id_to_generation.remove(r);
}
result
}
}