@@ -743,12 +743,12 @@ pub trait Iterator {
743
743
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
744
744
fn max ( self ) -> Option < Self :: Item > where Self : Sized , Self :: Item : Ord
745
745
{
746
- self . fold ( None , |max , y| {
747
- match max {
748
- None => Some ( y ) ,
749
- Some ( x ) => Some ( cmp :: max ( x , y ) )
750
- }
751
- } )
746
+ select_fold1 ( self ,
747
+ |_| ( ) ,
748
+ // switch to y even if it is only equal, to preserve
749
+ // stability.
750
+ |_ , x , _ , y| * x <= * y )
751
+ . map ( | ( _ , x ) | x )
752
752
}
753
753
754
754
/// Consumes the entire iterator to return the minimum element.
@@ -766,12 +766,12 @@ pub trait Iterator {
766
766
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
767
767
fn min ( self ) -> Option < Self :: Item > where Self : Sized , Self :: Item : Ord
768
768
{
769
- self . fold ( None , |min , y| {
770
- match min {
771
- None => Some ( y ) ,
772
- Some ( x ) => Some ( cmp :: min ( x , y ) )
773
- }
774
- } )
769
+ select_fold1 ( self ,
770
+ |_| ( ) ,
771
+ // only switch to y if it is strictly smaller, to
772
+ // preserve stability.
773
+ |_ , x , _ , y| * x > * y )
774
+ . map ( | ( _ , x ) | x )
775
775
}
776
776
777
777
/// `min_max` finds the minimum and maximum elements in the iterator.
@@ -869,21 +869,16 @@ pub trait Iterator {
869
869
#[ inline]
870
870
#[ unstable( feature = "core" ,
871
871
reason = "may want to produce an Ordering directly; see #15311" ) ]
872
- fn max_by < B : Ord , F > ( self , mut f : F ) -> Option < Self :: Item > where
872
+ fn max_by < B : Ord , F > ( self , f : F ) -> Option < Self :: Item > where
873
873
Self : Sized ,
874
874
F : FnMut ( & Self :: Item ) -> B ,
875
875
{
876
- self . fold ( None , |max : Option < ( Self :: Item , B ) > , y| {
877
- let y_val = f ( & y) ;
878
- match max {
879
- None => Some ( ( y, y_val) ) ,
880
- Some ( ( x, x_val) ) => if y_val >= x_val {
881
- Some ( ( y, y_val) )
882
- } else {
883
- Some ( ( x, x_val) )
884
- }
885
- }
886
- } ) . map ( |( x, _) | x)
876
+ select_fold1 ( self ,
877
+ f,
878
+ // switch to y even if it is only equal, to preserve
879
+ // stability.
880
+ |x_p, _, y_p, _| x_p <= y_p)
881
+ . map ( |( _, x) | x)
887
882
}
888
883
889
884
/// Return the element that gives the minimum value from the
@@ -903,21 +898,16 @@ pub trait Iterator {
903
898
#[ inline]
904
899
#[ unstable( feature = "core" ,
905
900
reason = "may want to produce an Ordering directly; see #15311" ) ]
906
- fn min_by < B : Ord , F > ( self , mut f : F ) -> Option < Self :: Item > where
901
+ fn min_by < B : Ord , F > ( self , f : F ) -> Option < Self :: Item > where
907
902
Self : Sized ,
908
903
F : FnMut ( & Self :: Item ) -> B ,
909
904
{
910
- self . fold ( None , |min : Option < ( Self :: Item , B ) > , y| {
911
- let y_val = f ( & y) ;
912
- match min {
913
- None => Some ( ( y, y_val) ) ,
914
- Some ( ( x, x_val) ) => if x_val <= y_val {
915
- Some ( ( x, x_val) )
916
- } else {
917
- Some ( ( y, y_val) )
918
- }
919
- }
920
- } ) . map ( |( x, _) | x)
905
+ select_fold1 ( self ,
906
+ f,
907
+ // only switch to y if it is strictly smaller, to
908
+ // preserve stability.
909
+ |x_p, _, y_p, _| x_p > y_p)
910
+ . map ( |( _, x) | x)
921
911
}
922
912
923
913
/// Change the direction of the iterator
@@ -1024,6 +1014,38 @@ pub trait Iterator {
1024
1014
}
1025
1015
}
1026
1016
1017
+ /// Select an element from an iterator based on the given projection
1018
+ /// and "comparison" function.
1019
+ ///
1020
+ /// This is an idiosyncratic helper to try to factor out the
1021
+ /// commonalities of {max,min}{,_by}. In particular, this avoids
1022
+ /// having to implement optimisations several times.
1023
+ #[ inline]
1024
+ fn select_fold1 < I , B , FProj , FCmp > ( mut it : I ,
1025
+ mut f_proj : FProj ,
1026
+ mut f_cmp : FCmp ) -> Option < ( B , I :: Item ) >
1027
+ where I : Iterator ,
1028
+ FProj : FnMut ( & I :: Item ) -> B ,
1029
+ FCmp : FnMut ( & B , & I :: Item , & B , & I :: Item ) -> bool
1030
+ {
1031
+ // start with the first element as our selection. This avoids
1032
+ // having to use `Option`s inside the loop, translating to a
1033
+ // sizeable performance gain (6x in one case).
1034
+ it. next ( )
1035
+ . map ( |mut sel| {
1036
+ let mut sel_p = f_proj ( & sel) ;
1037
+
1038
+ for x in it {
1039
+ let x_p = f_proj ( & x) ;
1040
+ if f_cmp ( & sel_p, & sel, & x_p, & x) {
1041
+ sel = x;
1042
+ sel_p = x_p;
1043
+ }
1044
+ }
1045
+ ( sel_p, sel)
1046
+ } )
1047
+ }
1048
+
1027
1049
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
1028
1050
impl < ' a , I : Iterator + ?Sized > Iterator for & ' a mut I {
1029
1051
type Item = I :: Item ;
0 commit comments