1#[cfg(not(feature = "std"))]
16use alloc::{
17 collections::{BTreeSet as HashSet, BTreeMap as HashMap, btree_map::Iter},
18 vec::Vec,
19};
20
21#[cfg(not(feature = "std"))]
22use core::{cmp::Ordering, hash::Hash, usize, iter::Iterator};
23
24#[cfg(feature = "std")]
25use std::{
26 cmp::Ordering,
27 collections::{HashMap, HashSet, hash_map::Iter},
28 hash::Hash,
29 usize,
30};
31
32use crate::visit::{DfsPostOrder, GraphBase, IntoNeighbors, Visitable, Walker};
33
34#[derive(Debug, Clone)]
36pub struct Dominators<N>
37where
38 N: Copy + Eq + Hash,
39{
40 root: N,
41 dominators: HashMap<N, N>,
42}
43
44impl<N> Dominators<N>
45where
46 N: Copy + Eq + Hash + Ord,
47{
48 pub fn root(&self) -> N {
50 self.root
51 }
52
53 pub fn immediate_dominator(&self, node: N) -> Option<N> {
58 if node == self.root {
59 None
60 } else {
61 self.dominators.get(&node).cloned()
62 }
63 }
64
65 pub fn strict_dominators(&self, node: N) -> Option<DominatorsIter<N>> {
70 if self.dominators.contains_key(&node) {
71 Some(DominatorsIter {
72 dominators: self,
73 node: self.immediate_dominator(node),
74 })
75 } else {
76 None
77 }
78 }
79
80 pub fn dominators(&self, node: N) -> Option<DominatorsIter<N>> {
86 if self.dominators.contains_key(&node) {
87 Some(DominatorsIter {
88 dominators: self,
89 node: Some(node),
90 })
91 } else {
92 None
93 }
94 }
95
96 pub fn immediately_dominated_by(&self, node: N) -> DominatedByIter<N> {
99 DominatedByIter {
100 iter: self.dominators.iter(),
101 node: node
102 }
103 }
104}
105
106pub struct DominatorsIter<'a, N>
108where
109 N: 'a + Copy + Eq + Hash,
110{
111 dominators: &'a Dominators<N>,
112 node: Option<N>,
113}
114
115impl<'a, N> Iterator for DominatorsIter<'a, N>
116where
117 N: 'a + Copy + Eq + Hash + Ord,
118{
119 type Item = N;
120
121 fn next(&mut self) -> Option<Self::Item> {
122 let next = self.node.take();
123 if let Some(next) = next {
124 self.node = self.dominators.immediate_dominator(next);
125 }
126 next
127 }
128}
129
130pub struct DominatedByIter<'a, N>
132where
133 N: 'a + Copy + Eq + Hash,
134{
135 iter: Iter<'a, N, N>,
136 node: N,
137}
138
139impl<'a, N> Iterator for DominatedByIter<'a, N>
140where
141 N: 'a + Copy + Eq + Hash,
142{
143 type Item = N;
144
145 fn next(&mut self) -> Option<Self::Item> {
146 while let Some(next) = self.iter.next() {
147 if next.1 == &self.node {
148 return Some(*next.0);
149 }
150 }
151 None
152 }
153}
154
155const UNDEFINED: usize = usize::MAX;
158
159pub fn simple_fast<G>(graph: G, root: G::NodeId) -> Dominators<G::NodeId>
169where
170 G: IntoNeighbors + Visitable,
171 <G as GraphBase>::NodeId: Eq + Hash + Ord,
172{
173 let (post_order, predecessor_sets) = simple_fast_post_order(graph, root);
174 let length = post_order.len();
175 debug_assert!(length > 0);
176 debug_assert!(post_order.last() == Some(&root));
177
178 let node_to_post_order_idx: HashMap<_, _> = post_order
185 .iter()
186 .enumerate()
187 .map(|(idx, &node)| (node, idx))
188 .collect();
189
190 let idx_to_predecessor_vec =
193 predecessor_sets_to_idx_vecs(&post_order, &node_to_post_order_idx, predecessor_sets);
194
195 let mut dominators = vec![UNDEFINED; length];
196 dominators[length - 1] = length - 1;
197
198 let mut changed = true;
199 while changed {
200 changed = false;
201
202 for idx in (0..length - 1).rev() {
205 debug_assert!(post_order[idx] != root);
206
207 let new_idom_idx = {
212 let mut predecessors = idx_to_predecessor_vec[idx]
213 .iter()
214 .filter(|&&p| dominators[p] != UNDEFINED);
215 let new_idom_idx = predecessors.next().expect(
216 "Because the root is initialized to dominate itself, and is the \
217 first node in every path, there must exist a predecessor to this \
218 node that also has a dominator",
219 );
220 predecessors.fold(*new_idom_idx, |new_idom_idx, &predecessor_idx| {
221 intersect(&dominators, new_idom_idx, predecessor_idx)
222 })
223 };
224
225 debug_assert!(new_idom_idx < length);
226
227 if new_idom_idx != dominators[idx] {
228 dominators[idx] = new_idom_idx;
229 changed = true;
230 }
231 }
232 }
233
234 debug_assert!(!dominators.iter().any(|&dom| dom == UNDEFINED));
237
238 Dominators {
239 root: root,
240 dominators: dominators
241 .into_iter()
242 .enumerate()
243 .map(|(idx, dom_idx)| (post_order[idx], post_order[dom_idx]))
244 .collect(),
245 }
246}
247
248fn intersect(dominators: &[usize], mut finger1: usize, mut finger2: usize) -> usize {
249 loop {
250 match finger1.cmp(&finger2) {
251 Ordering::Less => finger1 = dominators[finger1],
252 Ordering::Greater => finger2 = dominators[finger2],
253 Ordering::Equal => return finger1,
254 }
255 }
256}
257
258#[cfg(feature = "std")]
259fn predecessor_sets_to_idx_vecs<N>(
260 post_order: &[N],
261 node_to_post_order_idx: &HashMap<N, usize>,
262 mut predecessor_sets: HashMap<N, HashSet<N>>,
263) -> Vec<Vec<usize>>
264where
265 N: Copy + Eq + Hash,
266{
267 post_order
268 .iter()
269 .map(|node| {
270 predecessor_sets
271 .remove(node)
272 .map(|predecessors| {
273 predecessors
274 .into_iter()
275 .map(|p| *node_to_post_order_idx.get(&p).unwrap())
276 .collect()
277 })
278 .unwrap_or_else(Vec::new)
279 })
280 .collect()
281}
282
283#[cfg(not(feature = "std"))]
284fn predecessor_sets_to_idx_vecs<N>(
285 post_order: &[N],
286 node_to_post_order_idx: &HashMap<N, usize>,
287 mut predecessor_sets: HashMap<N, HashSet<N>>,
288) -> Vec<Vec<usize>>
289where
290 N: Copy + Eq + Hash + Ord,
291{
292 post_order
293 .iter()
294 .map(|node| {
295 predecessor_sets
296 .remove(node)
297 .map(|predecessors| {
298 predecessors
299 .into_iter()
300 .map(|p| *node_to_post_order_idx.get(&p).unwrap())
301 .collect()
302 })
303 .unwrap_or_else(Vec::new)
304 })
305 .collect()
306}
307
308#[cfg(feature = "std")]
309fn simple_fast_post_order<G>(
310 graph: G,
311 root: G::NodeId,
312) -> (Vec<G::NodeId>, HashMap<G::NodeId, HashSet<G::NodeId>>)
313where
314 G: IntoNeighbors + Visitable,
315 <G as GraphBase>::NodeId: Eq + Hash,
316{
317 let mut post_order = vec![];
318 let mut predecessor_sets = HashMap::new();
319
320 for node in DfsPostOrder::new(graph, root).iter(graph) {
321 post_order.push(node);
322
323 for successor in graph.neighbors(node) {
324 predecessor_sets
325 .entry(successor)
326 .or_insert_with(HashSet::new)
327 .insert(node);
328 }
329 }
330
331 (post_order, predecessor_sets)
332}
333
334#[cfg(not(feature = "std"))]
335fn simple_fast_post_order<G>(
336 graph: G,
337 root: G::NodeId,
338) -> (Vec<G::NodeId>, HashMap<G::NodeId, HashSet<G::NodeId>>)
339where
340 G: IntoNeighbors + Visitable,
341 <G as GraphBase>::NodeId: Eq + Hash + Ord,
342{
343 let mut post_order = vec![];
344 let mut predecessor_sets = HashMap::new();
345
346 for node in DfsPostOrder::new(graph, root).iter(graph) {
347 post_order.push(node);
348
349 for successor in graph.neighbors(node) {
350 predecessor_sets
351 .entry(successor)
352 .or_insert_with(HashSet::new)
353 .insert(node);
354 }
355 }
356
357 (post_order, predecessor_sets)
358}
359
360#[cfg(test)]
361#[cfg(not(feature = "std"))]
362mod tests {
363 use super::*;
364
365 #[test]
366 fn test_iter_dominators() {
367 let doms: Dominators<u32> = Dominators {
368 root: 0,
369 dominators: [(2, 1), (1, 0), (0, 0)].iter().cloned().collect(),
370 };
371
372 let all_doms: Vec<_> = doms.dominators(2).unwrap().collect();
373 assert_eq!(vec![2, 1, 0], all_doms);
374
375 assert_eq!(None::<()>, doms.dominators(99).map(|_| unreachable!()));
376
377 let strict_doms: Vec<_> = doms.strict_dominators(2).unwrap().collect();
378 assert_eq!(vec![1, 0], strict_doms);
379
380 assert_eq!(
381 None::<()>,
382 doms.strict_dominators(99).map(|_| unreachable!())
383 );
384
385 let dom_by: Vec<_> = doms.immediately_dominated_by(1).collect();
386 assert_eq!(vec![2], dom_by);
387 assert_eq!(None, doms.immediately_dominated_by(99).next());
388 }
389}