Skip to content

Commit 3bd6e46

Browse files
author
Stjepan Glavina
committed
Specialize PartialOrd<A> for [A] where A: Ord
This way we can call `cmp` instead of `partial_cmp` in the loop, removing some burden of optimizing `Option`s away from the compiler. PR #39538 introduced a regression where sorting slices suddenly became slower, since `slice1.lt(slice2)` was much slower than `slice1.cmp(slice2) == Less`. This problem is now fixed. To verify, I benchmarked this simple program: ```rust fn main() { let mut v = (0..2_000_000).map(|x| x * x * x * 18913515181).map(|x| vec![x, x ^ 3137831591]).collect::<Vec<_>>(); v.sort(); } ``` Before this PR, it would take 0.95 sec, and now it takes 0.58 sec. I also tried changing the `is_less` lambda to use `cmp` and `partial_cmp`. Now all three versions (`lt`, `cmp`, `partial_cmp`) are equally performant for sorting slices - all of them take 0.58 sec on the benchmark.
1 parent 4711ac3 commit 3bd6e46

File tree

1 file changed

+22
-0
lines changed

1 file changed

+22
-0
lines changed

src/libcore/slice.rs

+22
Original file line numberDiff line numberDiff line change
@@ -2290,6 +2290,28 @@ impl<A> SlicePartialOrd<A> for [A]
22902290
}
22912291
}
22922292

2293+
impl<A> SlicePartialOrd<A> for [A]
2294+
where A: Ord
2295+
{
2296+
default fn partial_compare(&self, other: &[A]) -> Option<Ordering> {
2297+
let l = cmp::min(self.len(), other.len());
2298+
2299+
// Slice to the loop iteration range to enable bound check
2300+
// elimination in the compiler
2301+
let lhs = &self[..l];
2302+
let rhs = &other[..l];
2303+
2304+
for i in 0..l {
2305+
match lhs[i].cmp(&rhs[i]) {
2306+
Ordering::Equal => (),
2307+
non_eq => return Some(non_eq),
2308+
}
2309+
}
2310+
2311+
self.len().partial_cmp(&other.len())
2312+
}
2313+
}
2314+
22932315
impl SlicePartialOrd<u8> for [u8] {
22942316
#[inline]
22952317
fn partial_compare(&self, other: &[u8]) -> Option<Ordering> {

0 commit comments

Comments
 (0)