@@ -2887,36 +2887,31 @@ 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()` because
2895+ // mid = self.len() / 2 + self.len() / 4 + self.len() / 8 ...
29012896 let cmp = f ( unsafe { self . get_unchecked ( mid) } ) ;
29022897
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+ }
29032903 // Binary search interacts poorly with branch prediction, so force
29042904 // the compiler to use conditional moves if supported by the target
29052905 // 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;
2906+ base = hint:: select_unpredictable ( cmp == Less , mid + ( size & 1 ) , base) ;
2907+ }
2908+
2909+ // if was going through `Ordering::Less` each loop (base = mid + 1)
2910+ if base == self . len ( ) {
2911+ return Err ( base) ;
29172912 }
29182913
2919- // SAFETY: base is always in [0, size) because base <= mid.
2914+ // SAFETY: ` base < self.len()` because ` base <= mid` .
29202915 let cmp = f ( unsafe { self . get_unchecked ( base) } ) ;
29212916 if cmp == Equal {
29222917 // SAFETY: same as the `get_unchecked` above.
0 commit comments