Skip to content

Improve performance of slice::sort with ipn_stable #108005

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
22 changes: 13 additions & 9 deletions library/alloc/src/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,21 +176,25 @@ pub(crate) mod hack {
impl<T> [T] {
/// Sorts the slice.
///
/// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) worst-case.
/// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*))
/// worst-case. Fully ascending or descending inputs are completed with O(n-1) comparisons.
///
/// When applicable, unstable sorting is preferred because it is generally faster than stable
/// sorting and it doesn't allocate auxiliary memory.
/// See [`sort_unstable`](slice::sort_unstable).
/// sorting and it doesn't allocate auxiliary memory. See
/// [`sort_unstable`](slice::sort_unstable).
///
/// # Current implementation
///
/// The current algorithm is an adaptive, iterative merge sort inspired by
/// [timsort](https://en.wikipedia.org/wiki/Timsort).
/// It is designed to be very fast in cases where the slice is nearly sorted, or consists of
/// two or more sorted sequences concatenated one after another.
///
/// Also, it allocates temporary storage half the size of `self`, but for short slices a
/// non-allocating insertion sort is used instead.
/// [Timsort](https://en.wikipedia.org/wiki/Timsort). It is designed to be very fast in cases
/// where the slice is nearly sorted, or consists of two or more sorted sequences concatenated
/// one after another. This implementation is adapted from ipn_stable developed by Lukas
/// Bergdoll, incorporating ideas for a fast bi-directional merge function from quadsort
/// developed by Igor van den Hoven.
///
/// It allocates temporary storage the size of `self`, if this allocation fails it falls back to
/// allocating temporary storage half the size of `self`. For small inputs a non-allocating
/// specialized small-sort is used.
///
/// # Examples
///
Expand Down
12 changes: 11 additions & 1 deletion library/alloc/src/slice/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,17 @@ fn test_sort() {
for i in 0..v.len() {
v[i] = i as i32;
}
v.sort_by(|_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap());

// The original set of elements must be preserved even if Ord is implemented incorrectly, the
// function may return with an unspecified order or may panic. In both cases all observable
// writes, must be observed.

// It's ok to panic on Ord violation or to complete.
// In both cases the original elements must still be present.
let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| {
v.sort_by(|_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap());
}));

v.sort();
for i in 0..v.len() {
assert_eq!(v[i], i as i32);
Expand Down
Loading