@@ -196,6 +196,10 @@ where
196196 }
197197}
198198
199+ /// A cycle detector that builds up paths by appending elements to it.
200+ /// Path elements are stored in a shared arena that must be provided
201+ /// when calling methods, so that cloning the cycle detector itself is
202+ /// cheap.
199203#[ derive( Clone ) ]
200204pub struct AppendingCycleDetector < H > {
201205 appendages : List < InternedPathOrHandle < H > > ,
@@ -251,6 +255,13 @@ where
251255
252256 let mut maybe_cyclic_path = None ;
253257 let mut remaining_appendages = self . appendages ;
258+ // Unlike the stored appendages, which are stored in a shared arena, we use a _local_
259+ // buffer to collect the prefix appendages that we collect for possible cycles. This is
260+ // to prevent adding elements to the shared arena for every invocation of this method,
261+ // because they would remain in the arena after the method returns. We take care to
262+ // minimize (re)allocations by (a) only allocating when a possible cycle is detected,
263+ // (b) reserving all necessary space before adding elements, and (c) reusing the buffer
264+ // between loop iterations.
254265 let mut prefix_appendages = Vec :: new ( ) ;
255266 loop {
256267 // find cycle length
@@ -270,7 +281,7 @@ where
270281 }
271282 }
272283
273- // collect prefix elements
284+ // collect prefix elements (reversing their order)
274285 prefix_appendages. clear ( ) ;
275286 prefix_appendages. reserve ( cycle_length) ;
276287 for _ in 0 ..cycle_length {
0 commit comments