Skip to content

Commit 0ccfeea

Browse files
Auto merge of #143495 - AngelicosPhosphoros:angelicos_phosphoros/skip_run_detection_in_sort_unstable, r=<try>
Skip `find_existing_run` call if head and tail pairs sorted differently This would help to avoid running comparator for all elements when user pushed an element to end of sorted Vec, breaking order only in last element. r? `@Voultapher`
2 parents e804cd4 + 67ac435 commit 0ccfeea

File tree

1 file changed

+22
-10
lines changed
  • library/core/src/slice/sort/unstable

1 file changed

+22
-10
lines changed

library/core/src/slice/sort/unstable/mod.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,19 +63,31 @@ where
6363
F: FnMut(&T, &T) -> bool,
6464
{
6565
let len = v.len();
66-
let (run_len, was_reversed) = find_existing_run(v, is_less);
66+
let check_existing_run = 'cer: {
67+
let v = &v[..];
68+
// Skip `find_existing_run` if head and tail sorted in different orders
69+
// because we are interested only if the whole slice is sorted.
70+
// This should skip running `find_existing_run` for an almost whole slice
71+
// in cases when user tries to sort a vector after single call to push.
72+
let [h0, h1, ..] = v else { break 'cer true };
73+
let [.., t0, t1] = v else { break 'cer true };
74+
(is_less(h0, h1) && !is_less(t1, t0)) || (is_less(h1, h0) && !is_less(t0, t1))
75+
};
76+
if check_existing_run {
77+
let (run_len, was_reversed) = find_existing_run(v, is_less);
6778

68-
// SAFETY: find_existing_run promises to return a valid run_len.
69-
unsafe { intrinsics::assume(run_len <= len) };
79+
// SAFETY: find_existing_run promises to return a valid run_len.
80+
unsafe { intrinsics::assume(run_len <= len) };
7081

71-
if run_len == len {
72-
if was_reversed {
73-
v.reverse();
74-
}
82+
if run_len == len {
83+
if was_reversed {
84+
v.reverse();
85+
}
7586

76-
// It would be possible to a do in-place merging here for a long existing streak. But that
77-
// makes the implementation a lot bigger, users can use `slice::sort` for that use-case.
78-
return;
87+
// It would be possible to a do in-place merging here for a long existing streak. But that
88+
// makes the implementation a lot bigger, users can use `slice::sort` for that use-case.
89+
return;
90+
}
7991
}
8092

8193
// Limit the number of imbalanced partitions to `2 * floor(log2(len))`.

0 commit comments

Comments
 (0)