@@ -2887,36 +2887,22 @@ impl<T> [T] {
2887
2887
}
2888
2888
let mut base = 0usize ;
2889
2889
2890
- // This loop intentionally doesn't have an early exit if the comparison
2891
- // returns Equal. We want the number of loop iterations to depend *only*
2892
- // on the size of the input slice so that the CPU can reliably predict
2893
- // the loop count.
2894
2890
while size > 1 {
2895
- let half = size / 2 ;
2896
- let mid = base + half ;
2891
+ size >>= 1 ;
2892
+ let mid = base + size ;
2897
2893
2898
- // SAFETY: the call is made safe by the following invariants:
2899
- // - `mid >= 0`: by definition
2900
- // - `mid < size`: `mid = size / 2 + size / 4 + size / 8 ...`
2894
+ // SAFETY: `mid < self.len()`:
2895
+ // mid = self.len() / 2 + self.len() / 4 + self.len() / 8 ...
2901
2896
let cmp = f ( unsafe { self . get_unchecked ( mid) } ) ;
2902
2897
2903
- // Binary search interacts poorly with branch prediction, so force
2904
- // the compiler to use conditional moves if supported by the target
2905
- // architecture.
2906
- base = hint:: select_unpredictable ( cmp == Greater , base, mid) ;
2907
-
2908
- // This is imprecise in the case where `size` is odd and the
2909
- // comparison returns Greater: the mid element still gets included
2910
- // by `size` even though it's known to be larger than the element
2911
- // being searched for.
2912
- //
2913
- // This is fine though: we gain more performance by keeping the
2914
- // loop iteration count invariant (and thus predictable) than we
2915
- // lose from considering one additional element.
2916
- size -= half;
2898
+ base = match cmp {
2899
+ Less => mid + ( size & 1 ) ,
2900
+ Equal => return Ok ( mid) ,
2901
+ Greater => base,
2902
+ } ;
2917
2903
}
2918
2904
2919
- // SAFETY: base is always in [0, size) because base <= mid .
2905
+ // SAFETY: same as the `get_unchecked` above .
2920
2906
let cmp = f ( unsafe { self . get_unchecked ( base) } ) ;
2921
2907
if cmp == Equal {
2922
2908
// SAFETY: same as the `get_unchecked` above.
0 commit comments