about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Bergdoll <lukas.bergdoll@gmail.com>2023-10-25 19:37:14 +0200
committerLukas Bergdoll <lukas.bergdoll@gmail.com>2023-10-25 19:37:14 +0200
commite501add1f9addf72a30a333ec57ccb4e2ac5a8e4 (patch)
tree6b30a8e7bb6a38b6f907504d3d8aee90cb6e817c
parentb66fe58f68d84cf422ff50c362ac5ad245cd9ce7 (diff)
downloadrust-e501add1f9addf72a30a333ec57ccb4e2ac5a8e4.tar.gz
rust-e501add1f9addf72a30a333ec57ccb4e2ac5a8e4.zip
Avoid unnecessary comparison in partition_equal
The branchy Hoare partition `partition_equal` as part of `slice::sort_unstable`
has a bug that makes it perform a comparison of the last element twice.

Measuring inputs with a Zipfian distribution with characterizing exponent s ==
1.0, yields a ~0.05% reduction in the total number of comparisons performed.
-rw-r--r--library/core/src/slice/sort.rs13
1 files changed, 10 insertions, 3 deletions
diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs
index db76d26257a..993a608f42b 100644
--- a/library/core/src/slice/sort.rs
+++ b/library/core/src/slice/sort.rs
@@ -628,9 +628,14 @@ where
     let _pivot_guard = InsertionHole { src: &*tmp, dest: pivot };
     let pivot = &*tmp;
 
+    let len = v.len();
+    if len == 0 {
+        return 0;
+    }
+
     // Now partition the slice.
     let mut l = 0;
-    let mut r = v.len();
+    let mut r = len;
     loop {
         // SAFETY: The unsafety below involves indexing an array.
         // For the first one: We already do the bounds checking here with `l < r`.
@@ -643,8 +648,11 @@ where
             }
 
             // Find the last element equal to the pivot.
-            while l < r && is_less(pivot, v.get_unchecked(r - 1)) {
+            loop {
                 r -= 1;
+                if l >= r || !is_less(pivot, v.get_unchecked(r)) {
+                    break;
+                }
             }
 
             // Are we done?
@@ -653,7 +661,6 @@ where
             }
 
             // Swap the found pair of out-of-order elements.
-            r -= 1;
             let ptr = v.as_mut_ptr();
             ptr::swap(ptr.add(l), ptr.add(r));
             l += 1;