about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFolyd <lyshuhow@gmail.com>2020-09-27 20:32:40 +0800
committerFolyd <lyshuhow@gmail.com>2021-01-30 14:11:47 +0800
commit7d078cfb94fa75e5dee699535f3f9781d3a1d47d (patch)
tree86fd305801ad06220c91474be985b9784ffee318
parent18e44a1be4d8aecf41d0b904d63f6c72f51d6b0d (diff)
downloadrust-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.rs37
-rw-r--r--library/core/tests/slice.rs2
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));