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
392pub struct 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 pub 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 pub async fn get_value(&mut self, node: &N) -> Result<Rc<V>, E> {
422 let values = self.get_values([node]).await?;
423 assert_eq!(values.len(), 1);
424 Ok(values[0].clone())
425 }
426
427 pub fn get_nodes_for_value(&self, value: &Rc<V>) -> Option<&Vec<N>> {
429 self.value_to_nodes.get(value)
430 }
431
432 async fn get_values<'a, NI>(&mut self, nodes: NI) -> Result<Vec<Rc<V>>, E>
439 where
440 N: 'a,
441 NI: IntoIterator<Item = &'a N>,
442 {
443 let mut values = vec![];
444 let mut futures = vec![];
445
446 for node in nodes {
448 match self.node_values.get(node) {
449 Some(value) => {
450 values.push(value.clone());
451 }
452 None => {
453 futures.push(async {
455 let value = (self.value_fn)(node).await?;
456 Ok((node.clone(), Rc::new(value)))
457 });
458 }
459 }
460 }
461 let new_results: Vec<(N, Rc<V>)> = try_join_all(futures).await?;
463 for (node, value) in new_results {
465 self.node_values.insert(node.clone(), value.clone());
466 self.value_to_nodes
467 .entry(value.clone())
468 .or_default()
469 .push(node);
470 values.push(value);
471 }
472 Ok(values)
473 }
474}
475
476impl<N> FlowGraph<N>
477where
478 N: Clone + Eq + Hash,
479{
480 pub fn new(graph: SimpleDirectedGraph<N>, start_node: N) -> Self {
482 Self { graph, start_node }
483 }
484
485 pub fn create_value_flow_graph<'a, V>(&self, node_values: &'a HashMap<N, V>) -> FlowGraph<&'a V>
495 where
496 V: Eq + Hash,
497 {
498 let mut edges = vec![];
499 let start_value = node_values.get(&self.start_node).expect("cached");
500 for (parent, children) in &self.graph.adj {
501 let parent_value = node_values.get(parent).expect("cached");
502 for child in children {
503 let child_value = node_values.get(child).expect("cached");
504 edges.push((parent_value, child_value));
505 }
506 }
507 FlowGraph::new(SimpleDirectedGraph::new(edges), start_value)
508 }
509
510 pub async fn find_dominator_value<'a, NI, V, VF, E>(
515 &'a self,
516 final_nodes: NI,
517 value_fn: VF,
518 ) -> Result<V, FindDominatorValueError<E>>
519 where
520 NI: IntoIterator<Item = &'a N>,
521 V: Hash + Eq + Clone,
522 VF: AsyncFn(&N) -> Result<V, E>,
523 {
524 let mut value_cache = ValueCache::new(value_fn);
525 let value_rc = self
526 .find_dominator_value_with_value_cache(final_nodes, &mut value_cache)
527 .await?;
528 Ok((*value_rc).clone())
529 }
530
531 pub async fn find_dominator_value_with_value_cache<'a, NI, V, VF, E>(
538 &'a self,
539 final_nodes: NI,
540 value_cache: &mut ValueCache<N, V, VF>,
541 ) -> Result<Rc<V>, FindDominatorValueError<E>>
542 where
543 NI: IntoIterator<Item = &'a N>,
544 V: Hash + Eq,
545 VF: AsyncFn(&N) -> Result<V, E>,
546 {
547 let final_values = value_cache
549 .get_values(final_nodes)
550 .await
551 .map_err(|e| FindDominatorValueError::ValueFnError(e))?;
552
553 match &*final_values {
554 [] => {
555 return Err(FindDominatorValueError::DominatorFinderError(
556 DominatorFinderError::EmptyTargetSet,
557 ));
558 }
559 [final_value] => {
560 return Ok(final_value.clone());
563 }
564 _ => {}
565 }
566
567 let start_value = value_cache
568 .get_value(&self.start_node)
569 .await
570 .map_err(|err| FindDominatorValueError::ValueFnError(err))?;
571 if final_values.contains(&start_value) {
572 return Ok(Rc::clone(&start_value));
573 }
574
575 value_cache
577 .get_values(self.graph.nodes())
578 .await
579 .map_err(|err| FindDominatorValueError::ValueFnError(err))?;
580
581 let value_flow_graph = self.create_value_flow_graph(&value_cache.node_values);
597 let dominator_finder = DominatorFinder::calculate(&value_flow_graph)?;
598 let dominator_value =
599 dominator_finder.find_closest_common_dominator(final_values.iter())?;
600
601 Ok(Rc::clone(dominator_value))
602 }
603}
604
605fn post_order<T, NI>(
607 start_node: T,
608 mut neighbors_fn: impl FnMut(&T) -> NI,
609) -> impl Iterator<Item = T>
610where
611 T: Clone + Hash + Eq,
612 NI: DoubleEndedIterator<Item = T>,
613{
614 let mut stack = vec![(start_node, false)];
615 let mut visited: HashSet<T> = HashSet::new();
616 iter::from_fn(move || {
617 while let Some((node, processed)) = stack.pop() {
618 if processed {
619 return Some(node);
622 }
623 if !visited.insert(node.clone()) {
625 continue;
627 }
628 let neighbors = neighbors_fn(&node);
629 stack.push((node, true));
632 for neighbor in neighbors.rev() {
636 if !visited.contains(&neighbor) {
637 stack.push((neighbor, false));
638 }
639 }
640 }
641 None
642 })
643}
644
645#[cfg(test)]
646mod tests {
647 use maplit::hashmap;
648 use pollster::FutureExt as _;
649
650 use super::*;
651
652 #[test]
653 fn test_closest_common_dominator_split() -> Result<(), DominatorFinderError> {
654 let flow_graph = FlowGraph::new(
658 SimpleDirectedGraph::new([("A", "B"), ("A", "C"), ("B", "D"), ("C", "D")]),
659 "A",
660 );
661 let df = DominatorFinder::calculate(&flow_graph)?;
662 assert_eq!(df.find_closest_common_dominator(["A"])?, "A");
663 assert_eq!(df.find_closest_common_dominator(["B"])?, "B");
664 assert_eq!(df.find_closest_common_dominator(["C"])?, "C");
665 assert_eq!(df.find_closest_common_dominator(["D"])?, "D");
666 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "A");
667 assert_eq!(df.find_closest_common_dominator(["B", "D"])?, "A");
668 assert_eq!(df.find_closest_common_dominator(["B", "C", "D"])?, "A");
669 Ok(())
670 }
671
672 #[test]
673 fn test_closest_common_dominator_linear_chain() -> Result<(), DominatorFinderError> {
674 let flow_graph = FlowGraph::new(
676 SimpleDirectedGraph::new([("A", "B"), ("B", "C"), ("C", "D")]),
677 "A",
678 );
679 let df = DominatorFinder::calculate(&flow_graph)?;
680 assert_eq!(df.find_closest_common_dominator(["A"])?, "A");
681 assert_eq!(df.find_closest_common_dominator(["B"])?, "B");
682 assert_eq!(df.find_closest_common_dominator(["C"])?, "C");
683 assert_eq!(df.find_closest_common_dominator(["D"])?, "D");
684 assert_eq!(df.find_closest_common_dominator(["A", "B"])?, "A");
685 assert_eq!(df.find_closest_common_dominator(["A", "C"])?, "A");
686 assert_eq!(df.find_closest_common_dominator(["A", "D"])?, "A");
687 assert_eq!(df.find_closest_common_dominator(["B", "D"])?, "B");
688 assert_eq!(df.find_closest_common_dominator(["C", "D"])?, "C");
689 assert_eq!(df.find_closest_common_dominator(["A", "B", "C", "D"])?, "A");
690 Ok(())
691 }
692
693 #[test]
694 fn test_closest_common_dominator_classic_diamond() -> Result<(), DominatorFinderError> {
695 let flow_graph = FlowGraph::new(
699 SimpleDirectedGraph::new([("A", "B"), ("A", "C"), ("B", "D"), ("C", "D"), ("D", "E")]),
700 "A",
701 );
702 let df = DominatorFinder::calculate(&flow_graph)?;
703 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "A");
704 assert_eq!(df.find_closest_common_dominator(["B", "E"])?, "A");
705 assert_eq!(df.find_closest_common_dominator(["D"])?, "D");
706 assert_eq!(df.find_closest_common_dominator(["D", "E"])?, "D");
707 assert_eq!(df.find_closest_common_dominator(["A", "D"])?, "A");
708 Ok(())
709 }
710
711 #[test]
712 fn test_closest_common_dominator_single_node() -> Result<(), DominatorFinderError> {
713 let flow_graph = FlowGraph::new(SimpleDirectedGraph::new([("A", "A")]), "A");
715 let df = DominatorFinder::calculate(&flow_graph)?;
716 assert_eq!(df.find_closest_common_dominator(["A"])?, "A");
717 Ok(())
718 }
719
720 #[test]
721 fn test_invalid_flowgraph() {
722 let flow_graph = FlowGraph::new(
729 SimpleDirectedGraph::new([("A", "B"), ("B", "E"), ("B", "F"), ("C", "D"), ("D", "F")]),
730 "A",
731 );
732 assert_eq!(
733 DominatorFinder::calculate(&flow_graph).err(),
734 Some(DominatorFinderError::UnreachableNodesInFlowGraph)
735 );
736 }
737
738 #[test]
739 fn test_closest_common_dominator_simple_cycle_with_entry() -> Result<(), DominatorFinderError> {
740 let flow_graph = FlowGraph::new(
746 SimpleDirectedGraph::new([("A", "B"), ("B", "C"), ("C", "D"), ("D", "B")]),
747 "A",
748 );
749 let df = DominatorFinder::calculate(&flow_graph)?;
750 assert_eq!(df.find_closest_common_dominator(["A", "B"])?, "A");
751 assert_eq!(df.find_closest_common_dominator(["A", "C"])?, "A");
752 assert_eq!(df.find_closest_common_dominator(["A", "B", "C"])?, "A");
753 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "B");
754 assert_eq!(df.find_closest_common_dominator(["B", "C", "D"])?, "B");
755 assert_eq!(df.find_closest_common_dominator(["A"])?, "A");
756 assert_eq!(df.find_closest_common_dominator(["B"])?, "B");
757 assert_eq!(df.find_closest_common_dominator(["C"])?, "C");
758 assert_eq!(df.find_closest_common_dominator(["D"])?, "D");
759 Ok(())
760 }
761
762 #[test]
763 fn test_closest_common_dominator_figure_eight_with_bridge() -> Result<(), DominatorFinderError>
764 {
765 let flow_graph = FlowGraph::new(
771 SimpleDirectedGraph::new([
772 ("A", "B"), ("B", "C"),
774 ("C", "D"),
775 ("D", "B"), ("D", "E"), ("E", "F"),
778 ("F", "G"),
779 ("G", "E"), ]),
781 "A",
782 );
783 let df = DominatorFinder::calculate(&flow_graph)?;
784 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "B");
785 assert_eq!(df.find_closest_common_dominator(["B", "D"])?, "B");
786 assert_eq!(df.find_closest_common_dominator(["B", "E"])?, "B");
787 assert_eq!(df.find_closest_common_dominator(["C", "E"])?, "C");
788 assert_eq!(df.find_closest_common_dominator(["C", "F"])?, "C");
789 assert_eq!(df.find_closest_common_dominator(["D", "E"])?, "D");
790 assert_eq!(df.find_closest_common_dominator(["D", "F"])?, "D");
791 assert_eq!(df.find_closest_common_dominator(["E", "G"])?, "E");
792 assert_eq!(df.find_closest_common_dominator(["F", "G"])?, "F");
793 Ok(())
794 }
795
796 #[test]
797 fn test_closest_common_dominator_figure_eight() -> Result<(), DominatorFinderError> {
798 let flow_graph = FlowGraph::new(
804 SimpleDirectedGraph::new([
805 ("A", "B"), ("B", "C"),
807 ("C", "D"),
808 ("D", "B"), ("D", "E"),
810 ("E", "F"),
811 ("F", "D"), ]),
813 "A",
814 );
815 let df = DominatorFinder::calculate(&flow_graph)?;
816 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "B");
817 assert_eq!(df.find_closest_common_dominator(["B", "D"])?, "B");
818 assert_eq!(df.find_closest_common_dominator(["B", "E"])?, "B");
819 assert_eq!(df.find_closest_common_dominator(["C", "D"])?, "C");
820 assert_eq!(df.find_closest_common_dominator(["C", "E"])?, "C");
821 assert_eq!(df.find_closest_common_dominator(["C", "F"])?, "C");
822 assert_eq!(df.find_closest_common_dominator(["D", "E"])?, "D");
823 assert_eq!(df.find_closest_common_dominator(["D", "F"])?, "D");
824 assert_eq!(df.find_closest_common_dominator(["E", "F"])?, "E");
825 Ok(())
826 }
827
828 #[test]
829 fn test_closest_common_dominator_entry_cycle_dominance() -> Result<(), DominatorFinderError> {
830 let flow_graph = FlowGraph::new(
834 SimpleDirectedGraph::new([("A", "B"), ("B", "C"), ("C", "B")]),
835 "A",
836 );
837 let df = DominatorFinder::calculate(&flow_graph)?;
838 assert_eq!(df.find_closest_common_dominator(["A", "B"])?, "A");
839 assert_eq!(df.find_closest_common_dominator(["A", "C"])?, "A");
840 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "B");
841 assert_eq!(df.find_closest_common_dominator(["A", "B", "C"])?, "A");
842 Ok(())
843 }
844
845 #[test]
846 fn test_closest_common_dominator_nested_loops() -> Result<(), DominatorFinderError> {
847 let flow_graph = FlowGraph::new(
855 SimpleDirectedGraph::new([
856 ("A", "B"),
857 ("B", "C"),
858 ("C", "D"),
859 ("C", "E"),
860 ("E", "C"),
861 ("D", "B"),
862 ]),
863 "A",
864 );
865 let df = DominatorFinder::calculate(&flow_graph)?;
866 assert_eq!(df.find_closest_common_dominator(["A", "B"])?, "A");
867 assert_eq!(df.find_closest_common_dominator(["A", "C"])?, "A");
868 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "B");
869 assert_eq!(df.find_closest_common_dominator(["B", "D"])?, "B");
870 assert_eq!(df.find_closest_common_dominator(["B", "E"])?, "B");
871 assert_eq!(df.find_closest_common_dominator(["C", "D"])?, "C");
872 assert_eq!(df.find_closest_common_dominator(["C", "E"])?, "C");
873 assert_eq!(df.find_closest_common_dominator(["D", "E"])?, "C");
874 assert_eq!(df.find_closest_common_dominator(["B", "C", "D"])?, "B");
875 assert_eq!(df.find_closest_common_dominator(["B", "C", "E"])?, "B");
876 assert_eq!(df.find_closest_common_dominator(["B", "D", "E"])?, "B");
877 assert_eq!(df.find_closest_common_dominator(["C", "D", "E"])?, "C");
878 assert_eq!(df.find_closest_common_dominator(["B", "C", "D", "E"])?, "B");
879 Ok(())
880 }
881
882 #[test]
883 fn test_irreducible_graph_cooper_harvey_kennedy_fig2() -> Result<(), DominatorFinderError> {
884 let graph = SimpleDirectedGraph::new([(1, 2), (2, 1), (3, 2), (4, 1), (5, 4), (5, 3)]);
893 let flow_graph = FlowGraph::new(graph, 5);
894 let df = DominatorFinder::calculate(&flow_graph)?;
895 assert_eq!(
896 df.get_immediate_dominators(),
897 HashMap::from([(1, 5), (2, 5), (3, 5), (4, 5), (5, 5),])
898 );
899 Ok(())
900 }
901
902 #[test]
903 fn test_irreducible_graph_cooper_harvey_kennedy_fig3() -> Result<(), DominatorFinderError> {
904 let graph = SimpleDirectedGraph::new([
913 (1, 2),
914 (2, 1),
915 (2, 3),
916 (3, 2),
917 (5, 1),
918 (4, 2),
919 (4, 3),
920 (6, 5),
921 (6, 4),
922 ]);
923 let flow_graph = FlowGraph::new(graph, 6);
924 let df = DominatorFinder::calculate(&flow_graph)?;
925 assert_eq!(
926 df.get_immediate_dominators(),
927 HashMap::from([(1, 6), (2, 6), (3, 6), (4, 6), (5, 6), (6, 6),])
928 );
929 assert_eq!(df.find_closest_common_dominator([2, 3])?, 6);
930 Ok(())
931 }
932
933 #[test]
934 fn test_dominator_tree_with_three_levels() -> Result<(), DominatorFinderError> {
935 let graph =
950 SimpleDirectedGraph::new([(1, 2), (2, 3), (2, 4), (2, 6), (3, 5), (4, 5), (5, 2)]);
951 let flow_graph = FlowGraph::new(graph, 1);
952 let df = DominatorFinder::calculate(&flow_graph)?;
953 assert_eq!(
954 df.get_immediate_dominators(),
955 HashMap::from([(1, 1), (2, 1), (3, 2), (4, 2), (5, 2), (6, 2),])
956 );
957 assert_eq!(df.find_closest_common_dominator([1, 6])?, 1);
958 assert_eq!(df.find_closest_common_dominator([2, 3])?, 2);
959 assert_eq!(df.find_closest_common_dominator([2, 4])?, 2);
960 assert_eq!(df.find_closest_common_dominator([2, 5])?, 2);
961 assert_eq!(df.find_closest_common_dominator([2, 6])?, 2);
962 assert_eq!(df.find_closest_common_dominator([3, 4])?, 2);
963 assert_eq!(df.find_closest_common_dominator([3, 5])?, 2);
964 assert_eq!(df.find_closest_common_dominator([3, 6])?, 2);
965 assert_eq!(df.find_closest_common_dominator([4, 5])?, 2);
966 assert_eq!(df.find_closest_common_dominator([4, 6])?, 2);
967 assert_eq!(df.find_closest_common_dominator([5, 6])?, 2);
968 assert_eq!(df.find_closest_common_dominator([2, 3, 5])?, 2);
969 assert_eq!(df.find_closest_common_dominator([3, 4, 5])?, 2);
970 assert_eq!(df.find_closest_common_dominator([3, 4, 5, 6])?, 2);
971 Ok(())
972 }
973
974 #[test]
975 fn test_big_graph_fig_18_3() -> Result<(), DominatorFinderError> {
976 let graph = SimpleDirectedGraph::new([
1002 (1, 2),
1003 (2, 3),
1004 (2, 4),
1005 (3, 2),
1006 (4, 2),
1007 (4, 5),
1008 (4, 6),
1009 (5, 7),
1010 (5, 8),
1011 (6, 7),
1012 (7, 11),
1013 (8, 9),
1014 (9, 8),
1015 (9, 10),
1016 (10, 5),
1017 (10, 12),
1018 (11, 12),
1019 ]);
1020 let flow_graph = FlowGraph::new(graph, 1);
1021 let df = DominatorFinder::calculate(&flow_graph)?;
1022 assert_eq!(
1023 df.get_immediate_dominators(),
1024 HashMap::from([
1025 (1, 1),
1026 (2, 1),
1027 (3, 2),
1028 (4, 2),
1029 (5, 4),
1030 (6, 4),
1031 (7, 4),
1032 (8, 5),
1033 (9, 8),
1034 (10, 9),
1035 (11, 7),
1036 (12, 4)
1037 ])
1038 );
1039 assert_eq!(df.find_closest_common_dominator([6, 3])?, 2);
1040 assert_eq!(df.find_closest_common_dominator([11, 9, 12])?, 4);
1041 assert_eq!(df.find_closest_common_dominator([11, 9, 5])?, 4);
1042 assert_eq!(df.find_closest_common_dominator([11, 10])?, 4);
1043 assert_eq!(df.find_closest_common_dominator([10, 11, 12, 3, 6])?, 2);
1044 Ok(())
1045 }
1046
1047 #[test]
1048 fn test_big_graph_fig_19_8() -> Result<(), DominatorFinderError> {
1049 let graph = SimpleDirectedGraph::new([
1076 ("A", "B"),
1077 ("A", "C"),
1078 ("B", "D"),
1079 ("B", "G"),
1080 ("C", "E"),
1081 ("C", "H"),
1082 ("D", "F"),
1083 ("D", "G"),
1084 ("E", "C"),
1085 ("E", "H"),
1086 ("F", "I"),
1087 ("F", "K"),
1088 ("G", "J"),
1089 ("H", "M"),
1090 ("I", "L"),
1091 ("J", "I"),
1092 ("K", "L"),
1093 ("L", "B"),
1094 ("L", "M"),
1095 ]);
1096 let flow_graph = FlowGraph::new(graph, "A");
1097 let df = DominatorFinder::calculate(&flow_graph)?;
1098 assert_eq!(
1099 df.get_immediate_dominators(),
1100 HashMap::from([
1101 ("A", "A"),
1102 ("B", "A"),
1103 ("C", "A"),
1104 ("D", "B"),
1105 ("E", "C"),
1106 ("F", "D"),
1107 ("G", "B"),
1108 ("H", "C"),
1109 ("I", "B"),
1110 ("J", "G"),
1111 ("K", "F"),
1112 ("L", "B"),
1113 ("M", "A"),
1114 ])
1115 );
1116 assert_eq!(df.find_closest_common_dominator(["K", "L"])?, "B");
1117 assert_eq!(df.find_closest_common_dominator(["K", "C"])?, "A");
1118 assert_eq!(df.find_closest_common_dominator(["B", "G", "J"])?, "B");
1119 Ok(())
1120 }
1121
1122 #[test]
1123 fn test_closest_common_dominator_tree() -> Result<(), DominatorFinderError> {
1124 let flow_graph = FlowGraph::new(
1128 SimpleDirectedGraph::new([("A", "B"), ("B", "C"), ("B", "D"), ("A", "E")]),
1129 "A",
1130 );
1131 let df = DominatorFinder::calculate(&flow_graph)?;
1132 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "B");
1133 assert_eq!(df.find_closest_common_dominator(["B", "E"])?, "A");
1134 assert_eq!(df.find_closest_common_dominator(["C", "D"])?, "B");
1135 assert_eq!(df.find_closest_common_dominator(["C", "E"])?, "A");
1136 assert_eq!(df.find_closest_common_dominator(["B", "C", "D"])?, "B");
1137 assert_eq!(df.find_closest_common_dominator(["C", "D", "E"])?, "A");
1138 Ok(())
1139 }
1140
1141 #[test]
1142 fn test_closest_common_dominator_bypassing_path() -> Result<(), DominatorFinderError> {
1143 let flow_graph = FlowGraph::new(
1148 SimpleDirectedGraph::new([("A", "B"), ("B", "C"), ("C", "D"), ("A", "E"), ("E", "D")]),
1149 "A",
1150 );
1151 let df = DominatorFinder::calculate(&flow_graph)?;
1152 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "B");
1153 assert_eq!(df.find_closest_common_dominator(["B", "D"])?, "A");
1154 assert_eq!(df.find_closest_common_dominator(["B", "E"])?, "A");
1155 assert_eq!(df.find_closest_common_dominator(["C", "D"])?, "A");
1156 assert_eq!(df.find_closest_common_dominator(["C", "E"])?, "A");
1157 assert_eq!(df.find_closest_common_dominator(["D", "E"])?, "A");
1158 assert_eq!(df.find_closest_common_dominator(["B", "C", "D"])?, "A");
1159 assert_eq!(df.find_closest_common_dominator(["C", "D", "E"])?, "A");
1160 Ok(())
1161 }
1162
1163 #[test]
1164 fn test_closest_common_dominator_self_loop_handling() -> Result<(), DominatorFinderError> {
1165 let flow_graph = FlowGraph::new(SimpleDirectedGraph::new([("A", "A"), ("A", "B")]), "A");
1167 let df = DominatorFinder::calculate(&flow_graph)?;
1168 assert_eq!(df.find_closest_common_dominator(["A"])?, "A");
1169 Ok(())
1170 }
1171
1172 #[test]
1173 fn test_closest_common_dominator_multi_edge() -> Result<(), DominatorFinderError> {
1174 let flow_graph = FlowGraph::new(
1176 SimpleDirectedGraph::new([
1177 ("A", "B"),
1178 ("A", "B"), ("B", "C"),
1180 ]),
1181 "A",
1182 );
1183 let df = DominatorFinder::calculate(&flow_graph)?;
1184 assert_eq!(df.find_closest_common_dominator(["A"])?, "A");
1185 assert_eq!(df.find_closest_common_dominator(["B", "C"])?, "B");
1186 Ok(())
1187 }
1188
1189 #[test]
1190 fn test_closest_common_dominator_invalid_target_set() -> Result<(), DominatorFinderError> {
1191 let flow_graph = FlowGraph::new(SimpleDirectedGraph::new([("A", "B")]), "A");
1193 let df = DominatorFinder::calculate(&flow_graph)?;
1194 assert_eq!(
1195 df.find_closest_common_dominator([]),
1196 Err(DominatorFinderError::EmptyTargetSet)
1197 );
1198 Ok(())
1199 }
1200
1201 #[test]
1202 fn test_closest_common_dominator_repeated_node() -> Result<(), DominatorFinderError> {
1203 let flow_graph = FlowGraph::new(SimpleDirectedGraph::new([("A", "B")]), "A");
1205 let df = DominatorFinder::calculate(&flow_graph)?;
1206 assert_eq!(df.find_closest_common_dominator(["A", "B", "A", "B"])?, "A");
1207 Ok(())
1208 }
1209
1210 #[test]
1211 fn test_simple_directed_graph_nodes() {
1212 let graph = SimpleDirectedGraph::new([("A", "B"), ("B", "C")]);
1213 let nodes = graph.nodes().copied().collect_vec();
1214 assert_eq!(nodes, ["A", "B", "C"]);
1215
1216 let graph = SimpleDirectedGraph::<String>::new([]);
1217 let nodes = graph.nodes().cloned().collect_vec();
1218 assert!(nodes.is_empty());
1219 }
1220
1221 #[test]
1222 fn test_simple_directed_graph_edges() {
1223 let graph = SimpleDirectedGraph::new([("A", "B"), ("B", "C"), ("A", "C")]);
1224 let edges = graph.edges().map(|(&u, &v)| (u, v)).collect_vec();
1225 assert_eq!(edges, [("A", "B"), ("A", "C"), ("B", "C")]);
1226
1227 let graph = SimpleDirectedGraph::<String>::new([]);
1228 let edges = graph.edges().collect_vec();
1229 assert!(edges.is_empty());
1230 }
1231
1232 #[test]
1233 fn test_simple_directed_graph_adjacent_nodes() {
1234 let graph = SimpleDirectedGraph::new([("A", "B"), ("A", "C"), ("B", "D")]);
1235 assert_eq!(
1236 graph.adjacent_nodes(&"A").unwrap().copied().collect_vec(),
1237 ["B", "C"]
1238 );
1239 assert_eq!(
1240 graph.adjacent_nodes(&"B").unwrap().copied().collect_vec(),
1241 ["D"]
1242 );
1243 assert!(graph.adjacent_nodes(&"C").unwrap().next().is_none());
1244 assert!(graph.adjacent_nodes(&"Z").is_none());
1245 }
1246
1247 #[test]
1248 fn test_simple_directed_graph_contains_node() {
1249 let graph = SimpleDirectedGraph::new([("A", "B"), ("B", "C")]);
1250 assert!(graph.contains_node(&"A"));
1251 assert!(graph.contains_node(&"B"));
1252 assert!(graph.contains_node(&"C"));
1253 assert!(!graph.contains_node(&"D"));
1254 }
1255
1256 #[test]
1257 fn test_simple_directed_graph_new() {
1258 let graph = SimpleDirectedGraph::new([("A", "B"), ("A", "C"), ("B", "C"), ("A", "B")]);
1259 let nodes = graph.nodes().copied().collect_vec();
1260 assert_eq!(nodes, ["A", "B", "C"]);
1261 let edges = graph.edges().map(|(&u, &v)| (u, v)).collect_vec();
1262 assert_eq!(edges, [("A", "B"), ("A", "C"), ("B", "C")]);
1263
1264 let graph = SimpleDirectedGraph::new([("B", "C"), ("A", "B")]);
1265 let nodes = graph.nodes().copied().collect_vec();
1266 assert_eq!(nodes, ["B", "C", "A"]);
1267 let edges = graph.edges().map(|(&u, &v)| (u, v)).collect_vec();
1268 assert_eq!(edges, [("B", "C"), ("A", "B")]);
1269 }
1270
1271 #[test]
1272 fn test_flow_graph_new() {
1273 let graph = SimpleDirectedGraph::new([("A", "B")]);
1274 let flow_graph = FlowGraph::new(graph.clone(), "A");
1275 assert_eq!(flow_graph.graph, graph);
1276 assert_eq!(flow_graph.start_node, "A");
1277 let flow_graph = FlowGraph::new(graph.clone(), "C");
1278 assert_eq!(flow_graph.graph, graph);
1279 assert_eq!(flow_graph.start_node, "C");
1280 }
1281
1282 #[test]
1283 fn test_post_order() {
1284 let neighbors = hashmap! {
1295 'A' => vec![],
1296 'B' => vec!['A'],
1297 'C' => vec!['B'],
1298 'D' => vec!['C'],
1299 'E' => vec!['A'],
1300 'F' => vec!['E', 'D'],
1301 };
1302 let neighbors_fn = |node: &char| neighbors[node].iter().copied();
1303 assert_eq!(
1304 post_order('F', neighbors_fn).collect_vec(),
1305 ['A', 'E', 'B', 'C', 'D', 'F']
1306 );
1307 assert_eq!(post_order('E', neighbors_fn).collect_vec(), ['A', 'E']);
1308 assert_eq!(
1309 post_order('D', neighbors_fn).collect_vec(),
1310 ['A', 'B', 'C', 'D']
1311 );
1312 assert_eq!(post_order('A', neighbors_fn).collect_vec(), ['A']);
1313
1314 let neighbors = hashmap! {
1329 'A' => vec![],
1330 'B' => vec!['A'],
1331 'C' => vec!['A'],
1332 'D' => vec!['B'],
1333 'E' => vec!['C'],
1334 'F' => vec!['C'],
1335 'G' => vec!['E'],
1336 'H' => vec!['F', 'G'],
1337 'I' => vec!['D', 'H'],
1338 };
1339 let neighbors_fn = |node: &char| neighbors[node].iter().copied();
1340 assert_eq!(
1341 post_order('I', neighbors_fn).collect_vec(),
1342 ['A', 'B', 'D', 'C', 'F', 'E', 'G', 'H', 'I']
1343 );
1344
1345 let neighbors = hashmap! {
1362 'A' => vec![],
1363 'b' => vec!['A'],
1364 'C' => vec!['A'],
1365 'D' => vec!['b'],
1366 'e' => vec!['C', 'b'],
1367 'f' => vec!['D'],
1368 'G' => vec!['e', 'D'],
1369 'h' => vec!['G', 'f'],
1370 'I' => vec!['C', 'e', 'G', 'h'],
1371 };
1372 let neighbors_fn = |node: &char| neighbors[node].iter().copied();
1373 assert_eq!(
1374 post_order('I', neighbors_fn).collect_vec(),
1375 ['A', 'C', 'b', 'e', 'D', 'G', 'f', 'h', 'I']
1376 );
1377
1378 let neighbors = hashmap! {
1390 'A' => vec![],
1391 'B' => vec!['A'],
1392 'C' => vec!['B'],
1393 'D' => vec!['C'],
1394 'E' => vec!['C'],
1395 'F' => vec!['D'],
1396 'G' => vec!['E', 'F'],
1397 };
1398 let neighbors_fn = |node: &char| neighbors[node].iter().copied();
1399 assert_eq!(
1400 post_order('G', neighbors_fn).collect_vec(),
1401 ['A', 'B', 'C', 'E', 'D', 'F', 'G']
1402 );
1403
1404 let neighbors = hashmap! {
1416 'A' => vec![],
1417 'B' => vec!['A'],
1418 'c' => vec!['B'],
1419 'D' => vec!['c'],
1420 'E' => vec!['c'],
1421 'F' => vec!['E'],
1422 'G' => vec!['F', 'D'],
1423 };
1424 let neighbors_fn = |node: &char| neighbors[node].iter().copied();
1425 assert_eq!(
1426 post_order('G', neighbors_fn).collect_vec(),
1427 ['A', 'B', 'c', 'E', 'F', 'D', 'G']
1428 );
1429
1430 let neighbors = hashmap! {
1443 'A' => vec![],
1444 'B' => vec!['A'],
1445 'C' => vec!['B'],
1446 'D' => vec!['A'],
1447 'E' => vec!['A'],
1448 'F' => vec!['E', 'D'],
1449 };
1450 let neighbors_fn = |node: &char| neighbors[node].iter().copied();
1451 assert_eq!(
1452 post_order('F', neighbors_fn).collect_vec(),
1453 ['A', 'E', 'D', 'F']
1454 );
1455 assert_eq!(post_order('C', neighbors_fn).collect_vec(), ['A', 'B', 'C']);
1456
1457 let neighbors = hashmap! {
1465 'A' => vec![],
1466 'B' => vec!['A'],
1467 'C' => vec![],
1468 'D' => vec!['C', 'B'],
1469 };
1470 let neighbors_fn = |node: &char| neighbors[node].iter().copied();
1471 assert_eq!(
1472 post_order('D', neighbors_fn).collect_vec(),
1473 ['C', 'A', 'B', 'D']
1474 );
1475
1476 let neighbors = hashmap! {
1482 'A' => vec!['C'],
1483 'B' => vec!['A'],
1484 'C' => vec!['B'],
1485 };
1486 let neighbors_fn = |node: &char| neighbors[node].iter().copied();
1487 assert_eq!(post_order('C', neighbors_fn).collect_vec(), ['A', 'B', 'C']);
1488 assert_eq!(post_order('B', neighbors_fn).collect_vec(), ['C', 'A', 'B']);
1489 assert_eq!(post_order('A', neighbors_fn).collect_vec(), ['B', 'C', 'A']);
1490 }
1491
1492 #[test]
1493 fn test_value_flow_graph_new() {
1494 let simple_graph = SimpleDirectedGraph::new([("A", "B"), ("B", "C")]);
1496 let flow_graph = FlowGraph::new(simple_graph, "A");
1497 let node_values = HashMap::from([("A", 1), ("B", 1), ("C", 2)]);
1498 let value_flow_graph = flow_graph.create_value_flow_graph(&node_values);
1499
1500 let expected_value_edges = [(&1, &1), (&1, &2)];
1501 let expected_flow_graph =
1502 FlowGraph::new(SimpleDirectedGraph::new(expected_value_edges), &1);
1503 assert_eq!(value_flow_graph, expected_flow_graph);
1504 }
1505
1506 #[test]
1507 fn test_value_flow_graph_find_dominator_value() {
1508 let simple_graph =
1511 SimpleDirectedGraph::new([("A", "B"), ("B", "C"), ("C", "D"), ("B", "E")]);
1512 let flow_graph = FlowGraph::new(simple_graph, "A");
1513 let value_fn = async |node: &&str| match *node {
1514 "A" | "B" => Ok(1),
1515 "C" => Ok(2),
1516 "D" | "E" => Ok(3),
1517 _ => Err("Unknown node".to_string()),
1518 };
1519
1520 assert_eq!(
1525 flow_graph
1526 .find_dominator_value(&["D", "E"], value_fn)
1527 .block_on(),
1528 Ok(3)
1529 );
1530 assert_eq!(
1531 flow_graph
1532 .find_dominator_value(&["C", "D"], value_fn)
1533 .block_on(),
1534 Ok(1)
1535 );
1536 assert_eq!(
1537 flow_graph
1538 .find_dominator_value(&["B", "C"], value_fn)
1539 .block_on(),
1540 Ok(1)
1541 );
1542 }
1543
1544 #[test]
1545 fn test_find_dominator_value_with_distinct_values() {
1546 let simple_graph =
1549 SimpleDirectedGraph::new([("A", "B"), ("B", "C"), ("C", "D"), ("B", "E")]);
1550 let flow_graph = FlowGraph::new(simple_graph, "A");
1551 let value_fn = async |node: &&str| match *node {
1552 "A" => Ok(1),
1553 "B" => Ok(2),
1554 "C" => Ok(3),
1555 "D" => Ok(4),
1556 "E" => Ok(5),
1557 _ => Err("Unknown node".to_string()),
1558 };
1559
1560 assert_eq!(
1564 flow_graph
1565 .find_dominator_value(&["D", "E"], value_fn)
1566 .block_on(),
1567 Ok(2)
1568 );
1569 assert_eq!(
1570 flow_graph
1571 .find_dominator_value(&["C", "D"], value_fn)
1572 .block_on(),
1573 Ok(3)
1574 );
1575 assert_eq!(
1576 flow_graph
1577 .find_dominator_value(&["B", "C"], value_fn)
1578 .block_on(),
1579 Ok(2)
1580 );
1581 }
1582
1583 #[test]
1584 fn test_find_dominator_value_with_invalid_flow_graph() {
1585 let simple_graph = SimpleDirectedGraph::new([("A", "B"), ("C", "D")]);
1588 let flow_graph = FlowGraph::new(simple_graph, "A");
1589 let value_fn = async |node: &&str| match *node {
1590 "A" | "B" => Ok(1),
1591 "C" | "D" => Ok(2),
1592 _ => Err("Unknown node".to_string()),
1593 };
1594 assert_eq!(
1601 flow_graph
1602 .find_dominator_value(&["B", "D"], value_fn)
1603 .block_on(),
1604 Ok(1)
1605 );
1606 }
1607
1608 #[test]
1609 fn test_find_dominator_value_with_unknown_node_in_target_set() {
1610 let simple_graph = SimpleDirectedGraph::new([("A", "B")]);
1612 let flow_graph = FlowGraph::new(simple_graph, "A");
1613 let value_fn = async |node: &&str| match *node {
1614 "A" => Ok(1),
1615 "B" => Ok(2),
1616 "X" => Ok(666),
1617 _ => Err("Unknown node".to_string()),
1618 };
1619 assert_eq!(
1620 flow_graph
1621 .find_dominator_value(&["B", "X"], value_fn)
1622 .block_on(),
1623 Err(FindDominatorValueError::DominatorFinderError(
1624 DominatorFinderError::UnknownNodeInTargetSet
1625 ))
1626 );
1627 }
1628
1629 #[test]
1630 fn test_find_dominator_value_with_unknown_node() {
1631 let simple_graph = SimpleDirectedGraph::new([("A", "B")]);
1633 let flow_graph = FlowGraph::new(simple_graph, "A");
1634 let value_fn = async |node: &&str| match *node {
1635 "A" => Ok(1),
1636 "B" => Ok(2),
1637 _ => Err("Unknown node".to_string()),
1638 };
1639 assert_eq!(
1640 flow_graph
1641 .find_dominator_value(&["B", "X"], value_fn)
1642 .block_on(),
1643 Err(FindDominatorValueError::ValueFnError(
1644 "Unknown node".to_string()
1645 ))
1646 );
1647 }
1648}