Skip to content

Commit 7164a9f

Browse files
committedJan 21, 2019
Auto merge of #55045 - kleimkuhler:add-std-is_sorted, r=KodrAus
Add `is_sorted` to `Iterator` and `[T]` This is an initial implementation for the first step of [RFC 2351](https://github.com/rust-lang/rfcs/blob/master/text/2351-is-sorted.md) Tracking issue: #53485
2 parents 0974bdc + b4766f8 commit 7164a9f

File tree

9 files changed

+271
-4
lines changed

9 files changed

+271
-4
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# `is_sorted`
2+
3+
The tracking issue for this feature is: [#53485]
4+
5+
[#53485]: https://github.com/rust-lang/rust/issues/53485
6+
7+
------------------------
8+
9+
Add the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to `[T]`;
10+
add the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to
11+
`Iterator`.

‎src/libcore/iter/iterator.rs

+89
Original file line numberDiff line numberDiff line change
@@ -2605,6 +2605,95 @@ pub trait Iterator {
26052605
}
26062606
}
26072607
}
2608+
2609+
/// Checks if the elements of this iterator are sorted.
2610+
///
2611+
/// That is, for each element `a` and its following element `b`, `a <= b` must hold. If the
2612+
/// iterator yields exactly zero or one element, `true` is returned.
2613+
///
2614+
/// Note that if `Self::Item` is only `PartialOrd`, but not `Ord`, the above definition
2615+
/// implies that this function returns `false` if any two consecutive items are not
2616+
/// comparable.
2617+
///
2618+
/// # Examples
2619+
///
2620+
/// ```
2621+
/// #![feature(is_sorted)]
2622+
///
2623+
/// assert!([1, 2, 2, 9].iter().is_sorted());
2624+
/// assert!(![1, 3, 2, 4].iter().is_sorted());
2625+
/// assert!([0].iter().is_sorted());
2626+
/// assert!(std::iter::empty::<i32>().is_sorted());
2627+
/// assert!(![0.0, 1.0, std::f32::NAN].iter().is_sorted());
2628+
/// ```
2629+
#[inline]
2630+
#[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
2631+
fn is_sorted(self) -> bool
2632+
where
2633+
Self: Sized,
2634+
Self::Item: PartialOrd,
2635+
{
2636+
self.is_sorted_by(|a, b| a.partial_cmp(b))
2637+
}
2638+
2639+
/// Checks if the elements of this iterator are sorted using the given comparator function.
2640+
///
2641+
/// Instead of using `PartialOrd::partial_cmp`, this function uses the given `compare`
2642+
/// function to determine the ordering of two elements. Apart from that, it's equivalent to
2643+
/// [`is_sorted`]; see its documentation for more information.
2644+
///
2645+
/// [`is_sorted`]: trait.Iterator.html#method.is_sorted
2646+
#[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
2647+
fn is_sorted_by<F>(mut self, mut compare: F) -> bool
2648+
where
2649+
Self: Sized,
2650+
F: FnMut(&Self::Item, &Self::Item) -> Option<Ordering>
2651+
{
2652+
let mut last = match self.next() {
2653+
Some(e) => e,
2654+
None => return true,
2655+
};
2656+
2657+
while let Some(curr) = self.next() {
2658+
if compare(&last, &curr)
2659+
.map(|o| o == Ordering::Greater)
2660+
.unwrap_or(true)
2661+
{
2662+
return false;
2663+
}
2664+
last = curr;
2665+
}
2666+
2667+
true
2668+
}
2669+
2670+
/// Checks if the elements of this iterator are sorted using the given key extraction
2671+
/// function.
2672+
///
2673+
/// Instead of comparing the iterator's elements directly, this function compares the keys of
2674+
/// the elements, as determined by `f`. Apart from that, it's equivalent to [`is_sorted`]; see
2675+
/// its documentation for more information.
2676+
///
2677+
/// [`is_sorted`]: trait.Iterator.html#method.is_sorted
2678+
///
2679+
/// # Examples
2680+
///
2681+
/// ```
2682+
/// #![feature(is_sorted)]
2683+
///
2684+
/// assert!(["c", "bb", "aaa"].iter().is_sorted_by_key(|s| s.len()));
2685+
/// assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs()));
2686+
/// ```
2687+
#[inline]
2688+
#[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
2689+
fn is_sorted_by_key<F, K>(self, mut f: F) -> bool
2690+
where
2691+
Self: Sized,
2692+
F: FnMut(&Self::Item) -> K,
2693+
K: PartialOrd
2694+
{
2695+
self.is_sorted_by(|a, b| f(a).partial_cmp(&f(b)))
2696+
}
26082697
}
26092698

