Skip to content

Commit 35fd1ba

Browse files
committed
sort: Fast path for already sorted data
When merging two sorted blocks `left` and `right` if the last element in `left` is <= the first in `right`, the blocks are already sorted. Add this as an additional fast path by simply copying the whole left block into the output and advancing the left pointer. The right block is then treated the same way by the already present logic in the merge loop. Reduces runtime of .sort() to less than 50% of the previous, if the data was already perfectly sorted. Sorted data with a few swaps are also sorted quicker than before. The overhead of one comparison per merge seems to be negligible.
1 parent 792a9f1 commit 35fd1ba

File tree

1 file changed

+10
-0
lines changed

1 file changed

+10
-0
lines changed

src/libcollections/slice.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,16 @@ fn merge_sort<T, F>(v: &mut [T], mut compare: F) where F: FnMut(&T, &T) -> Order
10661066
let mut out = buf_tmp.offset(start as isize);
10671067
let out_end = buf_tmp.offset(right_end_idx as isize);
10681068

1069+
// if left[last] <= right[0], they are already in order:
1070+
// fast-forward the left side (the right side is handled
1071+
// in the loop).
1072+
if compare(&*right.offset(-1), &*right) != Greater {
1073+
let elems = (right_start as usize - left as usize) / mem::size_of::<T>();
1074+
ptr::copy_nonoverlapping(&*left, out, elems);
1075+
out = out.offset(elems as isize);
1076+
left = right_start;
1077+
}
1078+
10691079
while out < out_end {
10701080
// Either the left or the right run are exhausted,
10711081
// so just copy the remainder from the other run

0 commit comments

Comments
 (0)