Skip to content

Commit ee91d0f

Browse files
Auto merge of #149318 - tisonkun:slice_partial_sort_unstable, r=<try>
Implement partial_sort_unstable for slice try-job: aarch64-gnu-llvm-20-1
2 parents 3fda0e4 + 45e0fbf commit ee91d0f

5 files changed

Lines changed: 355 additions & 2 deletions

File tree

library/alloctests/tests/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#![feature(binary_heap_into_iter_sorted)]
2222
#![feature(binary_heap_drain_sorted)]
2323
#![feature(slice_ptr_get)]
24+
#![feature(slice_range)]
25+
#![feature(slice_partial_sort_unstable)]
2426
#![feature(inplace_iteration)]
2527
#![feature(iter_advance_by)]
2628
#![feature(iter_next_chunk)]

library/alloctests/tests/sort/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub trait Sort {
1212

1313
mod ffi_types;
1414
mod known_good_stable_sort;
15+
mod partial;
1516
mod patterns;
1617
mod tests;
1718
mod zipf;
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use std::fmt::Debug;
2+
use std::ops::{Range, RangeBounds};
3+
use std::slice;
4+
5+
use super::patterns;
6+
7+
fn check_is_partial_sorted<T: Ord + Clone + Debug, R: RangeBounds<usize>>(v: &mut [T], range: R) {
8+
let Range { start, end } = slice::range(range, ..v.len());
9+
v.partial_sort_unstable(start..end);
10+
11+
let max_before = v[..start].iter().max().into_iter();
12+
let sorted_range = v[start..end].into_iter();
13+
let min_after = v[end..].iter().min().into_iter();
14+
let seq = max_before.chain(sorted_range).chain(min_after);
15+
assert!(seq.is_sorted());
16+
}
17+
18+
fn check_is_partial_sorted_ranges<T: Ord + Clone + Debug>(v: &[T]) {
19+
let len = v.len();
20+
21+
check_is_partial_sorted::<T, _>(&mut v.to_vec(), ..);
22+
check_is_partial_sorted::<T, _>(&mut v.to_vec(), 0..0);
23+
check_is_partial_sorted::<T, _>(&mut v.to_vec(), len..len);
24+
25+
if len > 0 {
26+
check_is_partial_sorted::<T, _>(&mut v.to_vec(), len - 1..len - 1);
27+
check_is_partial_sorted::<T, _>(&mut v.to_vec(), 0..1);
28+
check_is_partial_sorted::<T, _>(&mut v.to_vec(), len - 1..len);
29+
30+
for mid in 1..len {
31+
check_is_partial_sorted::<T, _>(&mut v.to_vec(), 0..mid);
32+
check_is_partial_sorted::<T, _>(&mut v.to_vec(), mid..len);
33+
check_is_partial_sorted::<T, _>(&mut v.to_vec(), mid..mid);
34+
check_is_partial_sorted::<T, _>(&mut v.to_vec(), mid - 1..mid + 1);
35+
check_is_partial_sorted::<T, _>(&mut v.to_vec(), mid - 1..mid);
36+
check_is_partial_sorted::<T, _>(&mut v.to_vec(), mid..mid + 1);
37+
}
38+
39+
let quarters = [0, len / 4, len / 2, (3 * len) / 4, len];
40+
for &start in &quarters {
41+
for &end in &quarters {
42+
if start < end {
43+
check_is_partial_sorted::<T, _>(&mut v.to_vec(), start..end);
44+
}
45+
}
46+
}
47+
}
48+
}
49+
50+
#[test]
51+
fn basic_impl() {
52+
check_is_partial_sorted::<i32, _>(&mut [], ..);
53+
check_is_partial_sorted::<(), _>(&mut [], ..);
54+
check_is_partial_sorted::<(), _>(&mut [()], ..);
55+
check_is_partial_sorted::<(), _>(&mut [(), ()], ..);
56+
check_is_partial_sorted::<(), _>(&mut [(), (), ()], ..);
57+
check_is_partial_sorted::<i32, _>(&mut [], ..);
58+
59+
check_is_partial_sorted::<i32, _>(&mut [77], ..);
60+
check_is_partial_sorted::<i32, _>(&mut [2, 3], ..);
61+
check_is_partial_sorted::<i32, _>(&mut [2, 3, 6], ..);
62+
check_is_partial_sorted::<i32, _>(&mut [2, 3, 99, 6], ..);
63+
check_is_partial_sorted::<i32, _>(&mut [2, 7709, 400, 90932], ..);
64+
check_is_partial_sorted::<i32, _>(&mut [15, -1, 3, -1, -3, -1, 7], ..);
65+
66+
check_is_partial_sorted::<i32, _>(&mut [15, -1, 3, -1, -3, -1, 7], 0..0);
67+
check_is_partial_sorted::<i32, _>(&mut [15, -1, 3, -1, -3, -1, 7], 0..1);
68+
check_is_partial_sorted::<i32, _>(&mut [15, -1, 3, -1, -3, -1, 7], 0..5);
69+
check_is_partial_sorted::<i32, _>(&mut [15, -1, 3, -1, -3, -1, 7], 0..7);
70+
check_is_partial_sorted::<i32, _>(&mut [15, -1, 3, -1, -3, -1, 7], 7..7);
71+
check_is_partial_sorted::<i32, _>(&mut [15, -1, 3, -1, -3, -1, 7], 6..7);
72+
check_is_partial_sorted::<i32, _>(&mut [15, -1, 3, -1, -3, -1, 7], 5..7);
73+
check_is_partial_sorted::<i32, _>(&mut [15, -1, 3, -1, -3, -1, 7], 5..5);
74+
check_is_partial_sorted::<i32, _>(&mut [15, -1, 3, -1, -3, -1, 7], 4..5);
75+
check_is_partial_sorted::<i32, _>(&mut [15, -1, 3, -1, -3, -1, 7], 4..6);
76+
}
77+
78+
#[test]
79+
fn random_patterns() {
80+
check_is_partial_sorted_ranges(&patterns::random(10));
81+
check_is_partial_sorted_ranges(&patterns::random(50));
82+
check_is_partial_sorted_ranges(&patterns::random(100));
83+
check_is_partial_sorted_ranges(&patterns::random(1000));
84+
}

library/core/src/slice/mod.rs

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3244,6 +3244,219 @@ impl<T> [T] {
32443244
sort::unstable::sort(self, &mut |a, b| f(a).lt(&f(b)));
32453245
}
32463246

3247+
/// Partially sorts the slice in ascending order **without** preserving the initial order of equal elements.
3248+
///
3249+
/// Upon completion, for the specified range `start..end`, it's guaranteed that:
3250+
///
3251+
/// 1. Every element in `self[..start]` is smaller than or equal to
3252+
/// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to
3253+
/// 3. Every element in `self[end..]`.
3254+
///
3255+
/// This partial sort is unstable, meaning it may reorder equal elements in the specified range.
3256+
/// It may reorder elements outside the specified range as well, but the guarantees above still hold.
3257+
///
3258+
/// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case,
3259+
/// where *n* is the length of the slice and *k* is the length of the specified range.
3260+
///
3261+
/// See the documentation of [`sort_unstable`] for implementation notes.
3262+
///
3263+
/// # Panics
3264+
///
3265+
/// May panic if the implementation of [`Ord`] for `T` does not implement a total order, or if
3266+
/// the [`Ord`] implementation panics, or if the specified range is out of bounds.
3267+
///
3268+
/// # Examples
3269+
///
3270+
/// ```
3271+
/// #![feature(slice_partial_sort_unstable)]
3272+
///
3273+
/// let mut v = [4, -5, 1, -3, 2];
3274+
///
3275+
/// // empty range at the beginning, nothing changed
3276+
/// v.partial_sort_unstable(0..0);
3277+
/// assert_eq!(v, [4, -5, 1, -3, 2]);
3278+
///
3279+
/// // empty range in the middle, partitioning the slice
3280+
/// v.partial_sort_unstable(2..2);
3281+
/// for i in 0..2 {
3282+
/// assert!(v[i] <= v[2]);
3283+
/// }
3284+
/// for i in 3..v.len() {
3285+
/// assert!(v[2] <= v[i]);
3286+
/// }
3287+
///
3288+
/// // single element range, same as select_nth_unstable
3289+
/// v.partial_sort_unstable(2..3);
3290+
/// for i in 0..2 {
3291+
/// assert!(v[i] <= v[2]);
3292+
/// }
3293+
/// for i in 3..v.len() {
3294+
/// assert!(v[2] <= v[i]);
3295+
/// }
3296+
///
3297+
/// // partial sort a subrange
3298+
/// v.partial_sort_unstable(1..4);
3299+
/// assert_eq!(&v[1..4], [-3, 1, 2]);
3300+
///
3301+
/// // partial sort the whole range, same as sort_unstable
3302+
/// v.partial_sort_unstable(..);
3303+
/// assert_eq!(v, [-5, -3, 1, 2, 4]);
3304+
/// ```
3305+
///
3306+
/// [`sort_unstable`]: slice::sort_unstable
3307+
#[unstable(feature = "slice_partial_sort_unstable", issue = "149046")]
3308+
#[inline]
3309+
pub fn partial_sort_unstable<R>(&mut self, range: R)
3310+
where
3311+
T: Ord,
3312+
R: RangeBounds<usize>,
3313+
{
3314+
sort::unstable::partial_sort(self, range, T::lt);
3315+
}
3316+
3317+
/// Partially sorts the slice in ascending order with a comparison function, **without**
3318+
/// preserving the initial order of equal elements.
3319+
///
3320+
/// Upon completion, for the specified range `start..end`, it's guaranteed that:
3321+
///
3322+
/// 1. Every element in `self[..start]` is smaller than or equal to
3323+
/// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to
3324+
/// 3. Every element in `self[end..]`.
3325+
///
3326+
/// This partial sort is unstable, meaning it may reorder equal elements in the specified range.
3327+
/// It may reorder elements outside the specified range as well, but the guarantees above still hold.
3328+
///
3329+
/// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case,
3330+
/// where *n* is the length of the slice and *k* is the length of the specified range.
3331+
///
3332+
/// See the documentation of [`sort_unstable_by`] for implementation notes.
3333+
///
3334+
/// # Panics
3335+
///
3336+
/// May panic if the `compare` does not implement a total order, or if
3337+
/// the `compare` itself panics, or if the specified range is out of bounds.
3338+
///
3339+
/// # Examples
3340+
///
3341+
/// ```
3342+
/// #![feature(slice_partial_sort_unstable)]
3343+
///
3344+
/// let mut v = [4, -5, 1, -3, 2];
3345+
///
3346+
/// // empty range at the beginning, nothing changed
3347+
/// v.partial_sort_unstable_by(0..0, |a, b| b.cmp(a));
3348+
/// assert_eq!(v, [4, -5, 1, -3, 2]);
3349+
///
3350+
/// // empty range in the middle, partitioning the slice
3351+
/// v.partial_sort_unstable_by(2..2, |a, b| b.cmp(a));
3352+
/// for i in 0..2 {
3353+
/// assert!(v[i] >= v[2]);
3354+
/// }
3355+
/// for i in 3..v.len() {
3356+
/// assert!(v[2] >= v[i]);
3357+
/// }
3358+
///
3359+
/// // single element range, same as select_nth_unstable
3360+
/// v.partial_sort_unstable_by(2..3, |a, b| b.cmp(a));
3361+
/// for i in 0..2 {
3362+
/// assert!(v[i] >= v[2]);
3363+
/// }
3364+
/// for i in 3..v.len() {
3365+
/// assert!(v[2] >= v[i]);
3366+
/// }
3367+
///
3368+
/// // partial sort a subrange
3369+
/// v.partial_sort_unstable_by(1..4, |a, b| b.cmp(a));
3370+
/// assert_eq!(&v[1..4], [2, 1, -3]);
3371+
///
3372+
/// // partial sort the whole range, same as sort_unstable
3373+
/// v.partial_sort_unstable_by(.., |a, b| b.cmp(a));
3374+
/// assert_eq!(v, [4, 2, 1, -3, -5]);
3375+
/// ```
3376+
///
3377+
/// [`sort_unstable_by`]: slice::sort_unstable_by
3378+
#[unstable(feature = "slice_partial_sort_unstable", issue = "149046")]
3379+
#[inline]
3380+
pub fn partial_sort_unstable_by<F, R>(&mut self, range: R, mut compare: F)
3381+
where
3382+
F: FnMut(&T, &T) -> Ordering,
3383+
R: RangeBounds<usize>,
3384+
{
3385+
sort::unstable::partial_sort(self, range, |a, b| compare(a, b) == Less);
3386+
}
3387+
3388+
/// Partially sorts the slice in ascending order with a key extraction function, **without**
3389+
/// preserving the initial order of equal elements.
3390+
///
3391+
/// Upon completion, for the specified range `start..end`, it's guaranteed that:
3392+
///
3393+
/// 1. Every element in `self[..start]` is smaller than or equal to
3394+
/// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to
3395+
/// 3. Every element in `self[end..]`.
3396+
///
3397+
/// This partial sort is unstable, meaning it may reorder equal elements in the specified range.
3398+
/// It may reorder elements outside the specified range as well, but the guarantees above still hold.
3399+
///
3400+
/// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case,
3401+
/// where *n* is the length of the slice and *k* is the length of the specified range.
3402+
///
3403+
/// See the documentation of [`sort_unstable_by_key`] for implementation notes.
3404+
///
3405+
/// # Panics
3406+
///
3407+
/// May panic if the implementation of [`Ord`] for `K` does not implement a total order, or if
3408+
/// the [`Ord`] implementation panics, or if the specified range is out of bounds.
3409+
///
3410+
/// # Examples
3411+
///
3412+
/// ```
3413+
/// #![feature(slice_partial_sort_unstable)]
3414+
///
3415+
/// let mut v = [4i32, -5, 1, -3, 2];
3416+
///
3417+
/// // empty range at the beginning, nothing changed
3418+
/// v.partial_sort_unstable_by_key(0..0, |k| k.abs());
3419+
/// assert_eq!(v, [4, -5, 1, -3, 2]);
3420+
///
3421+
/// // empty range in the middle, partitioning the slice
3422+
/// v.partial_sort_unstable_by_key(2..2, |k| k.abs());
3423+
/// for i in 0..2 {
3424+
/// assert!(v[i].abs() <= v[2].abs());
3425+
/// }
3426+
/// for i in 3..v.len() {
3427+
/// assert!(v[2].abs() <= v[i].abs());
3428+
/// }
3429+
///
3430+
/// // single element range, same as select_nth_unstable
3431+
/// v.partial_sort_unstable_by_key(2..3, |k| k.abs());
3432+
/// for i in 0..2 {
3433+
/// assert!(v[i].abs() <= v[2].abs());
3434+
/// }
3435+
/// for i in 3..v.len() {
3436+
/// assert!(v[2].abs() <= v[i].abs());
3437+
/// }
3438+
///
3439+
/// // partial sort a subrange
3440+
/// v.partial_sort_unstable_by_key(1..4, |k| k.abs());
3441+
/// assert_eq!(&v[1..4], [2, -3, 4]);
3442+
///
3443+
/// // partial sort the whole range, same as sort_unstable
3444+
/// v.partial_sort_unstable_by_key(.., |k| k.abs());
3445+
/// assert_eq!(v, [1, 2, -3, 4, -5]);
3446+
/// ```
3447+
///
3448+
/// [`sort_unstable_by_key`]: slice::sort_unstable_by_key
3449+
#[unstable(feature = "slice_partial_sort_unstable", issue = "149046")]
3450+
#[inline]
3451+
pub fn partial_sort_unstable_by_key<K, F, R>(&mut self, range: R, mut f: F)
3452+
where
3453+
F: FnMut(&T) -> K,
3454+
K: Ord,
3455+
R: RangeBounds<usize>,
3456+
{
3457+
sort::unstable::partial_sort(self, range, |a, b| f(a).lt(&f(b)));
3458+
}
3459+
32473460
/// Reorders the slice such that the element at `index` is at a sort-order position. All
32483461
/// elements before `index` will be `<=` to this value, and all elements after will be `>=` to
32493462
/// it.

0 commit comments

Comments
 (0)