use ahash::HashSet;
use crate::graph::topology::Adjacency;
use crate::graph::Graph;
pub struct Ancestors<'a> {
incoming: &'a Adjacency,
stack: Vec<usize>,
visited: HashSet<usize>,
}
impl<T> Graph<T> {
#[inline]
#[must_use]
pub fn ancestors(&self, node: usize) -> Ancestors<'_> {
let mut iter = Ancestors {
incoming: self.topology.incoming(),
stack: Vec::from([node]),
visited: HashSet::default(),
};
iter.next();
iter
}
}
impl Iterator for Ancestors<'_> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
let node = self.stack.pop()?;
for &ancestor in self.incoming[node].iter().rev() {
if self.visited.insert(ancestor) {
self.stack.push(ancestor);
}
}
Some(node)
}
}
#[cfg(test)]
mod tests {
mod ancestors {
use crate::graph;
#[test]
fn handles_graph() {
let graph = graph! {
"a" => "b", "a" => "c",
"b" => "d", "b" => "e",
"c" => "f",
"d" => "g",
"e" => "g", "e" => "h",
"f" => "h",
"g" => "i",
"h" => "i",
};
for (node, ancestors) in [
(0, vec![]),
(1, vec![0]),
(2, vec![0]),
(3, vec![1, 0]),
(4, vec![1, 0]),
(5, vec![2, 0]),
(6, vec![3, 1, 0, 4]),
(7, vec![4, 1, 0, 5, 2]),
(8, vec![6, 3, 1, 0, 4, 7, 5, 2]),
] {
assert_eq!(
graph.ancestors(node).collect::<Vec<_>>(),
ancestors
);
}
}
#[test]
fn handles_multi_graph() {
let graph = graph! {
"a" => "b", "a" => "c", "a" => "c",
"b" => "d", "b" => "e",
"c" => "f",
"d" => "g",
"e" => "g", "e" => "h",
"f" => "h",
"g" => "i",
"h" => "i",
};
for (node, ancestors) in [
(0, vec![]),
(1, vec![0]),
(2, vec![0]),
(3, vec![1, 0]),
(4, vec![1, 0]),
(5, vec![2, 0]),
(6, vec![3, 1, 0, 4]),
(7, vec![4, 1, 0, 5, 2]),
(8, vec![6, 3, 1, 0, 4, 7, 5, 2]),
] {
assert_eq!(
graph.ancestors(node).collect::<Vec<_>>(),
ancestors
);
}
}
}
}