@@ -13,7 +13,7 @@ use std::fmt::Debug;
13
13
use std:: ops:: Range ;
14
14
15
15
use rustc_index:: { Idx , IndexSlice , IndexVec } ;
16
- use tracing:: { debug, instrument} ;
16
+ use tracing:: { debug, instrument, trace } ;
17
17
18
18
use crate :: fx:: FxHashSet ;
19
19
use crate :: graph:: vec_graph:: VecGraph ;
@@ -48,6 +48,20 @@ pub trait Annotation: Debug + Copy {
48
48
}
49
49
}
50
50
51
+ /// 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 ) ;
55
+ }
56
+
57
+ /// 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
+ fn annotate_scc ( & mut self , _scc : S , _annotation : ( ) ) { }
63
+ }
64
+
51
65
/// The empty annotation, which does nothing.
52
66
impl Annotation for ( ) {
53
67
fn merge_reached ( self , _other : Self ) -> Self {
@@ -62,23 +76,20 @@ impl Annotation for () {
62
76
/// the index type for the graph nodes and `S` is the index type for
63
77
/// the SCCs. We can map from each node to the SCC that it
64
78
/// participates in, and we also have the successors of each SCC.
65
- pub struct Sccs < N : Idx , S : Idx , A : Annotation = ( ) > {
79
+ pub struct Sccs < N : Idx , S : Idx > {
66
80
/// For each node, what is the SCC index of the SCC to which it
67
81
/// belongs.
68
82
scc_indices : IndexVec < N , S > ,
69
83
70
84
/// Data about all the SCCs.
71
- scc_data : SccData < S , A > ,
85
+ scc_data : SccData < S > ,
72
86
}
73
87
74
88
/// Information about an invidividual SCC node.
75
- struct SccDetails < A : Annotation > {
89
+ struct SccDetails {
76
90
/// For this SCC, the range of `all_successors` where its
77
91
/// successors can be found.
78
92
range : Range < usize > ,
79
-
80
- /// User-specified metadata about the SCC.
81
- annotation : A ,
82
93
}
83
94
84
95
// The name of this struct should discourage you from making it public and leaking
@@ -87,35 +98,29 @@ struct SccDetails<A: Annotation> {
87
98
// is difficult when it's publicly inspectable.
88
99
//
89
100
// Obey the law of Demeter!
90
- struct SccData < S : Idx , A : Annotation > {
101
+ struct SccData < S : Idx > {
91
102
/// Maps SCC indices to their metadata, including
92
103
/// offsets into `all_successors`.
93
- scc_details : IndexVec < S , SccDetails < A > > ,
104
+ scc_details : IndexVec < S , SccDetails > ,
94
105
95
106
/// Contains the successors for all the Sccs, concatenated. The
96
107
/// range of indices corresponding to a given SCC is found in its
97
108
/// `scc_details.range`.
98
109
all_successors : Vec < S > ,
99
110
}
100
111
101
- impl < N : Idx , S : Idx + Ord > Sccs < N , S , ( ) > {
112
+ impl < N : Idx , S : Idx + Ord > Sccs < N , S > {
102
113
/// Compute SCCs without annotations.
103
114
pub fn new ( graph : & impl Successors < Node = N > ) -> Self {
104
- Self :: new_with_annotation ( graph, |_| ( ) )
115
+ Self :: new_with_annotation ( graph, & mut ( ) )
105
116
}
106
- }
107
117
108
- impl < N : Idx , S : Idx + Ord , A : Annotation > Sccs < N , S , A > {
109
118
/// Compute SCCs and annotate them with a user-supplied annotation
110
- pub fn new_with_annotation < F : Fn ( N ) -> A > (
119
+ pub fn new_with_annotation < A : Annotation , AA : Annotations < N , S , A > > (
111
120
graph : & impl Successors < Node = N > ,
112
- to_annotation : F ,
121
+ annotations : & mut AA ,
113
122
) -> Self {
114
- SccsConstruction :: construct ( graph, to_annotation)
115
- }
116
-
117
- pub fn annotation ( & self , scc : S ) -> A {
118
- self . scc_data . annotation ( scc)
123
+ SccsConstruction :: construct ( graph, annotations)
119
124
}
120
125
121
126
pub fn scc_indices ( & self ) -> & IndexSlice < N , S > {
@@ -136,7 +141,13 @@ impl<N: Idx, S: Idx + Ord, A: Annotation> Sccs<N, S, A> {
136
141
pub fn all_sccs ( & self ) -> impl Iterator < Item = S > + ' static {
137
142
( 0 ..self . scc_data . len ( ) ) . map ( S :: new)
138
143
}
139
-
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
+ */
140
151
/// Returns the SCC to which a node `r` belongs.
141
152
pub fn scc ( & self , r : N ) -> S {
142
153
self . scc_indices [ r]
@@ -160,27 +171,27 @@ impl<N: Idx, S: Idx + Ord, A: Annotation> Sccs<N, S, A> {
160
171
}
161
172
}
162
173
163
- impl < N : Idx , S : Idx + Ord , A : Annotation > DirectedGraph for Sccs < N , S , A > {
174
+ impl < N : Idx , S : Idx + Ord > DirectedGraph for Sccs < N , S > {
164
175
type Node = S ;
165
176
166
177
fn num_nodes ( & self ) -> usize {
167
178
self . num_sccs ( )
168
179
}
169
180
}
170
181
171
- impl < N : Idx , S : Idx + Ord , A : Annotation > NumEdges for Sccs < N , S , A > {
182
+ impl < N : Idx , S : Idx + Ord > NumEdges for Sccs < N , S > {
172
183
fn num_edges ( & self ) -> usize {
173
184
self . scc_data . all_successors . len ( )
174
185
}
175
186
}
176
187
177
- impl < N : Idx , S : Idx + Ord , A : Annotation > Successors for Sccs < N , S , A > {
188
+ impl < N : Idx , S : Idx + Ord > Successors for Sccs < N , S > {
178
189
fn successors ( & self , node : S ) -> impl Iterator < Item = Self :: Node > {
179
190
self . successors ( node) . iter ( ) . cloned ( )
180
191
}
181
192
}
182
193
183
- impl < S : Idx , A : Annotation > SccData < S , A > {
194
+ impl < S : Idx > SccData < S > {
184
195
/// Number of SCCs,
185
196
fn len ( & self ) -> usize {
186
197
self . scc_details . len ( )
@@ -192,38 +203,32 @@ impl<S: Idx, A: Annotation> SccData<S, A> {
192
203
}
193
204
194
205
/// Creates a new SCC with `successors` as its successors and
195
- /// the maximum weight of its internal nodes `scc_max_weight` and
196
206
/// returns the resulting index.
197
- fn create_scc ( & mut self , successors : impl IntoIterator < Item = S > , annotation : A ) -> S {
207
+ fn create_scc ( & mut self , successors : impl IntoIterator < Item = S > ) -> S {
198
208
// Store the successors on `scc_successors_vec`, remembering
199
209
// the range of indices.
200
210
let all_successors_start = self . all_successors . len ( ) ;
201
211
self . all_successors . extend ( successors) ;
202
212
let all_successors_end = self . all_successors . len ( ) ;
203
213
204
214
debug ! (
205
- "create_scc({:?}) successors={:?}, annotation={:?} " ,
215
+ "create_scc({:?}) successors={:?}" ,
206
216
self . len( ) ,
207
217
& self . all_successors[ all_successors_start..all_successors_end] ,
208
- annotation
209
218
) ;
210
219
211
220
let range = all_successors_start..all_successors_end;
212
- let metadata = SccDetails { range, annotation } ;
221
+ let metadata = SccDetails { range } ;
213
222
self . scc_details . push ( metadata)
214
223
}
215
-
216
- fn annotation ( & self , scc : S ) -> A {
217
- self . scc_details [ scc] . annotation
218
- }
219
224
}
220
225
221
- struct SccsConstruction < ' c , G , S , A , F >
226
+ struct SccsConstruction < ' c , ' a , G , S , A , AA >
222
227
where
223
228
G : DirectedGraph + Successors ,
224
229
S : Idx ,
225
230
A : Annotation ,
226
- F : Fn ( G :: Node ) -> A ,
231
+ AA : Annotations < G :: Node , S , A > ,
227
232
{
228
233
graph : & ' c G ,
229
234
@@ -247,11 +252,9 @@ where
247
252
/// around between successors to amortize memory allocation costs.
248
253
duplicate_set : FxHashSet < S > ,
249
254
250
- scc_data : SccData < S , A > ,
255
+ scc_data : SccData < S > ,
251
256
252
- /// A function that constructs an initial SCC annotation
253
- /// out of a single node.
254
- to_annotation : F ,
257
+ annotations : & ' a mut AA ,
255
258
}
256
259
257
260
#[ derive( Copy , Clone , Debug ) ]
@@ -299,12 +302,12 @@ enum WalkReturn<S, A> {
299
302
Complete { scc_index : S , annotation : A } ,
300
303
}
301
304
302
- impl < ' c , G , S , A , F > SccsConstruction < ' c , G , S , A , F >
305
+ impl < ' c , ' a , G , S , A , AA > SccsConstruction < ' c , ' a , G , S , A , AA >
303
306
where
304
307
G : DirectedGraph + Successors ,
305
308
S : Idx ,
306
- F : Fn ( G :: Node ) -> A ,
307
309
A : Annotation ,
310
+ AA : Annotations < G :: Node , S , A > ,
308
311
{
309
312
/// Identifies SCCs in the graph `G` and computes the resulting
310
313
/// DAG. This uses a variant of [Tarjan's
@@ -320,7 +323,7 @@ where
320
323
/// Additionally, we keep track of a current annotation of the SCC.
321
324
///
322
325
/// [wikipedia]: https://bit.ly/2EZIx84
323
- fn construct ( graph : & ' c G , to_annotation : F ) -> Sccs < G :: Node , S , A > {
326
+ fn construct ( graph : & ' c G , annotations : & ' a mut AA ) -> Sccs < G :: Node , S > {
324
327
let num_nodes = graph. num_nodes ( ) ;
325
328
326
329
let mut this = Self {
@@ -330,7 +333,7 @@ where
330
333
successors_stack : Vec :: new ( ) ,
331
334
scc_data : SccData { scc_details : IndexVec :: new ( ) , all_successors : Vec :: new ( ) } ,
332
335
duplicate_set : FxHashSet :: default ( ) ,
333
- to_annotation ,
336
+ annotations ,
334
337
} ;
335
338
336
339
let scc_indices = graph
@@ -408,7 +411,7 @@ where
408
411
// a potentially derived version of the root state for non-root nodes in the chain.
409
412
let ( root_state, assigned_state) = {
410
413
loop {
411
- debug ! ( "find_state(r = {node:?} in state {:?})" , self . node_states[ node] ) ;
414
+ trace ! ( "find_state(r = {node:?} in state {:?})" , self . node_states[ node] ) ;
412
415
match self . node_states [ node] {
413
416
// This must have been the first and only state since it is unexplored*;
414
417
// no update needed! * Unless there is a bug :')
@@ -482,7 +485,7 @@ where
482
485
if previous_node == node {
483
486
return root_state;
484
487
}
485
- debug ! ( "Compressing {node:?} down to {previous_node:?} with state {assigned_state:?}" ) ;
488
+ trace ! ( "Compressing {node:?} down to {previous_node:?} with state {assigned_state:?}" ) ;
486
489
487
490
// Update to previous node in the link.
488
491
match self . node_states [ previous_node] {
@@ -507,9 +510,9 @@ where
507
510
/// Call this method when `inspect_node` has returned `None`. Having the
508
511
/// caller decide avoids mutual recursion between the two methods and allows
509
512
/// us to maintain an allocated stack for nodes on the path between calls.
510
- #[ instrument( skip( self , initial) , level = "debug " ) ]
513
+ #[ instrument( skip( self , initial) , level = "trace " ) ]
511
514
fn walk_unvisited_node ( & mut self , initial : G :: Node ) -> WalkReturn < S , A > {
512
- debug ! ( "Walk unvisited node: {initial:?}" ) ;
515
+ trace ! ( "Walk unvisited node: {initial:?}" ) ;
513
516
struct VisitingNodeFrame < G : DirectedGraph , Successors , A > {
514
517
node : G :: Node ,
515
518
successors : Option < Successors > ,
@@ -537,7 +540,7 @@ where
537
540
successors_len: 0 ,
538
541
min_cycle_root: initial,
539
542
successor_node: initial,
540
- current_component_annotation: ( self . to_annotation ) ( initial) ,
543
+ current_component_annotation: self . annotations . new ( initial) ,
541
544
} ] ;
542
545
543
546
let mut return_value = None ;
@@ -556,19 +559,15 @@ where
556
559
let node = * node;
557
560
let depth = * depth;
558
561
559
- // node is definitely in the current component, add it to the annotation.
560
- if node != initial {
561
- current_component_annotation. update_scc ( ( self . to_annotation ) ( node) ) ;
562
- }
563
- debug ! (
562
+ trace ! (
564
563
"Visiting {node:?} at depth {depth:?}, annotation: {current_component_annotation:?}"
565
564
) ;
566
565
567
566
let successors = match successors {
568
567
Some ( successors) => successors,
569
568
None => {
570
569
// This None marks that we still have the initialize this node's frame.
571
- debug ! ( ?depth, ?node) ;
570
+ trace ! ( ?depth, ?node) ;
572
571
573
572
debug_assert_matches ! ( self . node_states[ node] , NodeState :: NotVisited ) ;
574
573
@@ -598,7 +597,7 @@ where
598
597
return_value. take ( ) . into_iter ( ) . map ( |walk| ( * successor_node, Some ( walk) ) ) ;
599
598
600
599
let successor_walk = successors. map ( |successor_node| {
601
- debug ! ( ?node, ?successor_node) ;
600
+ trace ! ( ?node, ?successor_node) ;
602
601
( successor_node, self . inspect_node ( successor_node) )
603
602
} ) ;
604
603
for ( successor_node, walk) in returned_walk. chain ( successor_walk) {
@@ -609,13 +608,13 @@ where
609
608
min_depth : successor_min_depth,
610
609
annotation : successor_annotation,
611
610
} ) => {
612
- debug ! (
611
+ trace ! (
613
612
"Cycle found from {node:?}, minimum depth: {successor_min_depth:?}, annotation: {successor_annotation:?}"
614
613
) ;
615
614
// Track the minimum depth we can reach.
616
615
assert ! ( successor_min_depth <= depth) ;
617
616
if successor_min_depth < * min_depth {
618
- debug ! ( ?node, ?successor_min_depth) ;
617
+ trace ! ( ?node, ?successor_min_depth) ;
619
618
* min_depth = successor_min_depth;
620
619
* min_cycle_root = successor_node;
621
620
}
@@ -627,20 +626,20 @@ where
627
626
scc_index : successor_scc_index,
628
627
annotation : successor_annotation,
629
628
} ) => {
630
- debug ! (
629
+ trace ! (
631
630
"Complete; {node:?} is root of complete-visited SCC idx {successor_scc_index:?} with annotation {successor_annotation:?}"
632
631
) ;
633
632
// Push the completed SCC indices onto
634
633
// the `successors_stack` for later.
635
- debug ! ( ?node, ?successor_scc_index) ;
634
+ trace ! ( ?node, ?successor_scc_index) ;
636
635
successors_stack. push ( successor_scc_index) ;
637
636
current_component_annotation. update_reachable ( successor_annotation) ;
638
637
}
639
638
// `node` has no more (direct) successors; search recursively.
640
639
None => {
641
640
let depth = depth + 1 ;
642
- debug ! ( "Recursing down into {successor_node:?} at depth {depth:?}" ) ;
643
- debug ! ( ?depth, ?successor_node) ;
641
+ trace ! ( "Recursing down into {successor_node:?} at depth {depth:?}" ) ;
642
+ trace ! ( ?depth, ?successor_node) ;
644
643
// Remember which node the return value will come from.
645
644
frame. successor_node = successor_node;
646
645
// Start a new stack frame, then step into it.
@@ -652,14 +651,14 @@ where
652
651
min_depth : depth,
653
652
min_cycle_root : successor_node,
654
653
successor_node,
655
- current_component_annotation : ( self . to_annotation ) ( successor_node) ,
654
+ current_component_annotation : self . annotations . new ( successor_node) ,
656
655
} ) ;
657
656
continue ' recurse;
658
657
}
659
658
}
660
659
}
661
660
662
- debug ! ( "Finished walk from {node:?} with annotation: {current_component_annotation:?}" ) ;
661
+ trace ! ( "Finished walk from {node:?} with annotation: {current_component_annotation:?}" ) ;
663
662
664
663
// Completed walk, remove `node` from the stack.
665
664
let r = self . node_stack . pop ( ) ;
@@ -691,8 +690,9 @@ where
691
690
692
691
debug ! ( "Creating SCC rooted in {node:?} with successor {:?}" , frame. successor_node) ;
693
692
694
- let scc_index =
695
- self . scc_data . create_scc ( deduplicated_successors, current_component_annotation) ;
693
+ let scc_index = self . scc_data . create_scc ( deduplicated_successors) ;
694
+
695
+ self . annotations . annotate_scc ( scc_index, current_component_annotation) ;
696
696
697
697
self . node_states [ node] =
698
698
NodeState :: InCycle { scc_index, annotation : current_component_annotation } ;
0 commit comments