26102699
/// Select an element from an iterator based on the given "projection"

‎src/libcore/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
#![feature(extern_types)]
8080
#![feature(fundamental)]
8181
#![feature(intrinsics)]
82+
#![feature(is_sorted)]
8283
#![feature(iter_once_with)]
8384
#![feature(lang_items)]
8485
#![feature(link_llvm_intrinsics)]

‎src/libcore/slice/mod.rs

+93-4
Original file line numberDiff line numberDiff line change
@@ -1783,7 +1783,7 @@ impl<T> [T] {
17831783
/// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
17841784
/// a[1..5].rotate_left(1);
17851785
/// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']);
1786-
/// ```
1786+
/// ```
17871787
#[stable(feature = "slice_rotate", since = "1.26.0")]
17881788
pub fn rotate_left(&mut self, mid: usize) {
17891789
assert!(mid <= self.len());
@@ -2250,6 +2250,77 @@ impl<T> [T] {
22502250
from_raw_parts_mut(mut_ptr.add(rest.len() - ts_len), ts_len))
22512251
}
22522252
}
2253+
2254+
/// Checks if the elements of this slice are sorted.
2255+
///
2256+
/// That is, for each element `a` and its following element `b`, `a <= b` must hold. If the
2257+
/// slice yields exactly zero or one element, `true` is returned.
2258+
///
2259+
/// Note that if `Self::Item` is only `PartialOrd`, but not `Ord`, the above definition
2260+
/// implies that this function returns `false` if any two consecutive items are not
2261+
/// comparable.
2262+
///
2263+
/// # Examples
2264+
///
2265+
/// ```
2266+
/// #![feature(is_sorted)]
2267+
/// let empty: [i32; 0] = [];
2268+
///
2269+
/// assert!([1, 2, 2, 9].is_sorted());
2270+
/// assert!(![1, 3, 2, 4].is_sorted());
2271+
/// assert!([0].is_sorted());
2272+
/// assert!(empty.is_sorted());
2273+
/// assert!(![0.0, 1.0, std::f32::NAN].is_sorted());
2274+
/// ```
2275+
#[inline]
2276+
#[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
2277+
pub fn is_sorted(&self) -> bool
2278+
where
2279+
T: PartialOrd,
2280+
{
2281+
self.is_sorted_by(|a, b| a.partial_cmp(b))
2282+
}
2283+
2284+
/// Checks if the elements of this slice are sorted using the given comparator function.
2285+
///
2286+
/// Instead of using `PartialOrd::partial_cmp`, this function uses the given `compare`
2287+
/// function to determine the ordering of two elements. Apart from that, it's equivalent to
2288+
/// [`is_sorted`]; see its documentation for more information.
2289+
///
2290+
/// [`is_sorted`]: #method.is_sorted
2291+
#[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
2292+
pub fn is_sorted_by<F>(&self, mut compare: F) -> bool
2293+
where
2294+
F: FnMut(&T, &T) -> Option<Ordering>
2295+
{
2296+
self.iter().is_sorted_by(|a, b| compare(*a, *b))
2297+
}
2298+
2299+
/// Checks if the elements of this slice are sorted using the given key extraction function.
2300+
///
2301+
/// Instead of comparing the slice's elements directly, this function compares the keys of the
2302+
/// elements, as determined by `f`. Apart from that, it's equivalent to [`is_sorted`]; see its
2303+
/// documentation for more information.
2304+
///
2305+
/// [`is_sorted`]: #method.is_sorted
2306+
///
2307+
/// # Examples
2308+
///
2309+
/// ```
2310+
/// #![feature(is_sorted)]
2311+
///
2312+
/// assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len()));
2313+
/// assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs()));
2314+
/// ```
2315+
#[inline]
2316+
#[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
2317+
pub fn is_sorted_by_key<F, K>(&self, mut f: F) -> bool
2318+
where
2319+
F: FnMut(&T) -> K,
2320+
K: PartialOrd
2321+
{
2322+
self.is_sorted_by(|a, b| f(a).partial_cmp(&f(b)))
2323+
}
22532324
}
22542325

