@@ -2887,36 +2887,28 @@ 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
+ if cmp == Equal {
2899
+ // SAFETY: same as the `get_unchecked` above.
2900
+ unsafe { hint:: assert_unchecked ( mid < self . len ( ) ) } ;
2901
+ return Ok ( mid) ;
2902
+ }
2903
+ base = hint:: select_unpredictable ( cmp == Less , mid + ( size & 1 ) , base) ;
2904
+ }
2905
+
2906
+ // when always `Less` (base = mid + 1)
2907
+ if base == self . len ( ) {
2908
+ return Err ( base) ;
2917
2909
}
2918
2910
2919
- // SAFETY: base is always in [0, size) because base <= mid.
2911
+ // SAFETY: ` base < self.len()` because ` base <= mid` .
2920
2912
let cmp = f ( unsafe { self . get_unchecked ( base) } ) ;
2921
2913
if cmp == Equal {
2922
2914
// SAFETY: same as the `get_unchecked` above.
0 commit comments