use ahash::HashSet;
use crate::graph::topology::Adjacency;
use crate::graph::Graph;
pub struct Descendants<'a> {
outgoing: &'a Adjacency,
stack: Vec<usize>,
visited: HashSet<usize>,
}
impl<T> Graph<T> {
#[inline]
#[must_use]
pub fn descendants(&self, node: usize) -> Descendants<'_> {
let mut iter = Descendants {
outgoing: self.topology.outgoing(),
stack: Vec::from([node]),
visited: HashSet::default(),
};
iter.next();
iter
}
}
impl Iterator for Descendants<'_> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
let node = self.stack.pop()?;
for &descendant in self.outgoing[node].iter().rev() {
if self.visited.insert(descendant) {
self.stack.push(descendant);
}
}
Some(node)
}
}
#[cfg(test)]
mod tests {
mod descendants {
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, descendants) in [
(0, vec![1, 3, 6, 8, 4, 7, 2, 5]),
(1, vec![3, 6, 8, 4, 7]),
(2, vec![5, 7, 8]),
(3, vec![6, 8]),
(4, vec![6, 8, 7]),
(5, vec![7, 8]),
(6, vec![8]),
(7, vec![8]),
(8, vec![]),
] {
assert_eq!(
graph.descendants(node).collect::<Vec<_>>(),
descendants
);
}
}
#[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, descendants) in [
(0, vec![1, 3, 6, 8, 4, 7, 2, 5]),
(1, vec![3, 6, 8, 4, 7]),
(2, vec![5, 7, 8]),
(3, vec![6, 8]),
(4, vec![6, 8, 7]),
(5, vec![7, 8]),
(6, vec![8]),
(7, vec![8]),
(8, vec![]),
] {
assert_eq!(
graph.descendants(node).collect::<Vec<_>>(),
descendants
);
}
}
}
}