22552326
#[lang = "slice_u8"]
@@ -2773,7 +2844,13 @@ macro_rules! len {
27732844

27742845
// The shared definition of the `Iter` and `IterMut` iterators
27752846
macro_rules! iterator {
2776-
(struct $name:ident -> $ptr:ty, $elem:ty, $raw_mut:tt, $( $mut_:tt )*) => {
2847+
(
2848+
struct $name:ident -> $ptr:ty,
2849+
$elem:ty,
2850+
$raw_mut:tt,
2851+
{$( $mut_:tt )*},
2852+
{$($extra:tt)*}
2853+
) => {
27772854
impl<'a, T> $name<'a, T> {
27782855
// Helper function for creating a slice from the iterator.
27792856
#[inline(always)]
@@ -2950,6 +3027,8 @@ macro_rules! iterator {
29503027
i
29513028
})
29523029
}
3030+
3031+
$($extra)*
29533032
}
29543033

29553034
#[stable(feature = "rust1", since = "1.0.0")]
@@ -3087,7 +3166,17 @@ impl<'a, T> Iter<'a, T> {
30873166
}
30883167
}
30893168

3090-
iterator!{struct Iter -> *const T, &'a T, const, /* no mut */}
3169+
iterator!{struct Iter -> *const T, &'a T, const, {/* no mut */}, {
3170+
fn is_sorted_by<F>(self, mut compare: F) -> bool
3171+
where
3172+
Self: Sized,
3173+
F: FnMut(&Self::Item, &Self::Item) -> Option<Ordering>,
3174+
{
3175+
self.as_slice().windows(2).all(|w| {
3176+
compare(&&w[0], &&w[1]).map(|o| o != Ordering::Greater).unwrap_or(false)
3177+
})
3178+
}
3179+
}}
30913180

30923181
#[stable(feature = "rust1", since = "1.0.0")]
30933182
impl<T> Clone for Iter<'_, T> {
@@ -3188,7 +3277,7 @@ impl<'a, T> IterMut<'a, T> {
31883277
}
31893278
}
31903279

3191-
iterator!{struct IterMut -> *mut T, &'a mut T, mut, mut}
3280+
iterator!{struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}}
31923281

31933282
/// An internal abstraction over the splitting iterators, so that
31943283
/// splitn, splitn_mut etc can be implemented once.

‎src/libcore/tests/iter.rs

+13
Original file line numberDiff line numberDiff line change
@@ -2235,3 +2235,16 @@ fn test_monad_laws_associativity() {
22352235
assert_eq!((0..10).flat_map(f).flat_map(g).sum::<usize>(),
22362236
(0..10).flat_map(|x| f(x).flat_map(g)).sum::<usize>());
22372237
}
2238+
2239+
#[test]
2240+
fn test_is_sorted() {
2241+
assert!([1, 2, 2, 9].iter().is_sorted());
2242+
assert!(![1, 3, 2].iter().is_sorted());
2243+
assert!([0].iter().is_sorted());
2244+
assert!(std::iter::empty::<i32>().is_sorted());
2245+
assert!(![0.0, 1.0, std::f32::NAN].iter().is_sorted());
2246+
assert!([-2, -1, 0, 3].iter().is_sorted());
2247+
assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs()));
2248+
assert!(!["c", "bb", "aaa"].iter().is_sorted());
2249+
assert!(["c", "bb", "aaa"].iter().is_sorted_by_key(|s| s.len()));
2250+
}

