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.
This commit is contained in:
Stjepan Glavina 2017-02-08 12:19:50 +01:00
parent 4711ac314c
commit 3bd6e46687

View File

@ -2290,6 +2290,28 @@ impl<A> SlicePartialOrd<A> for [A]
}
}
impl<A> SlicePartialOrd<A> for [A]
where A: Ord
{
default fn partial_compare(&self, other: &[A]) -> Option<Ordering> {
let l = cmp::min(self.len(), other.len());
// Slice to the loop iteration range to enable bound check
// elimination in the compiler
let lhs = &self[..l];
let rhs = &other[..l];
for i in 0..l {
match lhs[i].cmp(&rhs[i]) {
Ordering::Equal => (),
non_eq => return Some(non_eq),
}
}
self.len().partial_cmp(&other.len())
}
}
impl SlicePartialOrd<u8> for [u8] {
#[inline]
fn partial_compare(&self, other: &[u8]) -> Option<Ordering> {