1use rustc_data_structures::fx::FxHashSet;
9use std::cmp;
10
11#[derive(Debug, Clone, Eq, Hash, PartialEq)]
13pub struct SccExit {
14 pub exit: usize,
15 pub to: usize,
16}
17
18impl SccExit {
19 pub fn new(exit: usize, to: usize) -> Self {
21 SccExit { exit, to }
22 }
23}
24
25#[derive(Debug, Clone)]
27pub struct SccInfo {
28 pub enter: usize,
30 pub nodes: FxHashSet<usize>,
32 pub exits: FxHashSet<SccExit>,
34 pub backnodes: FxHashSet<usize>,
36}
37
38impl SccInfo {
39 pub fn new(enter: usize) -> Self {
41 SccInfo {
42 enter,
43 nodes: FxHashSet::default(),
44 exits: FxHashSet::default(),
45 backnodes: FxHashSet::default(),
46 }
47 }
48}
49
50pub trait Scc {
52 fn find_scc(&mut self) {
54 if self.get_size() == 0 {
55 return;
56 }
57 self.find_scc_from(0);
58 }
59
60 fn find_scc_from(&mut self, start: usize) {
62 if start >= self.get_size() {
63 return;
64 }
65 let mut stack = Vec::new();
66 let mut instack = FxHashSet::<usize>::default();
67 let mut dfn = vec![0; self.get_size()];
68 let mut low = vec![0; self.get_size()];
69 let mut time = 1;
70 self.tarjan(
71 start,
72 &mut stack,
73 &mut instack,
74 &mut dfn,
75 &mut low,
76 &mut time,
77 );
78 }
79
80 fn on_scc_found(&mut self, root: usize, scc_components: &[usize]);
82
83 fn get_next(&mut self, root: usize) -> FxHashSet<usize>;
85
86 fn get_size(&mut self) -> usize;
88
89 fn tarjan(
91 &mut self,
92 index: usize,
93 stack: &mut Vec<usize>,
94 instack: &mut FxHashSet<usize>,
95 dfn: &mut Vec<usize>,
96 low: &mut Vec<usize>,
97 time: &mut usize,
98 ) {
99 dfn[index] = *time;
100 low[index] = *time;
101 *time += 1;
102 stack.push(index);
103 instack.insert(index);
104
105 let size = self.get_size();
106 let nexts = self.get_next(index);
107 for next in nexts {
108 if next >= size {
109 continue;
110 }
111 if dfn[next] == 0 {
112 self.tarjan(next, stack, instack, dfn, low, time);
113 low[index] = cmp::min(low[index], low[next]);
114 } else if instack.contains(&next) {
115 low[index] = cmp::min(low[index], dfn[next]);
116 }
117 }
118
119 if dfn[index] == low[index] {
120 let mut component = vec![index];
121 while let Some(top) = stack.pop() {
122 instack.remove(&top);
123 if top == index {
124 break;
125 }
126 component.push(top);
127 }
128 self.on_scc_found(index, &component);
129 }
130 }
131}
132
133#[derive(Debug)]
135pub struct SccTree {
136 pub scc: SccInfo,
137 pub children: Vec<SccTree>,
138}