@@ -119,6 +119,11 @@ impl<'a, G: RandomAccessGraph> Seq<'a, G> {
119
119
/// * `graph`: an immutable reference to the graph to visit.
120
120
pub fn new ( graph : & ' a G ) -> Self {
121
121
let num_nodes = graph. num_nodes ( ) ;
122
+ assert_ne ! (
123
+ num_nodes,
124
+ usize :: MAX ,
125
+ "The BFS Seq visit cannot be used on graphs with usize::MAX nodes."
126
+ ) ;
122
127
Self {
123
128
graph,
124
129
visited : BitVec :: new ( num_nodes) ,
@@ -257,7 +262,7 @@ impl<'a, G: RandomAccessGraph> Sequential<EventPred> for Seq<'a, G> {
257
262
}
258
263
259
264
impl < ' a , ' b , G : RandomAccessGraph > IntoIterator for & ' a mut Seq < ' b , G > {
260
- type Item = IterItem ;
265
+ type Item = IterEvent ;
261
266
type IntoIter = BfsOrder < ' a , ' b , G > ;
262
267
263
268
fn into_iter ( self ) -> Self :: IntoIter {
@@ -268,17 +273,15 @@ impl<'a, 'b, G: RandomAccessGraph> IntoIterator for &'a mut Seq<'b, G> {
268
273
/// Iterator on **all nodes** of the graph in a BFS order
269
274
pub struct BfsOrder < ' a , ' b , G : RandomAccessGraph > {
270
275
visit : & ' a mut Seq < ' b , G > ,
271
- /// If the queue is empty, resume the BFS from that node.
272
- ///
273
- /// This allows initializing the BFS from all orphan nodes without reading
274
- /// the reverse graph.
275
- start : usize ,
276
- /// The current node being visited.
277
- current_node : usize ,
276
+ /// The root of the current visit.
277
+ root : usize ,
278
+ /// The current node being enumerated, i.e. the parent of the nodes returned
279
+ /// by `succ`
280
+ parent : usize ,
278
281
/// The current distance from the root.
279
282
distance : usize ,
280
- /// The successors of the current node, this is done to be able to return
281
- /// also the predecessor .
283
+ /// The successors of the `parent` node, this is done to be able to return
284
+ /// also the parent .
282
285
succ : <<G as RandomAccessLabeling >:: Labels < ' a > as IntoIterator >:: IntoIter ,
283
286
/// Number of visited nodes, used to compute the length of the iterator.
284
287
visited_nodes : usize ,
@@ -290,81 +293,114 @@ impl<'a, 'b, G: RandomAccessGraph> BfsOrder<'a, 'b, G> {
290
293
let succ = visit. graph . successors ( 0 ) . into_iter ( ) ;
291
294
BfsOrder {
292
295
visit,
293
- start : 0 ,
294
- current_node : 0 ,
296
+ root : 0 ,
297
+ parent : 0 ,
295
298
distance : 0 ,
296
299
succ,
297
300
visited_nodes : 0 ,
298
301
}
299
302
}
300
303
}
301
304
302
- pub struct IterItem {
305
+ /// An event returned by the BFS iterator [`BfsOrder`].
306
+ pub struct IterEvent {
307
+ /// The root of the current visit
308
+ pub root : usize ,
309
+ /// The parent of the current node
303
310
pub parent : usize ,
311
+ /// The current node being visited
304
312
pub node : usize ,
313
+ /// The distance of the current node from the root
305
314
pub distance : usize ,
306
315
}
307
316
308
317
impl < ' a , ' b , G : RandomAccessGraph > Iterator for BfsOrder < ' a , ' b , G > {
309
- type Item = IterItem ;
318
+ type Item = IterEvent ;
310
319
311
320
fn next ( & mut self ) -> Option < Self :: Item > {
321
+ // handle the first node separately, as we need to pre-fill the succ
322
+ // iterator to be able to implement `new`
323
+ if self . visited_nodes == 0 {
324
+ self . visited_nodes += 1 ;
325
+ self . visit . visited . set ( self . root , true ) ;
326
+ self . visit . queue . push_back ( None ) ;
327
+ return Some ( IterEvent {
328
+ root : self . root ,
329
+ parent : self . root ,
330
+ node : self . root ,
331
+ distance : 0 ,
332
+ } ) ;
333
+ }
312
334
loop {
313
335
// fast path, if the successors iterator is not exhausted, we can just return the next node
314
- if let Some ( succ) = self . succ . next ( ) {
336
+ for succ in & mut self . succ {
315
337
if self . visit . visited [ succ] {
316
338
continue ; // skip already visited nodes
317
339
}
340
+
318
341
// if it's a new node, we visit it and add it to the queue
319
342
// 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
- ) ) ;
343
+ let node = NonMaxUsize :: new ( succ) ;
344
+ debug_assert ! ( node. is_some( ) , "Node index should never be usize::MAX" ) ;
345
+ let node = unsafe { node. unwrap_unchecked ( ) } ;
346
+ self . visit . queue . push_back ( Some ( node) ) ;
347
+
323
348
self . visit . visited . set ( succ as _ , true ) ;
324
349
self . visited_nodes += 1 ;
325
- return Some ( IterItem {
326
- parent : self . current_node ,
350
+ return Some ( IterEvent {
351
+ root : self . root ,
352
+ parent : self . parent ,
327
353
node : succ,
328
354
distance : self . distance ,
329
355
} ) ;
330
356
}
331
357
332
358
// the successors are exhausted, so we need to move to the next node
333
- self . current_node = loop {
334
- match self . visit . queue . pop_front ( ) {
359
+ loop {
360
+ match self . visit . queue . pop_front ( ) . expect (
361
+ "Queue should never be empty here, as we always add a level separator after the first node." ,
362
+ ) {
335
363
// if we have a node, we can continue visiting its successors
336
- Some ( Some ( node) ) => break node. into ( ) ,
364
+ Some ( node) => {
365
+ self . parent = node. into ( ) ;
366
+ // reset the successors iterator for the new current node
367
+ self . succ = self . visit . graph . successors ( self . parent ) . into_iter ( ) ;
368
+ break ;
369
+ }
337
370
// new level separator, so we increment the distance
338
- Some ( None ) => {
339
- self . distance += 1 ;
371
+ None => {
340
372
// if the queue is not empty, we need to add a new level separator
341
373
if !self . visit . queue . is_empty ( ) {
374
+ self . distance += 1 ;
342
375
self . visit . queue . push_back ( None ) ;
376
+ continue ;
343
377
}
344
- continue ;
345
- }
346
- // if the queue is empty, we need to find the next unvisited node
347
- None => {
348
- while self . visit . visited [ self . start ] {
349
- self . start += 1 ;
350
- if self . start >= self . visit . graph . num_nodes ( ) {
378
+ self . distance = 0 ; // new visits, new distance
379
+
380
+ // the queue is empty, we need to find the next unvisited node
381
+ while self . visit . visited [ self . root ] {
382
+ self . root += 1 ;
383
+ if self . root >= self . visit . graph . num_nodes ( ) {
351
384
return None ;
352
385
}
353
386
}
354
- self . visit . visited . set ( self . start , true ) ;
355
- self . distance = 0 ; // new visits, new distance
356
- break self . start
387
+
388
+ self . visited_nodes += 1 ;
389
+ self . visit . visited . set ( self . root , true ) ;
390
+ self . visit . queue . push_back ( None ) ;
391
+
392
+ self . parent = self . root ;
393
+ self . succ = self . visit . graph . successors ( self . root ) . into_iter ( ) ;
394
+
395
+ return Some ( IterEvent {
396
+ root : self . root ,
397
+ parent : self . root ,
398
+ node : self . root ,
399
+ distance : self . distance ,
400
+ } ) ;
357
401
}
358
402
}
359
- } ;
360
- // reset the successors iterator for the new current node
361
- self . succ = self . visit . graph . successors ( self . current_node ) . into_iter ( ) ;
362
- self . visited_nodes += 1 ;
363
- return Some ( IterItem {
364
- parent : self . current_node ,
365
- node : self . current_node ,
366
- distance : self . distance ,
367
- } ) ;
403
+ }
368
404
}
369
405
}
370
406
}
0 commit comments