‎src/libcore/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#![feature(flt2dec)]
1111
#![feature(fmt_internals)]
1212
#![feature(hashmap_internals)]
13+
#![feature(is_sorted)]
1314
#![feature(iter_copied)]
1415
#![feature(iter_nth_back)]
1516
#![feature(iter_once_with)]

‎src/libcore/tests/slice.rs

+15
Original file line numberDiff line numberDiff line change
@@ -1317,3 +1317,18 @@ fn test_copy_within_panics_src_inverted() {
13171317
// 2 is greater than 1, so this range is invalid.
13181318
bytes.copy_within(2..1, 0);
13191319
}
1320+
1321+
#[test]
1322+
fn test_is_sorted() {
1323+
let empty: [i32; 0] = [];
1324+
1325+
assert!([1, 2, 2, 9].is_sorted());
1326+
assert!(![1, 3, 2].is_sorted());
1327+
assert!([0].is_sorted());
1328+
assert!(empty.is_sorted());
1329+
assert!(![0.0, 1.0, std::f32::NAN].is_sorted());
1330+
assert!([-2, -1, 0, 3].is_sorted());
1331+
assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs()));
1332+
assert!(!["c", "bb", "aaa"].is_sorted());
1333+
assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len()));
1334+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
fn main() {
2+
// Assert `Iterator` methods are feature gated
3+
assert!([1, 2, 2, 9].iter().is_sorted());
4+
//~^ ERROR: use of unstable library feature 'is_sorted': new API
5+
assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs()));
6+
//~^ ERROR: use of unstable library feature 'is_sorted': new API
7+
8+
// Assert `[T]` methods are feature gated
9+
assert!([1, 2, 2, 9].is_sorted());
10+
//~^ ERROR: use of unstable library feature 'is_sorted': new API
11+
assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs()));
12+
//~^ ERROR: use of unstable library feature 'is_sorted': new API
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
error[E0658]: use of unstable library feature 'is_sorted': new API (see issue #53485)
2+
--> $DIR/feature-gate-is_sorted.rs:3:33
3+
|
4+
LL | assert!([1, 2, 2, 9].iter().is_sorted());
5+
| ^^^^^^^^^
6+
|
7+
= help: add #![feature(is_sorted)] to the crate attributes to enable
8+
9+
error[E0658]: use of unstable library feature 'is_sorted': new API (see issue #53485)
10+
--> $DIR/feature-gate-is_sorted.rs:5:39
11+
|
12+
LL | assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs()));
13+
| ^^^^^^^^^^^^^^^^
14+
|
15+
= help: add #![feature(is_sorted)] to the crate attributes to enable
16+
17+
error[E0658]: use of unstable library feature 'is_sorted': new API (see issue #53485)
18+
--> $DIR/feature-gate-is_sorted.rs:9:26
19+
|
20+
LL | assert!([1, 2, 2, 9].is_sorted());
21+
| ^^^^^^^^^
22+
|
23+
= help: add #![feature(is_sorted)] to the crate attributes to enable
24+
25+
error[E0658]: use of unstable library feature 'is_sorted': new API (see issue #53485)
26+
--> $DIR/feature-gate-is_sorted.rs:11:32
27+
|
28+
LL | assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs()));
29+
| ^^^^^^^^^^^^^^^^
30+
|
31+
= help: add #![feature(is_sorted)] to the crate attributes to enable
32+
33+
error: aborting due to 4 previous errors
34+
35+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)
Please sign in to comment.