# domtree `domtree` provides a generic implementation to calculate the dominator tree of a directed graph. The algorithm basically follows the description in "A Simple, Fast Dominance Algorithm" by Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy. To implement the trait for your own graph structure, you need to prepare several fields: ```rust #[derive(Clone)] struct VecSet(Vec); impl AssocSet for VecSet { fn get(&self, target: usize) -> Y { self.0[target].clone() } fn set(&mut self, key: usize, val: Y) { self.0[key] = val; } } #[derive(Clone, Debug)] struct HashMemberSet(HashSet); impl MemberSet for HashMemberSet { fn contains(&self, target: T) -> bool { self.0.contains(&target) } fn insert(&mut self, target: T) { self.0.insert(target); } type MemberIter<'a> = Cloned> where Self : 'a; fn iter<'a>(&'a self) -> Self::MemberIter<'a> { self.0.iter().cloned() } } impl MergeSet for HashMemberSet { fn subset(&self, other: &Self) -> bool { self.0.is_subset(&other.0) } fn union(&mut self, other: &Self) { for i in other.0.iter().cloned() { self.0.insert(i); } } } #[derive(Debug)] struct Node { tag: usize, // node's identifier dom: Option, // node's immediate dominator frontiers: UnsafeCell>, // node's dominance frontiers incoming_edges: Vec, // node's in-edges outgoing_edges: Vec // node's out-edges } #[derive(Debug)] struct Graph { nodes: Vec, } ``` Then, one needs to first expose some APIs such that this crate can run DFS on the graph. ```rust use std::iter::Cloned; use std::slice::Iter; use domtree::dfs::DFSGraph; impl DFSGraph for Graph { type Identifier = usize; type Set = VecSet where Y: Clone + Default; type SuccessorIter<'a> = Cloned> where Self: 'a; fn create_set(&self) -> Self::Set where Y: Clone + Default { let mut data = Vec::new(); data.resize(self.nodes.len(), Default::default()); VecSet(data) } fn outgoing_edges<'a>(&'a self, id: Self::Identifier) -> Self::SuccessorIter<'a> { self.nodes[id].outgoing_edges.iter().cloned() } } ``` After this, one also need to specify how the algorithm can access the fields related to the dominance tree. ```rust impl DomTree for Graph { type MutDomIter<'a> = Map, fn(&'a mut Node)->&'a mut Option> where Self: 'a; type PredecessorIter<'a> = Cloned> where Self: 'a; fn dom(&self, id: Self::Identifier) -> Option { self.nodes[id].dom.clone() } fn set_dom(&mut self, id: Self::Identifier, target: Option) { self.nodes[id].dom = target; } fn predecessor_iter<'a>(&'a self, id: Self::Identifier) -> Self::PredecessorIter<'a> { self.nodes[id].incoming_edges.iter().cloned() } fn doms_mut<'a>(&'a mut self) -> Self::MutDomIter<'a> { self.nodes.iter_mut().map(|x|&mut x.dom) } } impl DominanceFrontier for Graph { type FrontierSet = HashMemberSet; type NodeIter<'a> = Range where Self: 'a ; fn frontiers_cell(&self, id: Self::Identifier) -> &UnsafeCell { &self.nodes[id].frontiers } fn node_iter<'a>(&'a self) -> Self::NodeIter<'a> { 0..self.nodes.len() } } ``` Then, one can just run populate the dominance tree and the dominance frontiers ```rust let mut g = random_graph(10000); dump_graph(&g); g.populate_dom(0); g.populate_frontiers(); ```