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