dag: Accept multiple roots in `fold`, remove depth

This allows the fold to start anywhere in our DAG.
This commit is contained in:
cloudhead 2023-09-07 10:02:06 +02:00
parent 5c256c8bfb
commit f760b1153f
No known key found for this signature in database
3 changed files with 10 additions and 56 deletions

View File

@ -91,7 +91,7 @@ impl ChangeGraph {
let manifest = root_node.manifest.clone(); let manifest = root_node.manifest.clone();
let graph = self let graph = self
.graph .graph
.fold(&root, Dag::new(), |mut graph, _, change, _| { .fold(&[root], Dag::new(), |mut graph, _, change| {
// Check the change signatures are valid. // Check the change signatures are valid.
if !change.valid_signatures() { if !change.valid_signatures() {
return ControlFlow::Break(graph); return ControlFlow::Break(graph);

View File

@ -65,7 +65,7 @@ impl History {
F: for<'r> FnMut(A, &'r EntryId, &'r Entry) -> ControlFlow<A, A>, F: for<'r> FnMut(A, &'r EntryId, &'r Entry) -> ControlFlow<A, A>,
{ {
self.graph self.graph
.fold(&self.root, init, |acc, k, v, _| f(acc, k, v)) .fold(&[self.root], init, |acc, k, v| f(acc, k, v))
} }
/// Return a topologically-sorted list of history entries. /// Return a topologically-sorted list of history entries.

View File

@ -187,21 +187,21 @@ impl<K: Ord + Copy, V> Dag<K, V> {
/// ///
/// To continue traversing a branch, return [`ControlFlow::Continue`] from the /// To continue traversing a branch, return [`ControlFlow::Continue`] from the
/// filter function. To stop traversal of a branch, return [`ControlFlow::Break`]. /// filter function. To stop traversal of a branch, return [`ControlFlow::Break`].
pub fn fold<A, F>(&self, root: &K, mut acc: A, mut filter: F) -> A pub fn fold<A, F>(&self, roots: &[K], mut acc: A, mut filter: F) -> A
where where
F: for<'r> FnMut(A, &'r K, &'r Node<K, V>, usize) -> ControlFlow<A, A>, F: for<'r> FnMut(A, &'r K, &'r Node<K, V>) -> ControlFlow<A, A>,
{ {
let mut visited = BTreeSet::new(); let mut visited = BTreeSet::new();
let mut queue = VecDeque::<(K, usize)>::from([(*root, 0)]); let mut queue = VecDeque::<K>::from_iter(roots.iter().cloned());
while let Some((next, depth)) = queue.pop_front() { while let Some(next) = queue.pop_front() {
if !visited.insert(next) { if !visited.insert(next) {
continue; continue;
} }
if let Some(node) = self.graph.get(&next) { if let Some(node) = self.graph.get(&next) {
match filter(acc, &next, node, depth) { match filter(acc, &next, node) {
ControlFlow::Continue(a) => { ControlFlow::Continue(a) => {
queue.extend(node.dependents.iter().map(|k| (*k, depth + 1))); queue.extend(node.dependents.iter().cloned());
acc = a; acc = a;
} }
ControlFlow::Break(a) => { ControlFlow::Break(a) => {
@ -497,59 +497,13 @@ mod tests {
dag.dependency("C1", "B2"); dag.dependency("C1", "B2");
dag.dependency("C1", "B3"); dag.dependency("C1", "B3");
let acc = dag.fold(&"R", Vec::new(), |mut acc, key, _, _| { let acc = dag.fold(&["R"], Vec::new(), |mut acc, key, _| {
acc.push(*key); acc.push(*key);
ControlFlow::Continue(acc) ControlFlow::Continue(acc)
}); });
assert_eq!(acc, vec!["R", "A1", "A2", "A3", "B1", "B2", "B3", "C1"]); assert_eq!(acc, vec!["R", "A1", "A2", "A3", "B1", "B2", "B3", "C1"]);
} }
#[test]
fn test_fold_depth() {
let mut dag = Dag::new();
dag.node("R", ());
dag.node("A1", ());
dag.node("A2", ());
dag.node("A3", ());
dag.node("B1", ());
dag.node("B2", ());
dag.node("B3", ());
dag.node("C1", ());
dag.dependency("A1", "R");
dag.dependency("A2", "R");
dag.dependency("A3", "R");
dag.dependency("B1", "A1");
dag.dependency("B2", "A1");
dag.dependency("B3", "A2");
dag.dependency("B3", "A3");
dag.dependency("C1", "B1");
dag.dependency("C1", "B2");
dag.dependency("C1", "B3");
let acc = dag.fold(&"R", Vec::new(), |mut acc, key, _, depth| {
acc.push((*key, depth));
ControlFlow::Continue(acc)
});
assert_eq!(
acc,
vec![
("R", 0),
("A1", 1),
("A2", 1),
("A3", 1),
("B1", 2),
("B2", 2),
("B3", 2),
("C1", 3)
]
);
}
#[test] #[test]
fn test_fold_reject() { fn test_fold_reject() {
let mut dag = Dag::new(); let mut dag = Dag::new();
@ -571,7 +525,7 @@ mod tests {
let a1 = dag.get(&"A1").unwrap(); let a1 = dag.get(&"A1").unwrap();
assert_eq!(dag.descendants_of(a1), vec!["B1", "C1", "D1"]); assert_eq!(dag.descendants_of(a1), vec!["B1", "C1", "D1"]);
let acc = dag.fold(&"R", Vec::new(), |mut acc, key, accept, _| { let acc = dag.fold(&["R"], Vec::new(), |mut acc, key, accept| {
if !accept.value { if !accept.value {
ControlFlow::Break(acc) ControlFlow::Break(acc)
} else { } else {