@@ -2887,36 +2887,22 @@ impl<T> [T] {
28872887 }
28882888 let mut base = 0usize ;
28892889
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.
28942890 while size > 1 {
2895- let half = size / 2 ;
2896- let mid = base + half ;
2891+ size >>= 1 ;
2892+ let mid = base + size ;
28972893
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 ...
29012896 let cmp = f ( unsafe { self . get_unchecked ( mid) } ) ;
29022897
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+ } ;
29172903 }
29182904
2919- // SAFETY: base is always in [0, size) because base <= mid .
2905+ // SAFETY: same as the `get_unchecked` above .
29202906 let cmp = f ( unsafe { self . get_unchecked ( base) } ) ;
29212907 if cmp == Equal {
29222908 // SAFETY: same as the `get_unchecked` above.
0 commit comments