use std::collections::BTreeSet;
use crate::graph::topology::{Topology, Transitive};
use crate::graph::Graph;
pub struct CommonDescendants<'a> {
topology: &'a Topology<Transitive>,
descendants: BTreeSet<usize>,
}
impl<T> Graph<T, Transitive> {
pub fn common_descendants<N>(&self, nodes: N) -> CommonDescendants<'_>
where
N: AsRef<[usize]>,
{
let nodes = nodes.as_ref();
let mut descendants = BTreeSet::new();
for descendant in self {
let mut iter = nodes.iter();
if iter.all(|&node| self.topology.has_path(node, descendant)) {
descendants.insert(descendant);
}
}
CommonDescendants {
topology: &self.topology,
descendants,
}
}
}
impl Iterator for CommonDescendants<'_> {
type Item = Vec<usize>;
fn next(&mut self) -> Option<Self::Item> {
if self.descendants.is_empty() {
return None;
}
let mut layer = Vec::new();
for &descendant in &self.descendants {
let mut iter = self.descendants.iter();
if !iter.any(|&node| {
node != descendant && self.topology.has_path(node, descendant)
}) {
layer.push(descendant);
}
}
self.descendants.retain(|node| !layer.contains(node));
(!layer.is_empty()).then_some(layer)
}
}
#[cfg(test)]
mod tests {
mod common_descendants {
use crate::graph;
#[test]
fn handles_graph() {
let graph = graph! {
transitive;
"a" => "d",
"b" => "d", "b" => "e",
"c" => "f", "c" => "g",
"d" => "f", "d" => "g",
"e" => "g",
};
assert_eq!(
graph.common_descendants([0, 2]).collect::<Vec<_>>(),
vec![vec![1], vec![5, 6]]
);
}
#[test]
fn handles_multi_graph() {
let graph = graph! {
transitive;
"a" => "d",
"b" => "d", "b" => "e", "b" => "e",
"c" => "f", "c" => "g",
"d" => "f", "d" => "g",
"e" => "g",
};
assert_eq!(
graph.common_descendants([0, 2]).collect::<Vec<_>>(),
vec![vec![1], vec![5, 6]]
);
}
}
}