Rollup merge of #62205 - timvermeulen:iter_order_by, r=KodrAus
Add Iterator comparison methods that take a comparison function This PR adds `Iterator::{cmp_by, partial_cmp_by, eq_by, ne_by, lt_by, le_by, gt_by, ge_by}`. We already have `Iterator::{cmp, partial_cmp, ...}` which are less general (but not any simpler) than the ones I'm proposing here. I'm submitting this PR now because #61505 has been merged, so this change should not have a noticeable effect on the `Iterator` docs page size. The diff is quite messy, here's what I changed: - The logic of `cmp` / `partial_cmp` / `eq` is moved to `cmp_by` / `partial_cmp_by` / `eq_by` respectively, changing `x.cmp(&y)` to `cmp(&x, &y)` in the `cmp` method where `cmp` is the given comparison function (and similar for `partial_cmp_by` and `eq_by`). - `ne_by` / `lt_by` / `le_by` / `gt_by` / `ge_by` are each implemented in terms of one of the three methods above. - The existing comparison methods are each forwarded to their `_by` counterpart, passing one of `Ord::cmp` / `PartialOrd::partial_cmp` / `PartialEq::eq` as the comparison function. The corresponding `_by_key` methods aren't included because they're not as fundamental as the `_by` methods and can easily be implemented in terms of them. Is that reasonable, or would adding the `_by_key` methods be desirable for the sake of completeness? I didn't add any tests – I couldn't think of any that weren't already covered by our existing tests. Let me know if there's a particular test that would be useful to add.
This commit is contained in:
commit
0ac09aef84
@ -2557,10 +2557,40 @@ pub trait Iterator {
|
||||
/// assert_eq!([1, 2].iter().cmp([1].iter()), Ordering::Greater);
|
||||
/// ```
|
||||
#[stable(feature = "iter_order", since = "1.5.0")]
|
||||
fn cmp<I>(mut self, other: I) -> Ordering where
|
||||
fn cmp<I>(self, other: I) -> Ordering
|
||||
where
|
||||
I: IntoIterator<Item = Self::Item>,
|
||||
Self::Item: Ord,
|
||||
Self: Sized,
|
||||
{
|
||||
self.cmp_by(other, |x, y| x.cmp(&y))
|
||||
}
|
||||
|
||||
/// Lexicographically compares the elements of this `Iterator` with those
|
||||
/// of another with respect to the specified comparison function.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_order_by)]
|
||||
///
|
||||
/// use std::cmp::Ordering;
|
||||
///
|
||||
/// let xs = [1, 2, 3, 4];
|
||||
/// let ys = [1, 4, 9, 16];
|
||||
///
|
||||
/// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| x.cmp(&y)), Ordering::Less);
|
||||
/// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (x * x).cmp(&y)), Ordering::Equal);
|
||||
/// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (2 * x).cmp(&y)), Ordering::Greater);
|
||||
/// ```
|
||||
#[unstable(feature = "iter_order_by", issue = "0")]
|
||||
fn cmp_by<I, F>(mut self, other: I, mut cmp: F) -> Ordering
|
||||
where
|
||||
Self: Sized,
|
||||
I: IntoIterator,
|
||||
F: FnMut(Self::Item, I::Item) -> Ordering,
|
||||
{
|
||||
let mut other = other.into_iter();
|
||||
|
||||
@ -2579,7 +2609,7 @@ pub trait Iterator {
|
||||
Some(val) => val,
|
||||
};
|
||||
|
||||
match x.cmp(&y) {
|
||||
match cmp(x, y) {
|
||||
Ordering::Equal => (),
|
||||
non_eq => return non_eq,
|
||||
}
|
||||
@ -2601,10 +2631,49 @@ pub trait Iterator {
|
||||
/// assert_eq!([std::f64::NAN].iter().partial_cmp([1.].iter()), None);
|
||||
/// ```
|
||||
#[stable(feature = "iter_order", since = "1.5.0")]
|
||||
fn partial_cmp<I>(mut self, other: I) -> Option<Ordering> where
|
||||
fn partial_cmp<I>(self, other: I) -> Option<Ordering>
|
||||
where
|
||||
I: IntoIterator,
|
||||
Self::Item: PartialOrd<I::Item>,
|
||||
Self: Sized,
|
||||
{
|
||||
self.partial_cmp_by(other, |x, y| x.partial_cmp(&y))
|
||||
}
|
||||
|
||||
/// Lexicographically compares the elements of this `Iterator` with those
|
||||
/// of another with respect to the specified comparison function.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_order_by)]
|
||||
///
|
||||
/// use std::cmp::Ordering;
|
||||
///
|
||||
/// let xs = [1.0, 2.0, 3.0, 4.0];
|
||||
/// let ys = [1.0, 4.0, 9.0, 16.0];
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// xs.iter().partial_cmp_by(&ys, |&x, &y| x.partial_cmp(&y)),
|
||||
/// Some(Ordering::Less)
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// xs.iter().partial_cmp_by(&ys, |&x, &y| (x * x).partial_cmp(&y)),
|
||||
/// Some(Ordering::Equal)
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// xs.iter().partial_cmp_by(&ys, |&x, &y| (2.0 * x).partial_cmp(&y)),
|
||||
/// Some(Ordering::Greater)
|
||||
/// );
|
||||
/// ```
|
||||
#[unstable(feature = "iter_order_by", issue = "0")]
|
||||
fn partial_cmp_by<I, F>(mut self, other: I, mut partial_cmp: F) -> Option<Ordering>
|
||||
where
|
||||
Self: Sized,
|
||||
I: IntoIterator,
|
||||
F: FnMut(Self::Item, I::Item) -> Option<Ordering>,
|
||||
{
|
||||
let mut other = other.into_iter();
|
||||
|
||||
@ -2623,7 +2692,7 @@ pub trait Iterator {
|
||||
Some(val) => val,
|
||||
};
|
||||
|
||||
match x.partial_cmp(&y) {
|
||||
match partial_cmp(x, y) {
|
||||
Some(Ordering::Equal) => (),
|
||||
non_eq => return non_eq,
|
||||
}
|
||||
@ -2640,10 +2709,36 @@ pub trait Iterator {
|
||||
/// assert_eq!([1].iter().eq([1, 2].iter()), false);
|
||||
/// ```
|
||||
#[stable(feature = "iter_order", since = "1.5.0")]
|
||||
fn eq<I>(mut self, other: I) -> bool where
|
||||
fn eq<I>(self, other: I) -> bool
|
||||
where
|
||||
I: IntoIterator,
|
||||
Self::Item: PartialEq<I::Item>,
|
||||
Self: Sized,
|
||||
{
|
||||
self.eq_by(other, |x, y| x == y)
|
||||
}
|
||||
|
||||
/// Determines if the elements of this `Iterator` are equal to those of
|
||||
/// another with respect to the specified equality function.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_order_by)]
|
||||
///
|
||||
/// let xs = [1, 2, 3, 4];
|
||||
/// let ys = [1, 4, 9, 16];
|
||||
///
|
||||
/// assert!(xs.iter().eq_by(&ys, |&x, &y| x * x == y));
|
||||
/// ```
|
||||
#[unstable(feature = "iter_order_by", issue = "0")]
|
||||
fn eq_by<I, F>(mut self, other: I, mut eq: F) -> bool
|
||||
where
|
||||
Self: Sized,
|
||||
I: IntoIterator,
|
||||
F: FnMut(Self::Item, I::Item) -> bool,
|
||||
{
|
||||
let mut other = other.into_iter();
|
||||
|
||||
@ -2658,7 +2753,9 @@ pub trait Iterator {
|
||||
Some(val) => val,
|
||||
};
|
||||
|
||||
if x != y { return false }
|
||||
if !eq(x, y) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,62 @@ fn test_multi_iter() {
|
||||
assert!(xs.iter().lt(xs.iter().skip(2)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cmp_by() {
|
||||
use core::cmp::Ordering;
|
||||
|
||||
let f = |x: i32, y: i32| (x * x).cmp(&y);
|
||||
let xs = || [1, 2, 3, 4].iter().copied();
|
||||
let ys = || [1, 4, 16].iter().copied();
|
||||
|
||||
assert_eq!(xs().cmp_by(ys(), f), Ordering::Less);
|
||||
assert_eq!(ys().cmp_by(xs(), f), Ordering::Greater);
|
||||
assert_eq!(xs().cmp_by(xs().map(|x| x * x), f), Ordering::Equal);
|
||||
assert_eq!(xs().rev().cmp_by(ys().rev(), f), Ordering::Greater);
|
||||
assert_eq!(xs().cmp_by(ys().rev(), f), Ordering::Less);
|
||||
assert_eq!(xs().cmp_by(ys().take(2), f), Ordering::Greater);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_partial_cmp_by() {
|
||||
use core::cmp::Ordering;
|
||||
use core::f64;
|
||||
|
||||
let f = |x: i32, y: i32| (x * x).partial_cmp(&y);
|
||||
let xs = || [1, 2, 3, 4].iter().copied();
|
||||
let ys = || [1, 4, 16].iter().copied();
|
||||
|
||||
assert_eq!(xs().partial_cmp_by(ys(), f), Some(Ordering::Less));
|
||||
assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater));
|
||||
assert_eq!(xs().partial_cmp_by(xs().map(|x| x * x), f), Some(Ordering::Equal));
|
||||
assert_eq!(xs().rev().partial_cmp_by(ys().rev(), f), Some(Ordering::Greater));
|
||||
assert_eq!(xs().partial_cmp_by(xs().rev(), f), Some(Ordering::Less));
|
||||
assert_eq!(xs().partial_cmp_by(ys().take(2), f), Some(Ordering::Greater));
|
||||
|
||||
let f = |x: f64, y: f64| (x * x).partial_cmp(&y);
|
||||
let xs = || [1.0, 2.0, 3.0, 4.0].iter().copied();
|
||||
let ys = || [1.0, 4.0, f64::NAN, 16.0].iter().copied();
|
||||
|
||||
assert_eq!(xs().partial_cmp_by(ys(), f), None);
|
||||
assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eq_by() {
|
||||
let f = |x: i32, y: i32| x * x == y;
|
||||
let xs = || [1, 2, 3, 4].iter().copied();
|
||||
let ys = || [1, 4, 9, 16].iter().copied();
|
||||
|
||||
assert!(xs().eq_by(ys(), f));
|
||||
assert!(!ys().eq_by(xs(), f));
|
||||
assert!(!xs().eq_by(xs(), f));
|
||||
assert!(!ys().eq_by(ys(), f));
|
||||
|
||||
assert!(!xs().take(3).eq_by(ys(), f));
|
||||
assert!(!xs().eq_by(ys().take(3), f));
|
||||
assert!(xs().take(3).eq_by(ys().take(3), f));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_counter_from_iter() {
|
||||
let it = (0..).step_by(5).take(10);
|
||||
|
@ -33,6 +33,7 @@
|
||||
#![feature(const_fn)]
|
||||
#![feature(iter_partition_in_place)]
|
||||
#![feature(iter_is_partitioned)]
|
||||
#![feature(iter_order_by)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user