Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b005d21

Browse filesBrowse files
committed
Optimize: core slice binary_search_by
1 parent 16d2276 commit b005d21
Copy full SHA for b005d21

File tree

Expand file treeCollapse file tree

1 file changed

+16
-21
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+16
-21
lines changed

‎library/core/src/slice/mod.rs

Copy file name to clipboardExpand all lines: library/core/src/slice/mod.rs
+16-21Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.