@@ -257,7 +257,7 @@ impl<'a, G: RandomAccessGraph> Sequential<EventPred> for Seq<'a, G> {
257
257
}
258
258
259
259
impl < ' a , ' b , G : RandomAccessGraph > IntoIterator for & ' a mut Seq < ' b , G > {
260
- type Item = usize ;
260
+ type Item = IterItem ;
261
261
type IntoIter = BfsOrder < ' a , ' b , G > ;
262
262
263
263
fn into_iter ( self ) -> Self :: IntoIter {
@@ -273,6 +273,12 @@ pub struct BfsOrder<'a, 'b, G: RandomAccessGraph> {
273
273
/// This allows initializing the BFS from all orphan nodes without reading
274
274
/// the reverse graph.
275
275
start : usize ,
276
+ /// The current node being visited.
277
+ current_node : usize ,
278
+ /// The current distance from the root.
279
+ distance : usize ,
280
+ /// The successors of the current node, this is done to be able to return
281
+ /// also the predecessor.
276
282
succ : <<G as RandomAccessLabeling >:: Labels < ' a > as IntoIterator >:: IntoIter ,
277
283
/// Number of visited nodes, used to compute the length of the iterator.
278
284
visited_nodes : usize ,
@@ -285,38 +291,77 @@ impl<'a, 'b, G: RandomAccessGraph> BfsOrder<'a, 'b, G> {
285
291
BfsOrder {
286
292
visit,
287
293
start : 0 ,
294
+ current_node : 0 ,
295
+ distance : 0 ,
288
296
succ,
289
297
visited_nodes : 0 ,
290
298
}
291
299
}
292
300
}
293
301
302
+ pub struct IterItem {
303
+ pub parent : usize ,
304
+ pub node : usize ,
305
+ pub distance : usize ,
306
+ }
307
+
294
308
impl < ' a , ' b , G : RandomAccessGraph > Iterator for BfsOrder < ' a , ' b , G > {
295
- type Item = usize ;
309
+ type Item = IterItem ;
296
310
297
- fn next ( & mut self ) -> Option < usize > {
298
- let current_node = match self . visit . queue . pop_front ( ) {
299
- Some ( Some ( node) ) => node. into ( ) ,
300
- _ => {
301
- while self . visit . visited [ self . start ] {
302
- self . start += 1 ;
303
- if self . start >= self . visit . graph . num_nodes ( ) {
304
- return None ;
305
- }
311
+ fn next ( & mut self ) -> Option < Self :: Item > {
312
+ loop {
313
+ // fast path, if the successors iterator is not exhausted, we can just return the next node
314
+ if let Some ( succ) = self . succ . next ( ) {
315
+ if self . visit . visited [ succ] {
316
+ continue ; // skip already visited nodes
306
317
}
307
- self . visit . visited . set ( self . start , true ) ;
308
- self . start
309
- }
310
- } ;
311
-
312
- for succ in self . visit . graph . successors ( current_node) {
313
- if !self . visit . visited [ succ] {
314
- self . visit . queue . push_back ( NonMaxUsize :: new ( succ) ) ;
318
+ // if it's a new node, we visit it and add it to the queue
319
+ // of nodes whose successors we will visit
320
+ self . visit . queue . push_back ( Some (
321
+ NonMaxUsize :: new ( succ) . expect ( "node index should never be usize::MAX" ) ,
322
+ ) ) ;
315
323
self . visit . visited . set ( succ as _ , true ) ;
324
+ self . visited_nodes += 1 ;
325
+ return Some ( IterItem {
326
+ parent : self . current_node ,
327
+ node : succ,
328
+ distance : self . distance ,
329
+ } ) ;
316
330
}
331
+
332
+ // the successors are exhausted, so we need to move to the next node
333
+ self . current_node = match self . visit . queue . pop_front ( ) {
334
+ // if we have a node, we can continue visiting its successors
335
+ Some ( Some ( node) ) => node. into ( ) ,
336
+ // new level separator, so we increment the distance
337
+ Some ( None ) => {
338
+ self . distance += 1 ;
339
+ self . visit . queue . push_back ( None ) ;
340
+ // TODO: this assumes the iter are fuse
341
+ continue ;
342
+ }
343
+ // if the queue is empty, we need to find the next unvisited node
344
+ None => {
345
+ while self . visit . visited [ self . start ] {
346
+ self . start += 1 ;
347
+ if self . start >= self . visit . graph . num_nodes ( ) {
348
+ return None ;
349
+ }
350
+ }
351
+ self . visit . visited . set ( self . start , true ) ;
352
+ self . distance = 0 ; // new visits, new distance
353
+ self . start
354
+ }
355
+ } ;
356
+ // reset the successors iterator for the new current node
357
+ self . succ = self . visit . graph . successors ( self . current_node ) . into_iter ( ) ;
358
+ self . visited_nodes += 1 ;
359
+ return Some ( IterItem {
360
+ parent : self . current_node ,
361
+ node : self . current_node ,
362
+ distance : self . distance ,
363
+ } ) ;
317
364
}
318
- self . visited_nodes += 1 ;
319
- Some ( current_node)
320
365
}
321
366
}
322
367
0 commit comments