use std::{collections::HashSet, hash::BuildHasher};
#[derive(Clone, Debug, Default)]
pub struct Visit<T, S = super::Hasher> {
visited: HashSet<T, S>,
to_visit: Vec<T>,
}
impl<T, S> Visit<T, S>
where
S: BuildHasher + Default,
T: Clone + Eq + std::hash::Hash,
{
pub fn new() -> Self {
Self {
visited: HashSet::<_, S>::default(),
to_visit: Vec::new(),
}
}
pub fn insert(&mut self, item: T) -> bool {
let visit = self.visited.insert(item.clone());
if visit {
self.to_visit.push(item)
}
visit
}
pub fn pop(&mut self) -> Option<T> {
self.to_visit.pop()
}
}
impl<T, S> IntoIterator for Visit<T, S>
where
S: BuildHasher,
T: Eq + std::hash::Hash,
{
type Item = T;
type IntoIter = <HashSet<T, S> as IntoIterator>::IntoIter;
fn into_iter(mut self) -> Self::IntoIter {
for item in self.to_visit {
self.visited.remove(&item);
}
self.visited.into_iter()
}
}
pub struct ReVisit<T, S = super::Hasher> {
visiting: HashSet<T, S>,
to_visit: Vec<T>,
}
impl<T, S> ReVisit<T, S>
where
S: BuildHasher + Default,
T: Clone + Eq + std::hash::Hash,
{
pub fn new() -> Self {
Self {
visiting: HashSet::default(),
to_visit: Vec::new(),
}
}
pub fn insert(&mut self, item: T) -> bool {
let result = self.visiting.insert(item.clone());
if result {
self.to_visit.push(item);
}
result
}
pub fn pop(&mut self) -> Option<T> {
let item = self.to_visit.pop()?;
self.visiting.remove(&item);
Some(item)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{structures::Set, test_common::collect};
#[test]
fn visit() {
let mut visit: Visit<i32> = Visit::new();
assert!(visit.insert(0));
assert!(visit.insert(1));
assert!(visit.insert(2));
assert!(!visit.insert(1));
assert!(!visit.insert(2));
assert_eq!(visit.pop(), Some(2));
assert!(!visit.insert(2));
assert_eq!(visit.pop(), Some(1));
assert!(!visit.insert(2));
assert!(visit.insert(3));
assert_eq!(visit.pop(), Some(3));
assert_eq!(visit.pop(), Some(0));
assert!(visit.insert(4));
assert_eq!(
visit.into_iter().collect::<Set<i32>>(),
collect(&[0, 1, 2, 3])
);
}
#[test]
fn re_visit() {
let mut visit: ReVisit<i32> = ReVisit::new();
assert!(visit.insert(0));
assert!(visit.insert(1));
assert!(visit.insert(2));
assert!(!visit.insert(1));
assert!(!visit.insert(2));
assert_eq!(visit.pop(), Some(2));
assert!(visit.insert(2));
assert_eq!(visit.pop(), Some(2));
assert!(!visit.insert(1));
assert!(visit.insert(3));
assert_eq!(visit.pop(), Some(3));
assert_eq!(visit.pop(), Some(1));
assert_eq!(visit.pop(), Some(0));
}
}