10
10
11
11
use std:: assert_matches:: debug_assert_matches;
12
12
use std:: fmt:: Debug ;
13
+ use std:: marker:: PhantomData ;
13
14
use std:: ops:: Range ;
14
15
15
16
use rustc_index:: { Idx , IndexSlice , IndexVec } ;
@@ -49,13 +50,20 @@ pub trait Annotation: Debug + Copy {
49
50
}
50
51
51
52
/// An accumulator for annotations.
52
- pub trait Annotations < N : Idx , S : Idx , A : Annotation > {
53
- fn new ( & self , element : N ) -> A ;
54
- fn annotate_scc ( & mut self , scc : S , annotation : A ) ;
53
+ pub trait Annotations < N : Idx > {
54
+ type Ann : Annotation ;
55
+ type SccIdx : Idx + Ord ;
56
+
57
+ fn new ( & self , element : N ) -> Self :: Ann ;
58
+ fn annotate_scc ( & mut self , scc : Self :: SccIdx , annotation : Self :: Ann ) ;
55
59
}
56
60
57
61
/// The nil annotation accumulator, which does nothing.
58
- impl < N : Idx , S : Idx > Annotations < N , S , ( ) > for ( ) {
62
+ struct NoAnnotations < S : Idx + Ord > ( PhantomData < S > ) ;
63
+
64
+ impl < N : Idx , S : Idx + Ord > Annotations < N > for NoAnnotations < S > {
65
+ type SccIdx = S ;
66
+ type Ann = ( ) ;
59
67
fn new ( & self , _element : N ) -> ( ) {
60
68
( )
61
69
}
@@ -112,13 +120,13 @@ struct SccData<S: Idx> {
112
120
impl < N : Idx , S : Idx + Ord > Sccs < N , S > {
113
121
/// Compute SCCs without annotations.
114
122
pub fn new ( graph : & impl Successors < Node = N > ) -> Self {
115
- Self :: new_with_annotation ( graph, & mut ( ) )
123
+ Self :: new_with_annotation ( graph, & mut NoAnnotations ( PhantomData :: < S > ) )
116
124
}
117
125
118
126
/// Compute SCCs and annotate them with a user-supplied annotation
119
- pub fn new_with_annotation < A : Annotation , AA : Annotations < N , S , A > > (
127
+ pub fn new_with_annotation < A : Annotations < N , SccIdx = S > > (
120
128
graph : & impl Successors < Node = N > ,
121
- annotations : & mut AA ,
129
+ annotations : & mut A ,
122
130
) -> Self {
123
131
SccsConstruction :: construct ( graph, annotations)
124
132
}
@@ -141,13 +149,7 @@ impl<N: Idx, S: Idx + Ord> Sccs<N, S> {
141
149
pub fn all_sccs ( & self ) -> impl Iterator < Item = S > + ' static {
142
150
( 0 ..self . scc_data . len ( ) ) . map ( S :: new)
143
151
}
144
- /*
145
- /// Returns an iterator over the SCC annotations in the graph
146
- /// The order is the same as `all_sccs()`, dependency order.
147
- pub fn all_annotations(&self, annotations: &A) -> impl Iterator<Item = (S, A)> + use<'_, N, S, A> {
148
- self.all_sccs().map(|scc| (scc, self.annotation(scc)))
149
- }
150
- */
152
+
151
153
/// Returns the SCC to which a node `r` belongs.
152
154
pub fn scc ( & self , r : N ) -> S {
153
155
self . scc_indices [ r]
@@ -223,19 +225,17 @@ impl<S: Idx> SccData<S> {
223
225
}
224
226
}
225
227
226
- struct SccsConstruction < ' c , ' a , G , S , A , AA >
228
+ struct SccsConstruction < ' c , ' a , G , A >
227
229
where
228
230
G : DirectedGraph + Successors ,
229
- S : Idx ,
230
- A : Annotation ,
231
- AA : Annotations < G :: Node , S , A > ,
231
+ A : Annotations < G :: Node > ,
232
232
{
233
233
graph : & ' c G ,
234
234
235
235
/// The state of each node; used during walk to record the stack
236
236
/// and after walk to record what cycle each node ended up being
237
237
/// in.
238
- node_states : IndexVec < G :: Node , NodeState < G :: Node , S , A > > ,
238
+ node_states : IndexVec < G :: Node , NodeState < G :: Node , A :: SccIdx , A :: Ann > > ,
239
239
240
240
/// The stack of nodes that we are visiting as part of the DFS.
241
241
node_stack : Vec < G :: Node > ,
@@ -244,21 +244,21 @@ where
244
244
/// position in this stack, and when we encounter a successor SCC,
245
245
/// we push it on the stack. When we complete an SCC, we can pop
246
246
/// everything off the stack that was found along the way.
247
- successors_stack : Vec < S > ,
247
+ successors_stack : Vec < A :: SccIdx > ,
248
248
249
249
/// A set used to strip duplicates. As we accumulate successors
250
250
/// into the successors_stack, we sometimes get duplicate entries.
251
251
/// We use this set to remove those -- we also keep its storage
252
252
/// around between successors to amortize memory allocation costs.
253
- duplicate_set : FxHashSet < S > ,
253
+ duplicate_set : FxHashSet < A :: SccIdx > ,
254
254
255
- scc_data : SccData < S > ,
255
+ scc_data : SccData < A :: SccIdx > ,
256
256
257
- annotations : & ' a mut AA ,
257
+ annotations : & ' a mut A ,
258
258
}
259
259
260
260
#[ derive( Copy , Clone , Debug ) ]
261
- enum NodeState < N , S , A > {
261
+ enum NodeState < N , S , A : Annotation > {
262
262
/// This node has not yet been visited as part of the DFS.
263
263
///
264
264
/// After SCC construction is complete, this state ought to be
@@ -289,7 +289,7 @@ enum NodeState<N, S, A> {
289
289
290
290
/// The state of walking a given node.
291
291
#[ derive( Copy , Clone , Debug ) ]
292
- enum WalkReturn < S , A > {
292
+ enum WalkReturn < S , A : Annotation > {
293
293
/// The walk found a cycle, but the entire component is not known to have
294
294
/// been fully walked yet. We only know the minimum depth of this
295
295
/// component in a minimum spanning tree of the graph. This component
@@ -302,12 +302,10 @@ enum WalkReturn<S, A> {
302
302
Complete { scc_index : S , annotation : A } ,
303
303
}
304
304
305
- impl < ' c , ' a , G , S , A , AA > SccsConstruction < ' c , ' a , G , S , A , AA >
305
+ impl < ' c , ' a , G , A > SccsConstruction < ' c , ' a , G , A >
306
306
where
307
307
G : DirectedGraph + Successors ,
308
- S : Idx ,
309
- A : Annotation ,
310
- AA : Annotations < G :: Node , S , A > ,
308
+ A : Annotations < G :: Node > ,
311
309
{
312
310
/// Identifies SCCs in the graph `G` and computes the resulting
313
311
/// DAG. This uses a variant of [Tarjan's
@@ -323,7 +321,7 @@ where
323
321
/// Additionally, we keep track of a current annotation of the SCC.
324
322
///
325
323
/// [wikipedia]: https://bit.ly/2EZIx84
326
- fn construct ( graph : & ' c G , annotations : & ' a mut AA ) -> Sccs < G :: Node , S > {
324
+ fn construct ( graph : & ' c G , annotations : & ' a mut A ) -> Sccs < G :: Node , A :: SccIdx > {
327
325
let num_nodes = graph. num_nodes ( ) ;
328
326
329
327
let mut this = Self {
@@ -349,7 +347,7 @@ where
349
347
Sccs { scc_indices, scc_data : this. scc_data }
350
348
}
351
349
352
- fn start_walk_from ( & mut self , node : G :: Node ) -> WalkReturn < S , A > {
350
+ fn start_walk_from ( & mut self , node : G :: Node ) -> WalkReturn < A :: SccIdx , A :: Ann > {
353
351
self . inspect_node ( node) . unwrap_or_else ( || self . walk_unvisited_node ( node) )
354
352
}
355
353
@@ -365,7 +363,7 @@ where
365
363
/// Otherwise, we are looking at a node that has already been
366
364
/// completely visited. We therefore return `WalkReturn::Complete`
367
365
/// with its associated SCC index.
368
- fn inspect_node ( & mut self , node : G :: Node ) -> Option < WalkReturn < S , A > > {
366
+ fn inspect_node ( & mut self , node : G :: Node ) -> Option < WalkReturn < A :: SccIdx , A :: Ann > > {
369
367
Some ( match self . find_state ( node) {
370
368
NodeState :: InCycle { scc_index, annotation } => {
371
369
WalkReturn :: Complete { scc_index, annotation }
@@ -388,7 +386,7 @@ where
388
386
/// of `r2` (and updates `r` to reflect current result). This is
389
387
/// basically the "find" part of a standard union-find algorithm
390
388
/// (with path compression).
391
- fn find_state ( & mut self , mut node : G :: Node ) -> NodeState < G :: Node , S , A > {
389
+ fn find_state ( & mut self , mut node : G :: Node ) -> NodeState < G :: Node , A :: SccIdx , A :: Ann > {
392
390
// To avoid recursion we temporarily reuse the `parent` of each
393
391
// InCycleWith link to encode a downwards link while compressing
394
392
// the path. After we have found the root or deepest node being
@@ -511,7 +509,7 @@ where
511
509
/// caller decide avoids mutual recursion between the two methods and allows
512
510
/// us to maintain an allocated stack for nodes on the path between calls.
513
511
#[ instrument( skip( self , initial) , level = "trace" ) ]
514
- fn walk_unvisited_node ( & mut self , initial : G :: Node ) -> WalkReturn < S , A > {
512
+ fn walk_unvisited_node ( & mut self , initial : G :: Node ) -> WalkReturn < A :: SccIdx , A :: Ann > {
515
513
trace ! ( "Walk unvisited node: {initial:?}" ) ;
516
514
struct VisitingNodeFrame < G : DirectedGraph , Successors , A > {
517
515
node : G :: Node ,
0 commit comments