1use std::collections::HashMap;
67use std::collections::HashSet;
68use std::hash::Hash;
69use std::iter;
70use std::rc::Rc;
71
72use futures::future::try_join_all;
73use indexmap::IndexMap;
74use indexmap::IndexSet;
75use itertools::Itertools as _;
76use thiserror::Error;
77
78#[derive(Clone, Eq, PartialEq, Debug)]
81pub struct SimpleDirectedGraph<N>
82where
83 N: Clone + Eq + Hash,
84{
85 adj: IndexMap<N, IndexSet<N>>,
91}
92
93impl<N> SimpleDirectedGraph<N>
94where
95 N: Clone + Eq + Hash,
96{
97 pub fn new<EI>(edges: EI) -> Self
99 where
100 EI: IntoIterator<Item = (N, N)>,
101 {
102 let mut adj: IndexMap<N, IndexSet<N>> = IndexMap::new();
103 for (parent, child) in edges {
104 adj.entry(parent).or_default().insert(child.clone());
105 adj.entry(child).or_default();
106 }
107 Self { adj }
108 }
109
110 pub fn nodes(&self) -> impl Iterator<Item = &N> {
112 self.adj.keys()
113 }
114
115 pub fn num_nodes(&self) -> usize {
117 self.adj.len()
118 }
119
120 pub fn edges(&self) -> impl Iterator<Item = (&N, &N)> {
122 self.adj
123 .iter()
124 .flat_map(|(parent, adj_set)| adj_set.iter().map(move |child| (parent, child)))
125 }
126
127 pub fn adjacent_nodes(&self, node: &N) -> Option<impl DoubleEndedIterator<Item = &N>> {
130 self.adj.get(node).map(|adj_set| adj_set.iter())
131 }
132
133 pub fn contains_node(&self, node: &N) -> bool {
135 self.adj.contains_key(node)
136 }
137
138 pub fn get_postorder<'a>(&'a self, start_node: &'a N) -> Vec<&'a N> {
141 post_order(start_node, |&u| self.adjacent_nodes(u).unwrap()).collect_vec()
142 }
143}
144
145#[derive(Clone, Eq, PartialEq, Debug)]
152pub struct FlowGraph<N>
153where
154 N: Clone + Eq + Hash,
155{
156 pub graph: SimpleDirectedGraph<N>,
158 pub start_node: N,
160}
161
162pub struct DominatorFinder<'a, N> {
165 node_to_id: HashMap<&'a N, InternalId>,
168 id_to_node: Vec<&'a N>,
170 immediate_dominators: Vec<InternalId>,
173}
174
175#[derive(Debug, Error, PartialEq)]
177pub enum DominatorFinderError {
178 #[error("The flow graph is invalid: some nodes are unreachable from the start node")]
180 UnreachableNodesInFlowGraph,
181 #[error("Target set must not be empty")]
183 EmptyTargetSet,
184 #[error("Target set contains a node which is not in the flow graph")]
186 UnknownNodeInTargetSet,
187}
188
189type InternalId = usize;
192
193impl<'a, N> DominatorFinder<'a, N>
194where
195 N: Clone + Eq + Hash,
196{
197 pub fn calculate(flow_graph: &'a FlowGraph<N>) -> Result<Self, DominatorFinderError> {
200 let postorder = flow_graph.graph.get_postorder(&flow_graph.start_node);
202 if postorder.len() != flow_graph.graph.num_nodes() {
203 return Err(DominatorFinderError::UnreachableNodesInFlowGraph);
204 }
205
206 let mut node_to_id = HashMap::new();
208 let mut id_to_node = Vec::new();
209 for (index, &node) in postorder.iter().enumerate() {
210 id_to_node.push(node);
211 node_to_id.insert(node, index);
212 }
213
214 let num_nodes = node_to_id.len();
216 let mut rev_adj = vec![vec![]; num_nodes];
217 for (u, v) in flow_graph.graph.edges() {
218 rev_adj[node_to_id[v]].push(node_to_id[u]);
219 }
220
221 let immediate_dominators = Self::calculate_immediate_dominators(&rev_adj);
224
225 Ok(Self {
226 node_to_id,
227 id_to_node,
228 immediate_dominators,
229 })
230 }
231
232 pub fn get_immediate_dominators(&self) -> HashMap<N, N> {
235 self.immediate_dominators
236 .iter()
237 .enumerate()
238 .map(|(index, &idom)| {
239 (
240 self.id_to_node[index].clone(),
241 self.id_to_node[idom].clone(),
242 )
243 })
244 .collect()
245 }
246
247 pub fn find_closest_common_dominator<NI>(
250 &self,
251 target_set: NI,
252 ) -> Result<N, DominatorFinderError>
253 where
254 NI: IntoIterator<Item = N>,
255 {
256 let target_ids: Vec<InternalId> = target_set
258 .into_iter()
259 .map(|node| match self.node_to_id.get(&node) {
260 Some(id) => Ok(*id),
261 None => Err(DominatorFinderError::UnknownNodeInTargetSet),
262 })
263 .try_collect()?;
264 if target_ids.is_empty() {
265 return Err(DominatorFinderError::EmptyTargetSet);
266 }
267
268 let closest_common_dominator =
271 Self::find_lowest_common_ancestor(&target_ids, &self.immediate_dominators);
272
273 Ok(self.id_to_node[closest_common_dominator].clone())
275 }
276
277 fn calculate_immediate_dominators(rev_adj: &[Vec<InternalId>]) -> Vec<InternalId> {
281 let num_nodes = rev_adj.len();
283 let start_node_id = num_nodes - 1;
284
285 let mut immediate_dominators: Vec<InternalId> = vec![usize::MAX; num_nodes];
292 immediate_dominators[start_node_id] = start_node_id;
297
298 loop {
299 let mut changed = false;
305
306 for u in (0..start_node_id).rev() {
308 let mut new_idom = usize::MAX;
309 let preds = &rev_adj[u];
311 for &p in preds {
312 if immediate_dominators[p] == usize::MAX {
313 continue;
315 }
316 if new_idom == usize::MAX {
317 new_idom = p;
321 } else {
322 new_idom = Self::intersect(new_idom, p, &immediate_dominators);
324 }
325 }
326 if new_idom == usize::MAX {
327 continue;
330 }
331 if immediate_dominators[u] != new_idom {
332 immediate_dominators[u] = new_idom;
334 changed = true;
335 }
336 }
337
338 if !changed {
339 break;
341 }
342 }
343
344 immediate_dominators
348 }
349
350 fn intersect(
352 mut b1: InternalId,
353 mut b2: InternalId,
354 immediate_dominators: &[InternalId],
355 ) -> InternalId {
356 while b1 != b2 {
357 while b1 < b2 {
358 b1 = immediate_dominators[b1];
359 }
360 while b2 < b1 {
361 b2 = immediate_dominators[b2];
362 }
363 }
364 b1
365 }
366
367 fn find_lowest_common_ancestor(
369 targets: &[InternalId],
370 immediate_dominators: &[InternalId],
371 ) -> InternalId {
372 targets
373 .iter()
374 .copied()
375 .reduce(|a, b| Self::intersect(a, b, immediate_dominators))
376 .expect("targets must not be empty")
377 }
378}
379
380#[derive(Debug, Error, PartialEq)]
383pub enum FindDominatorValueError<E> {
384 #[error(transparent)]
386 ValueFnError(E),
387 #[error(transparent)]
389 DominatorFinderError(#[from] DominatorFinderError),
390}
391
392struct ValueCache<N, V, VF> {
396 value_fn: VF,
398 node_values: HashMap<N, Rc<V>>,
400 value_to_nodes: HashMap<Rc<V>, Vec<N>>,
402}
403
404impl<N, V, VF, E> ValueCache<N, V, VF>
405where
406 N: Hash + Eq + Clone,
407 V: Hash + Eq,
408 VF: AsyncFn(&N) -> Result<V, E>,
409{
410 fn new(value_fn: VF) -> Self {
412 Self {
413 value_fn,
414 node_values: HashMap::new(),
415 value_to_nodes: HashMap::new(),
416 }
417 }
418
419 fn get_values(&self) -> Vec<Rc<V>> {
421 self.value_to_nodes.keys().cloned().collect_vec()
422 }
423
424 fn num_distinct_values(&self) -> usize {
426 self.value_to_nodes.len()
427 }
428
429 async fn get_or_compute_value(&mut self, node: &N) -> Result<Rc<V>, E> {
432 self.compute_values([node]).await?;
433 Ok(self.node_values.get(node).expect("cached").clone())
434 }
435
436 async fn compute_values<'a, NI>(&mut self, nodes: NI) -> Result<(), E>
439 where
440 N: 'a,
441 NI: IntoIterator<Item = &'a N>,
442 {
443 let futures = nodes
445 .into_iter()
446 .filter(|node| !self.node_values.contains_key(node))
447 .map(|node| async {
448 let value = (self.value_fn)(node).await?;
449 Ok((node.clone(), Rc::new(value)))
450 });
451 let new_results: Vec<(N, Rc<V>)> = try_join_all(futures).await?;
453 for (node, value) in new_results {
455 self.node_values.insert(node.clone(), value.clone());
456 self.value_to_nodes.entry(value).or_default().push(node);
457 }
458 Ok(())
459 }
460}
461
462impl<N> FlowGraph<N>
463where
464 N: Clone + Eq + Hash,
465{
466 pub fn new(graph: SimpleDirectedGraph<N>, start_node: N) -> Self {
468 Self { graph, start_node }
469 }
470
471 pub fn create_value_flow_graph<'a, V>(&self, node_values: &'a HashMap<N, V>) -> FlowGraph<&'a V>
481 where
482 V: Eq + Hash,
483 {
484 let mut edges = vec![];
485 let start_value = node_values.get(&self.start_node).expect("cached");
486 for (parent, children) in &self.graph.adj {
487 let parent_value = node_values.get(parent).expect("cached");
488 for child in children {
489 let child_value = node_values.get(child).expect("cached");
490 edges.push((parent_value, child_value));
491 }
492 }
493 FlowGraph::new(SimpleDirectedGraph::new(edges), start_value)
494 }
495
496 pub async fn find_dominator_value<V, VF, E>(
501 &self,
502 final_nodes: &[N],
503 value_fn: VF,
504 ) -> Result<V, FindDominatorValueError<E>>
505 where
506 V: Hash + Eq + Clone,
507 VF: AsyncFn(&N) -> Result<V, E>,
508 {
509 let mut value_cache = ValueCache::new(value_fn);
510 value_cache
512 .compute_values(final_nodes)
513 .await
514 .map_err(|e| FindDominatorValueError::ValueFnError(e))?;
515
516 let final_values = value_cache.get_values();
517 match &*final_values {
518 [] => {
519 return Err(FindDominatorValueError::DominatorFinderError(
520 DominatorFinderError::EmptyTargetSet,
521 ));
522 }
523 [final_value] => {
524 return Ok(final_value.as_ref().clone());
527 }
528 _ => {}
529 }
530
531 let start_value = value_cache
532 .get_or_compute_value(&self.start_node)
533 .await
534 .map_err(|err| FindDominatorValueError::ValueFnError(err))?;
535
536 if value_cache.num_distinct_values() == final_values.len() {
537 return Ok(start_value.as_ref().clone());
542 }
543
544 value_cache
546 .compute_values(self.graph.nodes())
547 .await
548 .map_err(|err| FindDominatorValueError::ValueFnError(err))?;
549
550 let value_flow_graph = self.create_value_flow_graph(&value_cache.node_values);
566 let dominator_finder = DominatorFinder::calculate(&value_flow_graph)?;
567 let dominator_value =
568 dominator_finder.find_closest_common_dominator(final_values.iter())?;
569
570 Ok(dominator_value.as_ref().clone())
571 }
572}
573
574fn post_order<T, NI>(
576 start_node: T,
577 mut neighbors_fn: impl FnMut(&T) -> NI,
578) -> impl Iterator<Item = T>
579where
580 T: Clone + Hash + Eq,
581 NI: DoubleEndedIterator<Item = T>,
582{
583 let mut stack = vec![(start_node, false)];
584 let mut visited: HashSet<T> = HashSet::new();
585 iter::from_fn(move || {
586 while let Some((node, processed)) = stack.pop() {
587 if processed {
588 return Some(node);
591 }
592 if !visited.insert(node.clone()) {
594 continue;
596 }
597 let neighbors = neighbors_fn(&node);
598 stack.push((node, true));
601 for neighbor in neighbors.rev() {
605 if !visited.contains(&neighbor) {
606 stack.push((neighbor, false));
607 }
608 }
609 }
610 None
611 })
612}
613
614#[cfg(test)]
615mod tests {
616 use maplit::hashmap;
617 use pollster::FutureExt as _;
618
619 use super::*;
620
621 #[test]
622 fn test_closest_common_dominator_split() -> Result<(), DominatorFinderError> {
623 let flow_graph = FlowGraph::new(
627 SimpleDirectedGraph::new([("A", "B"), ("A", "C"), ("B", "D"), ("C", "D")]),
628 "A",
629 );
630 let df = DominatorFinder::calculate(&flow_graph)?;
631 assert_eq!(df.find_closest_common_dominator(["A"])?, "A");
632 assert_eq!(df.find_closest_common_dominator(["B"])?, "B");
633 assert_eq!(df.find_closest_common_dominator(["C"])?, "C");
634 assert_eq!(df.find_closest_common_dominator(["D"])?, "D");
635 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "A");
636 assert_eq!(df.find_closest_common_dominator(["B", "D"])?, "A");
637 assert_eq!(df.find_closest_common_dominator(["B", "C", "D"])?, "A");
638 Ok(())
639 }
640
641 #[test]
642 fn test_closest_common_dominator_linear_chain() -> Result<(), DominatorFinderError> {
643 let flow_graph = FlowGraph::new(
645 SimpleDirectedGraph::new([("A", "B"), ("B", "C"), ("C", "D")]),
646 "A",
647 );
648 let df = DominatorFinder::calculate(&flow_graph)?;
649 assert_eq!(df.find_closest_common_dominator(["A"])?, "A");
650 assert_eq!(df.find_closest_common_dominator(["B"])?, "B");
651 assert_eq!(df.find_closest_common_dominator(["C"])?, "C");
652 assert_eq!(df.find_closest_common_dominator(["D"])?, "D");
653 assert_eq!(df.find_closest_common_dominator(["A", "B"])?, "A");
654 assert_eq!(df.find_closest_common_dominator(["A", "C"])?, "A");
655 assert_eq!(df.find_closest_common_dominator(["A", "D"])?, "A");
656 assert_eq!(df.find_closest_common_dominator(["B", "D"])?, "B");
657 assert_eq!(df.find_closest_common_dominator(["C", "D"])?, "C");
658 assert_eq!(df.find_closest_common_dominator(["A", "B", "C", "D"])?, "A");
659 Ok(())
660 }
661
662 #[test]
663 fn test_closest_common_dominator_classic_diamond() -> Result<(), DominatorFinderError> {
664 let flow_graph = FlowGraph::new(
668 SimpleDirectedGraph::new([("A", "B"), ("A", "C"), ("B", "D"), ("C", "D"), ("D", "E")]),
669 "A",
670 );
671 let df = DominatorFinder::calculate(&flow_graph)?;
672 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "A");
673 assert_eq!(df.find_closest_common_dominator(["B", "E"])?, "A");
674 assert_eq!(df.find_closest_common_dominator(["D"])?, "D");
675 assert_eq!(df.find_closest_common_dominator(["D", "E"])?, "D");
676 assert_eq!(df.find_closest_common_dominator(["A", "D"])?, "A");
677 Ok(())
678 }
679
680 #[test]
681 fn test_closest_common_dominator_single_node() -> Result<(), DominatorFinderError> {
682 let flow_graph = FlowGraph::new(SimpleDirectedGraph::new([("A", "A")]), "A");
684 let df = DominatorFinder::calculate(&flow_graph)?;
685 assert_eq!(df.find_closest_common_dominator(["A"])?, "A");
686 Ok(())
687 }
688
689 #[test]
690 fn test_invalid_flowgraph() {
691 let flow_graph = FlowGraph::new(
698 SimpleDirectedGraph::new([("A", "B"), ("B", "E"), ("B", "F"), ("C", "D"), ("D", "F")]),
699 "A",
700 );
701 assert_eq!(
702 DominatorFinder::calculate(&flow_graph).err(),
703 Some(DominatorFinderError::UnreachableNodesInFlowGraph)
704 );
705 }
706
707 #[test]
708 fn test_closest_common_dominator_simple_cycle_with_entry() -> Result<(), DominatorFinderError> {
709 let flow_graph = FlowGraph::new(
715 SimpleDirectedGraph::new([("A", "B"), ("B", "C"), ("C", "D"), ("D", "B")]),
716 "A",
717 );
718 let df = DominatorFinder::calculate(&flow_graph)?;
719 assert_eq!(df.find_closest_common_dominator(["A", "B"])?, "A");
720 assert_eq!(df.find_closest_common_dominator(["A", "C"])?, "A");
721 assert_eq!(df.find_closest_common_dominator(["A", "B", "C"])?, "A");
722 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "B");
723 assert_eq!(df.find_closest_common_dominator(["B", "C", "D"])?, "B");
724 assert_eq!(df.find_closest_common_dominator(["A"])?, "A");
725 assert_eq!(df.find_closest_common_dominator(["B"])?, "B");
726 assert_eq!(df.find_closest_common_dominator(["C"])?, "C");
727 assert_eq!(df.find_closest_common_dominator(["D"])?, "D");
728 Ok(())
729 }
730
731 #[test]
732 fn test_closest_common_dominator_figure_eight_with_bridge() -> Result<(), DominatorFinderError>
733 {
734 let flow_graph = FlowGraph::new(
740 SimpleDirectedGraph::new([
741 ("A", "B"), ("B", "C"),
743 ("C", "D"),
744 ("D", "B"), ("D", "E"), ("E", "F"),
747 ("F", "G"),
748 ("G", "E"), ]),
750 "A",
751 );
752 let df = DominatorFinder::calculate(&flow_graph)?;
753 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "B");
754 assert_eq!(df.find_closest_common_dominator(["B", "D"])?, "B");
755 assert_eq!(df.find_closest_common_dominator(["B", "E"])?, "B");
756 assert_eq!(df.find_closest_common_dominator(["C", "E"])?, "C");
757 assert_eq!(df.find_closest_common_dominator(["C", "F"])?, "C");
758 assert_eq!(df.find_closest_common_dominator(["D", "E"])?, "D");
759 assert_eq!(df.find_closest_common_dominator(["D", "F"])?, "D");
760 assert_eq!(df.find_closest_common_dominator(["E", "G"])?, "E");
761 assert_eq!(df.find_closest_common_dominator(["F", "G"])?, "F");
762 Ok(())
763 }
764
765 #[test]
766 fn test_closest_common_dominator_figure_eight() -> Result<(), DominatorFinderError> {
767 let flow_graph = FlowGraph::new(
773 SimpleDirectedGraph::new([
774 ("A", "B"), ("B", "C"),
776 ("C", "D"),
777 ("D", "B"), ("D", "E"),
779 ("E", "F"),
780 ("F", "D"), ]),
782 "A",
783 );
784 let df = DominatorFinder::calculate(&flow_graph)?;
785 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "B");
786 assert_eq!(df.find_closest_common_dominator(["B", "D"])?, "B");
787 assert_eq!(df.find_closest_common_dominator(["B", "E"])?, "B");
788 assert_eq!(df.find_closest_common_dominator(["C", "D"])?, "C");
789 assert_eq!(df.find_closest_common_dominator(["C", "E"])?, "C");
790 assert_eq!(df.find_closest_common_dominator(["C", "F"])?, "C");
791 assert_eq!(df.find_closest_common_dominator(["D", "E"])?, "D");
792 assert_eq!(df.find_closest_common_dominator(["D", "F"])?, "D");
793 assert_eq!(df.find_closest_common_dominator(["E", "F"])?, "E");
794 Ok(())
795 }
796
797 #[test]
798 fn test_closest_common_dominator_entry_cycle_dominance() -> Result<(), DominatorFinderError> {
799 let flow_graph = FlowGraph::new(
803 SimpleDirectedGraph::new([("A", "B"), ("B", "C"), ("C", "B")]),
804 "A",
805 );
806 let df = DominatorFinder::calculate(&flow_graph)?;
807 assert_eq!(df.find_closest_common_dominator(["A", "B"])?, "A");
808 assert_eq!(df.find_closest_common_dominator(["A", "C"])?, "A");
809 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "B");
810 assert_eq!(df.find_closest_common_dominator(["A", "B", "C"])?, "A");
811 Ok(())
812 }
813
814 #[test]
815 fn test_closest_common_dominator_nested_loops() -> Result<(), DominatorFinderError> {
816 let flow_graph = FlowGraph::new(
824 SimpleDirectedGraph::new([
825 ("A", "B"),
826 ("B", "C"),
827 ("C", "D"),
828 ("C", "E"),
829 ("E", "C"),
830 ("D", "B"),
831 ]),
832 "A",
833 );
834 let df = DominatorFinder::calculate(&flow_graph)?;
835 assert_eq!(df.find_closest_common_dominator(["A", "B"])?, "A");
836 assert_eq!(df.find_closest_common_dominator(["A", "C"])?, "A");
837 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "B");
838 assert_eq!(df.find_closest_common_dominator(["B", "D"])?, "B");
839 assert_eq!(df.find_closest_common_dominator(["B", "E"])?, "B");
840 assert_eq!(df.find_closest_common_dominator(["C", "D"])?, "C");
841 assert_eq!(df.find_closest_common_dominator(["C", "E"])?, "C");
842 assert_eq!(df.find_closest_common_dominator(["D", "E"])?, "C");
843 assert_eq!(df.find_closest_common_dominator(["B", "C", "D"])?, "B");
844 assert_eq!(df.find_closest_common_dominator(["B", "C", "E"])?, "B");
845 assert_eq!(df.find_closest_common_dominator(["B", "D", "E"])?, "B");
846 assert_eq!(df.find_closest_common_dominator(["C", "D", "E"])?, "C");
847 assert_eq!(df.find_closest_common_dominator(["B", "C", "D", "E"])?, "B");
848 Ok(())
849 }
850
851 #[test]
852 fn test_irreducible_graph_cooper_harvey_kennedy_fig2() -> Result<(), DominatorFinderError> {
853 let graph = SimpleDirectedGraph::new([(1, 2), (2, 1), (3, 2), (4, 1), (5, 4), (5, 3)]);
862 let flow_graph = FlowGraph::new(graph, 5);
863 let df = DominatorFinder::calculate(&flow_graph)?;
864 assert_eq!(
865 df.get_immediate_dominators(),
866 HashMap::from([(1, 5), (2, 5), (3, 5), (4, 5), (5, 5),])
867 );
868 Ok(())
869 }
870
871 #[test]
872 fn test_irreducible_graph_cooper_harvey_kennedy_fig3() -> Result<(), DominatorFinderError> {
873 let graph = SimpleDirectedGraph::new([
882 (1, 2),
883 (2, 1),
884 (2, 3),
885 (3, 2),
886 (5, 1),
887 (4, 2),
888 (4, 3),
889 (6, 5),
890 (6, 4),
891 ]);
892 let flow_graph = FlowGraph::new(graph, 6);
893 let df = DominatorFinder::calculate(&flow_graph)?;
894 assert_eq!(
895 df.get_immediate_dominators(),
896 HashMap::from([(1, 6), (2, 6), (3, 6), (4, 6), (5, 6), (6, 6),])
897 );
898 assert_eq!(df.find_closest_common_dominator([2, 3])?, 6);
899 Ok(())
900 }
901
902 #[test]
903 fn test_dominator_tree_with_three_levels() -> Result<(), DominatorFinderError> {
904 let graph =
919 SimpleDirectedGraph::new([(1, 2), (2, 3), (2, 4), (2, 6), (3, 5), (4, 5), (5, 2)]);
920 let flow_graph = FlowGraph::new(graph, 1);
921 let df = DominatorFinder::calculate(&flow_graph)?;
922 assert_eq!(
923 df.get_immediate_dominators(),
924 HashMap::from([(1, 1), (2, 1), (3, 2), (4, 2), (5, 2), (6, 2),])
925 );
926 assert_eq!(df.find_closest_common_dominator([1, 6])?, 1);
927 assert_eq!(df.find_closest_common_dominator([2, 3])?, 2);
928 assert_eq!(df.find_closest_common_dominator([2, 4])?, 2);
929 assert_eq!(df.find_closest_common_dominator([2, 5])?, 2);
930 assert_eq!(df.find_closest_common_dominator([2, 6])?, 2);
931 assert_eq!(df.find_closest_common_dominator([3, 4])?, 2);
932 assert_eq!(df.find_closest_common_dominator([3, 5])?, 2);
933 assert_eq!(df.find_closest_common_dominator([3, 6])?, 2);
934 assert_eq!(df.find_closest_common_dominator([4, 5])?, 2);
935 assert_eq!(df.find_closest_common_dominator([4, 6])?, 2);
936 assert_eq!(df.find_closest_common_dominator([5, 6])?, 2);
937 assert_eq!(df.find_closest_common_dominator([2, 3, 5])?, 2);
938 assert_eq!(df.find_closest_common_dominator([3, 4, 5])?, 2);
939 assert_eq!(df.find_closest_common_dominator([3, 4, 5, 6])?, 2);
940 Ok(())
941 }
942
943 #[test]
944 fn test_big_graph_fig_18_3() -> Result<(), DominatorFinderError> {
945 let graph = SimpleDirectedGraph::new([
971 (1, 2),
972 (2, 3),
973 (2, 4),
974 (3, 2),
975 (4, 2),
976 (4, 5),
977 (4, 6),
978 (5, 7),
979 (5, 8),
980 (6, 7),
981 (7, 11),
982 (8, 9),
983 (9, 8),
984 (9, 10),
985 (10, 5),
986 (10, 12),
987 (11, 12),
988 ]);
989 let flow_graph = FlowGraph::new(graph, 1);
990 let df = DominatorFinder::calculate(&flow_graph)?;
991 assert_eq!(
992 df.get_immediate_dominators(),
993 HashMap::from([
994 (1, 1),
995 (2, 1),
996 (3, 2),
997 (4, 2),
998 (5, 4),
999 (6, 4),
1000 (7, 4),
1001 (8, 5),
1002 (9, 8),
1003 (10, 9),
1004 (11, 7),
1005 (12, 4)
1006 ])
1007 );
1008 assert_eq!(df.find_closest_common_dominator([6, 3])?, 2);
1009 assert_eq!(df.find_closest_common_dominator([11, 9, 12])?, 4);
1010 assert_eq!(df.find_closest_common_dominator([11, 9, 5])?, 4);
1011 assert_eq!(df.find_closest_common_dominator([11, 10])?, 4);
1012 assert_eq!(df.find_closest_common_dominator([10, 11, 12, 3, 6])?, 2);
1013 Ok(())
1014 }
1015
1016 #[test]
1017 fn test_big_graph_fig_19_8() -> Result<(), DominatorFinderError> {
1018 let graph = SimpleDirectedGraph::new([
1045 ("A", "B"),
1046 ("A", "C"),
1047 ("B", "D"),
1048 ("B", "G"),
1049 ("C", "E"),
1050 ("C", "H"),
1051 ("D", "F"),
1052 ("D", "G"),
1053 ("E", "C"),
1054 ("E", "H"),
1055 ("F", "I"),
1056 ("F", "K"),
1057 ("G", "J"),
1058 ("H", "M"),
1059 ("I", "L"),
1060 ("J", "I"),
1061 ("K", "L"),
1062 ("L", "B"),
1063 ("L", "M"),
1064 ]);
1065 let flow_graph = FlowGraph::new(graph, "A");
1066 let df = DominatorFinder::calculate(&flow_graph)?;
1067 assert_eq!(
1068 df.get_immediate_dominators(),
1069 HashMap::from([
1070 ("A", "A"),
1071 ("B", "A"),
1072 ("C", "A"),
1073 ("D", "B"),
1074 ("E", "C"),
1075 ("F", "D"),
1076 ("G", "B"),
1077 ("H", "C"),
1078 ("I", "B"),
1079 ("J", "G"),
1080 ("K", "F"),
1081 ("L", "B"),
1082 ("M", "A"),
1083 ])
1084 );
1085 assert_eq!(df.find_closest_common_dominator(["K", "L"])?, "B");
1086 assert_eq!(df.find_closest_common_dominator(["K", "C"])?, "A");
1087 assert_eq!(df.find_closest_common_dominator(["B", "G", "J"])?, "B");
1088 Ok(())
1089 }
1090
1091 #[test]
1092 fn test_closest_common_dominator_tree() -> Result<(), DominatorFinderError> {
1093 let flow_graph = FlowGraph::new(
1097 SimpleDirectedGraph::new([("A", "B"), ("B", "C"), ("B", "D"), ("A", "E")]),
1098 "A",
1099 );
1100 let df = DominatorFinder::calculate(&flow_graph)?;
1101 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "B");
1102 assert_eq!(df.find_closest_common_dominator(["B", "E"])?, "A");
1103 assert_eq!(df.find_closest_common_dominator(["C", "D"])?, "B");
1104 assert_eq!(df.find_closest_common_dominator(["C", "E"])?, "A");
1105 assert_eq!(df.find_closest_common_dominator(["B", "C", "D"])?, "B");
1106 assert_eq!(df.find_closest_common_dominator(["C", "D", "E"])?, "A");
1107 Ok(())
1108 }
1109
1110 #[test]
1111 fn test_closest_common_dominator_bypassing_path() -> Result<(), DominatorFinderError> {
1112 let flow_graph = FlowGraph::new(
1117 SimpleDirectedGraph::new([("A", "B"), ("B", "C"), ("C", "D"), ("A", "E"), ("E", "D")]),
1118 "A",
1119 );
1120 let df = DominatorFinder::calculate(&flow_graph)?;
1121 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "B");
1122 assert_eq!(df.find_closest_common_dominator(["B", "D"])?, "A");
1123 assert_eq!(df.find_closest_common_dominator(["B", "E"])?, "A");
1124 assert_eq!(df.find_closest_common_dominator(["C", "D"])?, "A");
1125 assert_eq!(df.find_closest_common_dominator(["C", "E"])?, "A");
1126 assert_eq!(df.find_closest_common_dominator(["D", "E"])?, "A");
1127 assert_eq!(df.find_closest_common_dominator(["B", "C", "D"])?, "A");
1128 assert_eq!(df.find_closest_common_dominator(["C", "D", "E"])?, "A");
1129 Ok(())
1130 }
1131
1132 #[test]
1133 fn test_closest_common_dominator_self_loop_handling() -> Result<(), DominatorFinderError> {
1134 let flow_graph = FlowGraph::new(SimpleDirectedGraph::new([("A", "A"), ("A", "B")]), "A");
1136 let df = DominatorFinder::calculate(&flow_graph)?;
1137 assert_eq!(df.find_closest_common_dominator(["A"])?, "A");
1138 Ok(())
1139 }
1140
1141 #[test]
1142 fn test_closest_common_dominator_multi_edge() -> Result<(), DominatorFinderError> {
1143 let flow_graph = FlowGraph::new(
1145 SimpleDirectedGraph::new([
1146 ("A", "B"),
1147 ("A", "B"), ("B", "C"),
1149 ]),
1150 "A",
1151 );
1152 let df = DominatorFinder::calculate(&flow_graph)?;
1153 assert_eq!(df.find_closest_common_dominator(["A"])?, "A");
1154 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "B");
1155 Ok(())
1156 }
1157
1158 #[test]
1159 fn test_closest_common_dominator_invalid_target_set() -> Result<(), DominatorFinderError> {
1160 let flow_graph = FlowGraph::new(SimpleDirectedGraph::new([("A", "B")]), "A");
1162 let df = DominatorFinder::calculate(&flow_graph)?;
1163 assert_eq!(
1164 df.find_closest_common_dominator([]),
1165 Err(DominatorFinderError::EmptyTargetSet)
1166 );
1167 Ok(())
1168 }
1169
1170 #[test]
1171 fn test_closest_common_dominator_repeated_node() -> Result<(), DominatorFinderError> {
1172 let flow_graph = FlowGraph::new(SimpleDirectedGraph::new([("A", "B")]), "A");
1174 let df = DominatorFinder::calculate(&flow_graph)?;
1175 assert_eq!(df.find_closest_common_dominator(["A", "B", "A", "B"])?, "A");
1176 Ok(())
1177 }
1178
1179 #[test]
1180 fn test_simple_directed_graph_nodes() {
1181 let graph = SimpleDirectedGraph::new([("A", "B"), ("B", "C")]);
1182 let nodes = graph.nodes().copied().collect_vec();
1183 assert_eq!(nodes, ["A", "B", "C"]);
1184
1185 let graph = SimpleDirectedGraph::<String>::new([]);
1186 let nodes = graph.nodes().cloned().collect_vec();
1187 assert!(nodes.is_empty());
1188 }
1189
1190 #[test]
1191 fn test_simple_directed_graph_edges() {
1192 let graph = SimpleDirectedGraph::new([("A", "B"), ("B", "C"), ("A", "C")]);
1193 let edges = graph.edges().map(|(&u, &v)| (u, v)).collect_vec();
1194 assert_eq!(edges, [("A", "B"), ("A", "C"), ("B", "C")]);
1195
1196 let graph = SimpleDirectedGraph::<String>::new([]);
1197 let edges = graph.edges().collect_vec();
1198 assert!(edges.is_empty());
1199 }
1200
1201 #[test]
1202 fn test_simple_directed_graph_adjacent_nodes() {
1203 let graph = SimpleDirectedGraph::new([("A", "B"), ("A", "C"), ("B", "D")]);
1204 assert_eq!(
1205 graph.adjacent_nodes(&"A").unwrap().copied().collect_vec(),
1206 ["B", "C"]
1207 );
1208 assert_eq!(
1209 graph.adjacent_nodes(&"B").unwrap().copied().collect_vec(),
1210 ["D"]
1211 );
1212 assert!(graph.adjacent_nodes(&"C").unwrap().next().is_none());
1213 assert!(graph.adjacent_nodes(&"Z").is_none());
1214 }
1215
1216 #[test]
1217 fn test_simple_directed_graph_contains_node() {
1218 let graph = SimpleDirectedGraph::new([("A", "B"), ("B", "C")]);
1219 assert!(graph.contains_node(&"A"));
1220 assert!(graph.contains_node(&"B"));
1221 assert!(graph.contains_node(&"C"));
1222 assert!(!graph.contains_node(&"D"));
1223 }
1224
1225 #[test]
1226 fn test_simple_directed_graph_new() {
1227 let graph = SimpleDirectedGraph::new([("A", "B"), ("A", "C"), ("B", "C"), ("A", "B")]);
1228 let nodes = graph.nodes().copied().collect_vec();
1229 assert_eq!(nodes, ["A", "B", "C"]);
1230 let edges = graph.edges().map(|(&u, &v)| (u, v)).collect_vec();
1231 assert_eq!(edges, [("A", "B"), ("A", "C"), ("B", "C")]);
1232
1233 let graph = SimpleDirectedGraph::new([("B", "C"), ("A", "B")]);
1234 let nodes = graph.nodes().copied().collect_vec();
1235 assert_eq!(nodes, ["B", "C", "A"]);
1236 let edges = graph.edges().map(|(&u, &v)| (u, v)).collect_vec();
1237 assert_eq!(edges, [("B", "C"), ("A", "B")]);
1238 }
1239
1240 #[test]
1241 fn test_flow_graph_new() {
1242 let graph = SimpleDirectedGraph::new([("A", "B")]);
1243 let flow_graph = FlowGraph::new(graph.clone(), "A");
1244 assert_eq!(flow_graph.graph, graph);
1245 assert_eq!(flow_graph.start_node, "A");
1246 let flow_graph = FlowGraph::new(graph.clone(), "C");
1247 assert_eq!(flow_graph.graph, graph);
1248 assert_eq!(flow_graph.start_node, "C");
1249 }
1250
1251 #[test]
1252 fn test_post_order() {
1253 let neighbors = hashmap! {
1264 'A' => vec![],
1265 'B' => vec!['A'],
1266 'C' => vec!['B'],
1267 'D' => vec!['C'],
1268 'E' => vec!['A'],
1269 'F' => vec!['E', 'D'],
1270 };
1271 let neighbors_fn = |node: &char| neighbors[node].iter().copied();
1272 assert_eq!(
1273 post_order('F', neighbors_fn).collect_vec(),
1274 ['A', 'E', 'B', 'C', 'D', 'F']
1275 );
1276 assert_eq!(post_order('E', neighbors_fn).collect_vec(), ['A', 'E']);
1277 assert_eq!(
1278 post_order('D', neighbors_fn).collect_vec(),
1279 ['A', 'B', 'C', 'D']
1280 );
1281 assert_eq!(post_order('A', neighbors_fn).collect_vec(), ['A']);
1282
1283 let neighbors = hashmap! {
1298 'A' => vec![],
1299 'B' => vec!['A'],
1300 'C' => vec!['A'],
1301 'D' => vec!['B'],
1302 'E' => vec!['C'],
1303 'F' => vec!['C'],
1304 'G' => vec!['E'],
1305 'H' => vec!['F', 'G'],
1306 'I' => vec!['D', 'H'],
1307 };
1308 let neighbors_fn = |node: &char| neighbors[node].iter().copied();
1309 assert_eq!(
1310 post_order('I', neighbors_fn).collect_vec(),
1311 ['A', 'B', 'D', 'C', 'F', 'E', 'G', 'H', 'I']
1312 );
1313
1314 let neighbors = hashmap! {
1331 'A' => vec![],
1332 'b' => vec!['A'],
1333 'C' => vec!['A'],
1334 'D' => vec!['b'],
1335 'e' => vec!['C', 'b'],
1336 'f' => vec!['D'],
1337 'G' => vec!['e', 'D'],
1338 'h' => vec!['G', 'f'],
1339 'I' => vec!['C', 'e', 'G', 'h'],
1340 };
1341 let neighbors_fn = |node: &char| neighbors[node].iter().copied();
1342 assert_eq!(
1343 post_order('I', neighbors_fn).collect_vec(),
1344 ['A', 'C', 'b', 'e', 'D', 'G', 'f', 'h', 'I']
1345 );
1346
1347 let neighbors = hashmap! {
1359 'A' => vec![],
1360 'B' => vec!['A'],
1361 'C' => vec!['B'],
1362 'D' => vec!['C'],
1363 'E' => vec!['C'],
1364 'F' => vec!['D'],
1365 'G' => vec!['E', 'F'],
1366 };
1367 let neighbors_fn = |node: &char| neighbors[node].iter().copied();
1368 assert_eq!(
1369 post_order('G', neighbors_fn).collect_vec(),
1370 ['A', 'B', 'C', 'E', 'D', 'F', 'G']
1371 );
1372
1373 let neighbors = hashmap! {
1385 'A' => vec![],
1386 'B' => vec!['A'],
1387 'c' => vec!['B'],
1388 'D' => vec!['c'],
1389 'E' => vec!['c'],
1390 'F' => vec!['E'],
1391 'G' => vec!['F', 'D'],
1392 };
1393 let neighbors_fn = |node: &char| neighbors[node].iter().copied();
1394 assert_eq!(
1395 post_order('G', neighbors_fn).collect_vec(),
1396 ['A', 'B', 'c', 'E', 'F', 'D', 'G']
1397 );
1398
1399 let neighbors = hashmap! {
1412 'A' => vec![],
1413 'B' => vec!['A'],
1414 'C' => vec!['B'],
1415 'D' => vec!['A'],
1416 'E' => vec!['A'],
1417 'F' => vec!['E', 'D'],
1418 };
1419 let neighbors_fn = |node: &char| neighbors[node].iter().copied();
1420 assert_eq!(
1421 post_order('F', neighbors_fn).collect_vec(),
1422 ['A', 'E', 'D', 'F']
1423 );
1424 assert_eq!(post_order('C', neighbors_fn).collect_vec(), ['A', 'B', 'C']);
1425
1426 let neighbors = hashmap! {
1434 'A' => vec![],
1435 'B' => vec!['A'],
1436 'C' => vec![],
1437 'D' => vec!['C', 'B'],
1438 };
1439 let neighbors_fn = |node: &char| neighbors[node].iter().copied();
1440 assert_eq!(
1441 post_order('D', neighbors_fn).collect_vec(),
1442 ['C', 'A', 'B', 'D']
1443 );
1444
1445 let neighbors = hashmap! {
1451 'A' => vec!['C'],
1452 'B' => vec!['A'],
1453 'C' => vec!['B'],
1454 };
1455 let neighbors_fn = |node: &char| neighbors[node].iter().copied();
1456 assert_eq!(post_order('C', neighbors_fn).collect_vec(), ['A', 'B', 'C']);
1457 assert_eq!(post_order('B', neighbors_fn).collect_vec(), ['C', 'A', 'B']);
1458 assert_eq!(post_order('A', neighbors_fn).collect_vec(), ['B', 'C', 'A']);
1459 }
1460
1461 #[test]
1462 fn test_value_flow_graph_new() {
1463 let simple_graph = SimpleDirectedGraph::new([("A", "B"), ("B", "C")]);
1465 let flow_graph = FlowGraph::new(simple_graph, "A");
1466 let node_values = HashMap::from([("A", 1), ("B", 1), ("C", 2)]);
1467 let value_flow_graph = flow_graph.create_value_flow_graph(&node_values);
1468
1469 let expected_value_edges = [(&1, &1), (&1, &2)];
1470 let expected_flow_graph =
1471 FlowGraph::new(SimpleDirectedGraph::new(expected_value_edges), &1);
1472 assert_eq!(value_flow_graph, expected_flow_graph);
1473 }
1474
1475 #[test]
1476 fn test_value_flow_graph_find_dominator_value() {
1477 let simple_graph =
1480 SimpleDirectedGraph::new([("A", "B"), ("B", "C"), ("C", "D"), ("B", "E")]);
1481 let flow_graph = FlowGraph::new(simple_graph, "A");
1482 let value_fn = async |node: &&str| match *node {
1483 "A" | "B" => Ok(1),
1484 "C" => Ok(2),
1485 "D" | "E" => Ok(3),
1486 _ => Err("Unknown node".to_string()),
1487 };
1488
1489 assert_eq!(
1494 flow_graph
1495 .find_dominator_value(&["D", "E"], value_fn)
1496 .block_on(),
1497 Ok(3)
1498 );
1499 assert_eq!(
1500 flow_graph
1501 .find_dominator_value(&["C", "D"], value_fn)
1502 .block_on(),
1503 Ok(1)
1504 );
1505 assert_eq!(
1506 flow_graph
1507 .find_dominator_value(&["B", "C"], value_fn)
1508 .block_on(),
1509 Ok(1)
1510 );
1511 }
1512
1513 #[test]
1514 fn test_find_dominator_value_with_distinct_values() {
1515 let simple_graph =
1518 SimpleDirectedGraph::new([("A", "B"), ("B", "C"), ("C", "D"), ("B", "E")]);
1519 let flow_graph = FlowGraph::new(simple_graph, "A");
1520 let value_fn = async |node: &&str| match *node {
1521 "A" => Ok(1),
1522 "B" => Ok(2),
1523 "C" => Ok(3),
1524 "D" => Ok(4),
1525 "E" => Ok(5),
1526 _ => Err("Unknown node".to_string()),
1527 };
1528
1529 assert_eq!(
1533 flow_graph
1534 .find_dominator_value(&["D", "E"], value_fn)
1535 .block_on(),
1536 Ok(2)
1537 );
1538 assert_eq!(
1539 flow_graph
1540 .find_dominator_value(&["C", "D"], value_fn)
1541 .block_on(),
1542 Ok(3)
1543 );
1544 assert_eq!(
1545 flow_graph
1546 .find_dominator_value(&["B", "C"], value_fn)
1547 .block_on(),
1548 Ok(2)
1549 );
1550 }
1551
1552 #[test]
1553 fn test_find_dominator_value_with_invalid_flow_graph() {
1554 let simple_graph = SimpleDirectedGraph::new([("A", "B"), ("C", "D")]);
1557 let flow_graph = FlowGraph::new(simple_graph, "A");
1558 let value_fn = async |node: &&str| match *node {
1559 "A" | "B" => Ok(1),
1560 "C" | "D" => Ok(2),
1561 _ => Err("Unknown node".to_string()),
1562 };
1563 assert_eq!(
1570 flow_graph
1571 .find_dominator_value(&["B", "D"], value_fn)
1572 .block_on(),
1573 Ok(1)
1574 );
1575 }
1576
1577 #[test]
1578 fn test_find_dominator_value_with_unknown_node_in_target_set() {
1579 let simple_graph = SimpleDirectedGraph::new([("A", "B")]);
1581 let flow_graph = FlowGraph::new(simple_graph, "A");
1582 let value_fn = async |node: &&str| match *node {
1583 "A" => Ok(1),
1584 "B" => Ok(2),
1585 "X" => Ok(666),
1586 _ => Err("Unknown node".to_string()),
1587 };
1588 assert_eq!(
1589 flow_graph
1590 .find_dominator_value(&["B", "X"], value_fn)
1591 .block_on(),
1592 Err(FindDominatorValueError::DominatorFinderError(
1593 DominatorFinderError::UnknownNodeInTargetSet
1594 ))
1595 );
1596 }
1597
1598 #[test]
1599 fn test_find_dominator_value_with_unknown_node() {
1600 let simple_graph = SimpleDirectedGraph::new([("A", "B")]);
1602 let flow_graph = FlowGraph::new(simple_graph, "A");
1603 let value_fn = async |node: &&str| match *node {
1604 "A" => Ok(1),
1605 "B" => Ok(2),
1606 _ => Err("Unknown node".to_string()),
1607 };
1608 assert_eq!(
1609 flow_graph
1610 .find_dominator_value(&["B", "X"], value_fn)
1611 .block_on(),
1612 Err(FindDominatorValueError::ValueFnError(
1613 "Unknown node".to_string()
1614 ))
1615 );
1616 }
1617}