|
13 | 13 | //! node in the graph. This uses Tarjan's algorithm that completes in
|
14 | 14 | //! O(n) time.
|
15 | 15 |
|
| 16 | +use fx::FxHashSet; |
16 | 17 | use graph::{DirectedGraph, WithNumNodes, WithSuccessors};
|
17 | 18 | use indexed_vec::{Idx, IndexVec};
|
18 | 19 | use std::ops::Range;
|
@@ -113,6 +114,13 @@ struct SccsConstruction<'c, G: DirectedGraph + WithNumNodes + WithSuccessors + '
|
113 | 114 | /// we push it on the stack. When we complete an SCC, we can pop
|
114 | 115 | /// everything off the stack that was found along the way.
|
115 | 116 | successors_stack: Vec<S>,
|
| 117 | + |
| 118 | + /// A set used to strip duplicates. As we accumulate successors |
| 119 | + /// into the successors_stack, we sometimes get duplicate entries. |
| 120 | + /// We use this set to remove those -- we keep it around between |
| 121 | + /// successors to amortize memory allocation costs. |
| 122 | + duplicate_set: FxHashSet<S>, |
| 123 | + |
116 | 124 | scc_data: SccData<S>,
|
117 | 125 | }
|
118 | 126 |
|
@@ -180,6 +188,7 @@ where
|
180 | 188 | ranges: IndexVec::new(),
|
181 | 189 | all_successors: Vec::new(),
|
182 | 190 | },
|
| 191 | + duplicate_set: FxHashSet::default(), |
183 | 192 | };
|
184 | 193 |
|
185 | 194 | let scc_indices = (0..num_nodes)
|
@@ -307,8 +316,16 @@ where
|
307 | 316 | debug_assert_eq!(r, Some(node));
|
308 | 317 |
|
309 | 318 | if min_depth == depth {
|
310 |
| - let scc_index = self.scc_data |
311 |
| - .create_scc(self.successors_stack.drain(successors_len..)); |
| 319 | + // Note that successor stack may have duplicates, so we |
| 320 | + // want to remove those: |
| 321 | + let deduplicated_successors = { |
| 322 | + let duplicate_set = &mut self.duplicate_set; |
| 323 | + duplicate_set.clear(); |
| 324 | + self.successors_stack |
| 325 | + .drain(successors_len..) |
| 326 | + .filter(move |&i| duplicate_set.insert(i)) |
| 327 | + }; |
| 328 | + let scc_index = self.scc_data.create_scc(deduplicated_successors); |
312 | 329 | self.node_states[node] = NodeState::InCycle { scc_index };
|
313 | 330 | WalkReturn::Complete { scc_index }
|
314 | 331 | } else {
|
|
0 commit comments