@@ -159,6 +159,8 @@ struct SpantreeBuilder<'a, Node: Idx> {
159
159
/// A supernode without a span edge is the root of its component of the
160
160
/// spantree. Nodes that aren't supernodes cannot have a spantree edge.
161
161
span_edges : IndexVec < Node , Option < SpantreeEdge < Node > > > ,
162
+ /// Shared path buffer recycled by all calls to `yank_to_spantree_root`.
163
+ yank_buffer : Vec < Node > ,
162
164
/// An in-progress counter expression for each node. Each expression is
163
165
/// initially empty, and will be filled in as relevant nodes are visited.
164
166
counter_exprs : IndexVec < Node , CounterExprVec < Node > > ,
@@ -171,6 +173,7 @@ impl<'a, Node: Idx> SpantreeBuilder<'a, Node> {
171
173
graph,
172
174
is_unvisited : DenseBitSet :: new_filled ( num_nodes) ,
173
175
span_edges : IndexVec :: from_fn_n ( |_| None , num_nodes) ,
176
+ yank_buffer : vec ! [ ] ,
174
177
counter_exprs : IndexVec :: from_fn_n ( |_| SmallVec :: new ( ) , num_nodes) ,
175
178
}
176
179
}
@@ -192,24 +195,37 @@ impl<'a, Node: Idx> SpantreeBuilder<'a, Node> {
192
195
fn yank_to_spantree_root ( & mut self , this : Node ) {
193
196
debug_assert ! ( self . graph. is_supernode( this) ) ;
194
197
195
- // Temporarily remove this supernode (any any spantree-children) from its
196
- // spantree component, by disconnecting the edge to its spantree-parent.
197
- let Some ( SpantreeEdge { is_reversed, claiming_node, span_parent } ) =
198
- self . span_edges [ this] . take ( )
199
- else {
200
- // This supernode has no spantree-parent edge, so it is already the
201
- // root of its spantree component.
202
- return ;
203
- } ;
204
-
205
- // Recursively make our immediate spantree-parent the root of what's
206
- // left of its component, so that only one more edge rotation is needed.
207
- self . yank_to_spantree_root ( span_parent) ;
208
-
209
- // Recreate the removed edge, but in the opposite direction.
210
- // Now `this` is the root of its spantree component.
211
- self . span_edges [ span_parent] =
212
- Some ( SpantreeEdge { is_reversed : !is_reversed, claiming_node, span_parent : this } ) ;
198
+ // The rotation is done iteratively, by first traversing from `this` to
199
+ // its root and storing the path in a buffer, and then traversing the
200
+ // path buffer backwards to reverse all the edges.
201
+
202
+ // Recycle the same path buffer for all calls to this method.
203
+ let path_buf = & mut self . yank_buffer ;
204
+ path_buf. clear ( ) ;
205
+ path_buf. push ( this) ;
206
+
207
+ // Traverse the spantree until we reach a supernode that has no
208
+ // span-parent, which must be the root.
209
+ let mut curr = this;
210
+ while let & Some ( SpantreeEdge { span_parent, .. } ) = & self . span_edges [ curr] {
211
+ path_buf. push ( span_parent) ;
212
+ curr = span_parent;
213
+ }
214
+
215
+ // For each spantree edge `a -> b` in the path that was just traversed,
216
+ // reverse it to become `a <- b`, while preserving `claiming_node`.
217
+ for & [ a, b] in path_buf. array_windows :: < 2 > ( ) . rev ( ) {
218
+ let SpantreeEdge { is_reversed, claiming_node, span_parent } = self . span_edges [ a]
219
+ . take ( )
220
+ . expect ( "all nodes in the path (except the last) have a `span_parent`" ) ;
221
+ debug_assert_eq ! ( span_parent, b) ;
222
+ debug_assert ! ( self . span_edges[ b] . is_none( ) ) ;
223
+ self . span_edges [ b] =
224
+ Some ( SpantreeEdge { is_reversed : !is_reversed, claiming_node, span_parent : a } ) ;
225
+ }
226
+
227
+ // The result of the rotation is that `this` is now a spantree root.
228
+ debug_assert ! ( self . span_edges[ this] . is_none( ) ) ;
213
229
}
214
230
215
231
/// Must be called exactly once for each node in the balanced-flow graph.
@@ -273,7 +289,7 @@ impl<'a, Node: Idx> SpantreeBuilder<'a, Node> {
273
289
/// Asserts that all nodes have been visited, and returns the computed
274
290
/// counter expressions (made up of physical counters) for each node.
275
291
fn finish ( self ) -> IndexVec < Node , CounterExprVec < Node > > {
276
- let Self { graph, is_unvisited, span_edges, counter_exprs } = self ;
292
+ let Self { graph, is_unvisited, span_edges, yank_buffer : _ , counter_exprs } = self ;
277
293
assert ! ( is_unvisited. is_empty( ) , "some nodes were never visited: {is_unvisited:?}" ) ;
278
294
debug_assert ! (
279
295
span_edges
0 commit comments