@@ -492,61 +492,55 @@ impl fmt::Display for DecisionErrorType {
492
492
493
493
//------------ Helpers -------------------------------------------------------
494
494
495
- pub fn preferred < ' a , OS : OrdStrat > (
496
- a : OrdRoute < ' a , OS > , b : OrdRoute < ' a , OS >
497
- ) -> OrdRoute < ' a , OS > {
495
+
496
+ /// Returns the preferred route.
497
+ ///
498
+ /// Note this method works on anything `T: Ord` and is thus not limited to
499
+ /// `OrdRoute`. Hence one can pass in a tuple of `(OrdRoute, L)` as long as
500
+ /// `L` implements `Ord`, to include and get back any local value like an ID.
501
+ /// This is consistent with [`fn best`] and [`fn best_backup_generic`].
502
+ pub fn preferred < T : Ord > ( a : T , b : T ) -> T {
498
503
cmp:: min ( a, b)
499
504
}
500
505
501
506
/// Selects the preferred ('best') route.
502
- pub fn best < ' a , T , I , OS > ( it : I ) -> Option < T >
507
+ ///
508
+ /// Note this method works on an iterator yielding anything `T: Ord`, so not
509
+ /// limited to `OrdRoute`. It is in that sense consistent with [`fn
510
+ /// best_backup_generic`], i.e. one can pass in tuples of `OrdRoute` and
511
+ /// something else that implements `Ord`.
512
+ pub fn best < T , I > ( it : I ) -> Option < T >
503
513
where
504
514
T : Ord ,
505
515
I : Iterator < Item = T > ,
506
- T : core:: borrow:: Borrow < OrdRoute < ' a , OS > >
507
516
{
508
517
it. min ( )
509
518
}
510
519
511
- /*
512
- pub fn best_with_strat<'a, OS, AltOS, I, T1>(it: I)
513
- -> Option<OrdRoute<'a, AltOS>>
514
- where
515
- OS: 'a + OrdStrat,
516
- AltOS: 'a + OrdStrat,
517
- I: Iterator<Item = T1>,
518
- T1: core::borrow::Borrow<OrdRoute<'a, OS>>
519
- {
520
- it.map(|r| r.into_strat()).min()
521
- }
522
- */
523
-
524
-
525
- // XXX would this be convenient?
526
- pub fn best_alt < ' a , OS : OrdStrat > (
527
- _pamaps : impl Iterator < Item = & ' a PaMap > ,
528
- _tiebreakers : impl Iterator < Item = TiebreakerInfo >
529
- ) -> Option < OrdRoute < ' a , OS > > {
530
- unimplemented ! ( )
531
- }
532
-
533
- /// Returns the 'best' and second-best path.
520
+ /// Alternative, generic version of `fn best_backup`.
534
521
///
535
- /// If the iterator passed in contains no paths, `(None, None)` is returned.
536
- /// If the iterator yields only a single item, that will be the 'best' path,
537
- /// and the 'backup' will be None, i.e. `(Some(best), None)`.
522
+ /// This method takes any iterator yielding items implementing Ord. As such,
523
+ /// it has little to do with routes or path selection per se.
538
524
///
539
- /// In all other cases (an iterator yielding two or more non-identical
540
- /// values), both members of the tuple should be `Some(..)`.
541
- ///
542
- /// The returned 'best' path is the same as the path returned by [`fn best`].
543
- pub fn best_backup < ' a , OS , T > (
544
- it : impl Iterator < Item = T >
545
- ) -> ( Option < T > , Option < T > )
546
- where
547
- OS : OrdStrat ,
548
- T : Ord ,
549
- T : core:: borrow:: Borrow < OrdRoute < ' a , OS > >
525
+ /// Note that because of this genericness, we have no access to methods or
526
+ /// members of `T`, and thus are unable to compare actual contents such as a
527
+ /// `PaMap` or the `TiebreakerInfo` when comparing `OrdRoute`s. This means the
528
+ /// method can not check for any duplicate route information between `T`s, and
529
+ /// really only order them. The caller therefore has to make sure to pass in
530
+ /// an iterator that does not yield any duplicate routes.
531
+ ///
532
+ /// This method enables the caller to attach additional information, as long
533
+ /// as it implements `Ord`. For example, one can pass in an iterator over
534
+ /// tuples of `OrdRoute` and something else. As long as the `OrdRoute` is the
535
+ /// first member of that tuple and no duplicates are yielded from the
536
+ /// iterator, the additional information is not used in the ordering process
537
+ /// but is returned together with the 'best' and 'backup' tuples. This can be
538
+ /// useful when the caller needs to relate routes to local IDs or something
539
+ /// alike.
540
+ pub fn best_backup_generic < I , T > ( it : I ) -> ( Option < T > , Option < T > )
541
+ where
542
+ I : Iterator < Item = T > ,
543
+ T : Ord
550
544
{
551
545
let mut best = None ;
552
546
let mut backup = None ;
@@ -564,6 +558,57 @@ pub fn best_backup<'a, OS, T>(
564
558
// put it back in
565
559
best = Some ( cur_best) ;
566
560
561
+ // c is not better than best, now check backup
562
+ match backup. take ( ) {
563
+ None => { backup = Some ( c) ; }
564
+ Some ( cur_backup) => {
565
+ if c < cur_backup {
566
+ // c is preferred over current backup
567
+ backup = Some ( c) ;
568
+ } else {
569
+ // put it back in
570
+ backup = Some ( cur_backup) ;
571
+ }
572
+
573
+ }
574
+ }
575
+ }
576
+ }
577
+ }
578
+
579
+ ( best, backup)
580
+ }
581
+
582
+
583
+ // Attaches an index to a (generic) T, only used internally in _best_backup.
584
+ type RouteWithIndex < T > = ( usize , T ) ;
585
+
586
+ // Internal version doing the heavy lifting for both best_backup and
587
+ // best_backup_position. Returns both the routes themselves (T) and their
588
+ // index (usize).
589
+ fn _best_backup < ' a , I , T , OS > ( it : I )
590
+ -> ( Option < RouteWithIndex < T > > , Option < RouteWithIndex < T > > )
591
+ where
592
+ OS : OrdStrat ,
593
+ I : Iterator < Item = T > ,
594
+ T : Ord + core:: borrow:: Borrow < OrdRoute < ' a , OS > >
595
+ {
596
+ let mut best: Option < RouteWithIndex < T > > = None ;
597
+ let mut backup: Option < RouteWithIndex < T > > = None ;
598
+
599
+ for ( idx, c) in it. enumerate ( ) {
600
+ match best. take ( ) {
601
+ None => { best = Some ( ( idx, c) ) ; continue }
602
+ Some ( ( idx_best, cur_best) ) => {
603
+ if c < cur_best {
604
+ // c is preferred over current best
605
+ best = Some ( ( idx, c) ) ;
606
+ backup = Some ( ( idx_best, cur_best) ) ;
607
+ continue ;
608
+ }
609
+ // put it back in
610
+ best = Some ( ( idx_best, cur_best) ) ;
611
+
567
612
// c is not better than best, now check backup
568
613
match backup. take ( ) {
569
614
None => {
@@ -580,24 +625,26 @@ pub fn best_backup<'a, OS, T>(
580
625
// though the actual path attributes differ.
581
626
//
582
627
583
- // Best is always Some at this point, unwrap is safe.
584
- if best. as_ref ( ) . unwrap ( ) . borrow ( ) . inner ( ) != c. borrow ( ) . inner ( ) {
585
- backup = Some ( c) ;
586
- } }
587
- Some ( cur_backup) => {
628
+ // `best` is always Some(..) at this point, but we do
629
+ // an `if let` instead of an `unwrap` anyway.
630
+ if let Some ( ( _, cur_best) ) = best. as_ref ( ) {
631
+ if cur_best. borrow ( ) . inner ( ) != c. borrow ( ) . inner ( )
632
+ {
633
+ backup = Some ( ( idx, c) ) ;
634
+ }
635
+ }
636
+ }
637
+ Some ( ( idx_backup, cur_backup) ) => {
588
638
if c < cur_backup {
589
639
// c is preferred over current backup
590
640
// check if it is not the same route as 'best'
591
- if best. as_ref ( ) != Some ( & c) {
592
- backup = Some ( c) ;
593
- } else {
594
- backup = Some ( cur_backup) ;
641
+ if best. as_ref ( ) . map ( |t| & t. 1 ) != Some ( & c) {
642
+ backup = Some ( ( idx, c) ) ;
643
+ continue ;
595
644
}
596
- } else {
597
- // put it back in
598
- backup = Some ( cur_backup) ;
599
645
}
600
-
646
+ // put it back in
647
+ backup = Some ( ( idx_backup, cur_backup) ) ;
601
648
}
602
649
}
603
650
}
@@ -607,50 +654,37 @@ pub fn best_backup<'a, OS, T>(
607
654
( best, backup)
608
655
}
609
656
610
- /*
611
- pub fn best_multistrat<'a, OS1: 'a + OrdStrat, OS2: 'a + OrdStrat, I>(it: I)
612
- -> Option<(OrdRoute<'a, OS1>, OrdRoute<'a, OS2>)>
613
- where
614
- I: Clone + Iterator<Item = OrdRoute<'a, OS1>>,
657
+ /// Returns the 'best' and second-best path.
658
+ ///
659
+ /// If the iterator passed in contains no paths, `(None, None)` is returned.
660
+ /// If the iterator yields only a single item, that will be the 'best' path,
661
+ /// and the 'backup' will be None, i.e. `(Some(best), None)`.
662
+ ///
663
+ /// In all other cases (an iterator yielding two or more non-identical
664
+ /// values), both members of the tuple should be `Some(..)`.
665
+ ///
666
+ /// The returned 'best' path is the same as the path returned by [`fn best`].
667
+ pub fn best_backup < ' a , I , T , OS > ( it : I ) -> ( Option < T > , Option < T > )
668
+ where
669
+ OS : OrdStrat ,
670
+ I : Iterator < Item = T > ,
671
+ T : Ord + core:: borrow:: Borrow < OrdRoute < ' a , OS > >
615
672
{
616
- let res1 = best(it.clone());
617
- let res1 = match res1 {
618
- Some(r) => r,
619
- None => return None
620
- };
621
-
622
- // Given that res1 is not None, `it` is non-empty.
623
- // For a non-empty collection of OrdRoutes, there is always a best, so we
624
- // can unwrap().
625
- let res2 = best_with_strat::<'_, _, OS2, _>(it).unwrap();
626
-
627
- Some((res1, res2))
673
+ let ( best, backup) = _best_backup ( it) ;
674
+ ( best. map ( |b| b. 1 ) , backup. map ( |b| b. 1 ) )
628
675
}
629
- */
630
-
631
- /*
632
- pub fn best_multistrat<'a, I, T1, T2, OS1, OS2>(it: I) -> Option<(T1, T2)>
633
- where
634
- T1: Ord + core::borrow::Borrow<OrdRoute<'a, OS1>>,
635
- T2: Ord,
636
- OS1: OrdStrat,
637
- OS2: OrdStrat,
638
- I: Clone + Iterator<Item = T1>,
676
+
677
+ /// Returns the index of the best and backup paths in the passed iterator.
678
+ pub fn best_backup_position < ' a , I , T , OS > ( it : I )
679
+ -> ( Option < usize > , Option < usize > )
680
+ where
681
+ OS : OrdStrat ,
682
+ I : Iterator < Item = T > ,
683
+ T : Ord + core:: borrow:: Borrow < OrdRoute < ' a , OS > >
639
684
{
640
- let res1 = best(it.clone());
641
- let res1 = match res1 {
642
- Some(r) => r,
643
- None => return None
644
- };
645
-
646
- // Given that res1 is not None, `it` is non-empty.
647
- // For a non-empty collection of OrdRoutes, there is always a best, so we
648
- // can unwrap().
649
- let res2 = best_with_strat::<'_, OS1, OS2, _>(it).unwrap();
650
-
651
- Some((res1, res2))
685
+ let ( best, backup) = _best_backup ( it) ;
686
+ ( best. map ( |b| b. 0 ) , backup. map ( |b| b. 0 ) )
652
687
}
653
- */
654
688
655
689
656
690
0 commit comments