diff options
| author | Folyd <lyshuhow@gmail.com> | 2020-09-27 20:32:40 +0800 |
|---|---|---|
| committer | Folyd <lyshuhow@gmail.com> | 2021-01-30 14:11:47 +0800 |
| commit | 7d078cfb94fa75e5dee699535f3f9781d3a1d47d (patch) | |
| tree | 86fd305801ad06220c91474be985b9784ffee318 | |
| parent | 18e44a1be4d8aecf41d0b904d63f6c72f51d6b0d (diff) | |
| download | rust-7d078cfb94fa75e5dee699535f3f9781d3a1d47d.tar.gz rust-7d078cfb94fa75e5dee699535f3f9781d3a1d47d.zip | |
Simplify binary search logic to full branch code to let CPU guessing branch more precisely
| -rw-r--r-- | library/core/src/slice/mod.rs | 37 | ||||
| -rw-r--r-- | library/core/tests/slice.rs | 2 |
2 files changed, 17 insertions, 22 deletions
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index e904f856d1e..c7dd000f71f 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -8,7 +8,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::cmp::Ordering::{self, Equal, Greater, Less}; +use crate::cmp::Ordering::{self, Greater, Less}; use crate::marker::Copy; use crate::mem; use crate::num::NonZeroUsize; @@ -2154,29 +2154,24 @@ impl<T> [T] { where F: FnMut(&'a T) -> Ordering, { - let s = self; - let mut size = s.len(); - if size == 0 { - return Err(0); - } - let mut base = 0usize; - while size > 1 { - let half = size / 2; - let mid = base + half; - // SAFETY: the call is made safe by the following inconstants: - // - `mid >= 0`: by definition - // - `mid < size`: `mid = size / 2 + size / 4 + size / 8 ...` - let cmp = f(unsafe { s.get_unchecked(mid) }); - if cmp == Equal { + let mut left = 0; + let mut right = self.len(); + while left < right { + // never overflow because `slice::len()` max is `isize::MAX`. + let mid = (left + right) / 2; + // SAFETY: the call is made safe by the following invariants: + // - `mid >= 0` + // - `mid < size`: `mid` is limited by `[left; right)` bound. + let cmp = f(unsafe { self.get_unchecked(mid) }); + if cmp == Less { + left = mid + 1; + } else if cmp == Greater { + right = mid; + } else { return Ok(mid); - } else if cmp == Less { - base = mid } - size -= half; } - // SAFETY: base is always in [0, size) because base <= mid. - let cmp = f(unsafe { s.get_unchecked(base) }); - if cmp == Equal { Ok(base) } else { Err(base + (cmp == Less) as usize) } + Err(left) } /// Binary searches this sorted slice with a key extraction function. diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index d9efa7ef20b..390066359f6 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -76,7 +76,7 @@ fn test_binary_search_implementation_details() { assert_eq!(b.binary_search(&3), Ok(5)); let b = [1, 1, 1, 1, 1, 3, 3, 3, 3]; assert_eq!(b.binary_search(&1), Ok(4)); - assert_eq!(b.binary_search(&3), Ok(6)); + assert_eq!(b.binary_search(&3), Ok(7)); let b = [1, 1, 1, 1, 3, 3, 3, 3, 3]; assert_eq!(b.binary_search(&1), Ok(2)); assert_eq!(b.binary_search(&3), Ok(4)); |
