From 8354839b4b121ba36850571d526c127d7b61a29e Mon Sep 17 00:00:00 2001
From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com>
Date: Sat, 21 Nov 2020 17:55:00 +0100
Subject: [PATCH 1/4] Add Iterator::find_or_{first,nth,last}
---
library/core/src/iter/traits/iterator.rs | 173 +++++++++++++++++++++++
library/core/tests/iter.rs | 56 ++++++++
2 files changed, 229 insertions(+)
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 19484bfd0419f..2805d2c827229 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -2231,6 +2231,179 @@ pub trait Iterator {
self.try_fold((), check(predicate)).break_value()
}
+ /// Searches for an element of an iterator that satisfies a predicate, returns the first
+ /// element if no such element is found.
+ ///
+ /// `find_or_first()` takes a closure that returns `true` or `false`. It applies this closure
+ /// to each element of the iterator, and if any of them return `true`, then `find_or_first()`
+ /// returns [`Some(element)`]. If they all return `false`, it returns the same as if [`next`]
+ /// was invoked instead, though the iterator will be empty.
+ ///
+ /// `find_or_first()` is short-circuiting; in other words, it will stop processing as soon as
+ /// closure returns `true`.
+ ///
+ /// Because `find_or_first()` takes a reference, and many iterators iterate over references,
+ /// this leads to a possibly confusing situation where the argument is a double reference. You
+ /// can see this effect in the examples below, with `&&x`.
+ ///
+ /// [`Some(element)`]: Some
+ /// [`next`]: Iterator::next
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(iter_find_or_fnl)]
+ ///
+ /// let a = [0, 1, 2, 3];
+ ///
+ /// assert_eq!(
+ /// a.iter().find_or_first(|&&x| x > 1),
+ /// Some(&2) // predicate is satisfied
+ /// );
+ /// assert_eq!(
+ /// a.iter().find_or_first(|&&x| x > 10),
+ /// Some(&0) // predicate not satisfied, first element is returned
+ /// );
+ /// ```
+ #[inline]
+ #[unstable(feature = "iter_find_or_fnl", reason = "recently added", issue = "none")]
+ fn find_or_first
(&mut self, mut predicate: P) -> Option
+ where
+ Self: Sized,
+ P: FnMut(&Self::Item) -> bool,
+ {
+ match self.next() {
+ Some(item) if predicate(&item) => Some(item),
+ default => self.find(predicate).or(default),
+ }
+ }
+
+ /// Searches for an element of an iterator that satisfies a predicate, returns the `n`th
+ /// element if no such element is found.
+ ///
+ /// `find_or_nth()` takes a closure that returns `true` or `false`. It applies this closure to
+ /// each element of the iterator, and if any of them return `true`, then `find_or_nth()`
+ /// returns [`Some(element)`]. If they all return `false`, it returns the same as if [`nth(n)`]
+ /// was invoked instead, though the iterator will be empty end.
+ ///
+ /// Like most indexing operations, the count starts from zero, so if `predicate` is never
+ /// satisfied, `find_or_nth(predicate, 0)` returns the first item, `find_or_nth(1)` the second,
+ /// and so on.
+ ///
+ /// `find_or_nth()` is short-circuiting; in other words, it will stop processing as soon as the
+ /// closure returns `true`.
+ ///
+ /// Because `find_or_nth()` takes a reference, and many iterators iterate over references, this
+ /// leads to a possibly confusing situation where the argument is a double reference. You can
+ /// see this effect in the examples below, with `&&x`.
+ ///
+ /// [`Some(element)`]: Some
+ /// [`nth(n)`]: Iterator::nth
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(iter_find_or_fnl)]
+ ///
+ /// let a = [0, 1, 2, 3];
+ ///
+ /// assert_eq!(
+ /// a.iter().find_or_nth(|&&x| x > 1, 2),
+ /// Some(&2) // predicate is satisfied
+ /// );
+ /// assert_eq!(
+ /// a.iter().find_or_nth(|&&x| x > 10, 2),
+ /// Some(&2) // predicate not satisfied, 3rd element is returned
+ /// );
+ /// assert_eq!(
+ /// a.iter().find_or_nth(|&&x| x > 10, 5),
+ /// None // predicate not satisfied, no 6th element
+ /// );
+ /// ```
+ #[inline]
+ #[unstable(feature = "iter_find_or_fnl", reason = "recently added", issue = "none")]
+ fn find_or_nth(&mut self, predicate: P, n: usize) -> Option
+ where
+ Self: Sized,
+ P: FnMut(&Self::Item) -> bool,
+ {
+ #[inline]
+ fn check(
+ mut predicate: impl FnMut(&T) -> bool,
+ n: usize,
+ ) -> impl FnMut(Option, (usize, T)) -> ControlFlow> {
+ move |prev, (idx, cur)| {
+ if predicate(&cur) {
+ ControlFlow::Break(cur)
+ } else if idx == n {
+ debug_assert!(prev.is_none());
+ ControlFlow::Continue(Some(cur))
+ } else {
+ debug_assert_eq!(idx < n, prev.is_none());
+ ControlFlow::Continue(prev)
+ }
+ }
+ }
+
+ self.enumerate().try_fold(None, check(predicate, n)).into_result().unwrap_or_else(Some)
+ }
+
+ /// Searches for an element of an iterator that satisfies a predicate, returns the last
+ /// element if no such element is found.
+ ///
+ /// `find_or_last()` takes a closure that returns `true` or `false`. It applies this closure to
+ /// each element of the iterator, and if any of them return `true`, then `find_or_last()`
+ /// returns [`Some(element)`]. If they all return `false`, it returns the same as if [`last`]
+ /// was invoked instead.
+ ///
+ /// `find_or_last()` is short-circuiting; in other words, it will stop processing as soon as the
+ /// closure returns `true`.
+ ///
+ /// Because `find_or_last()` takes a reference, and many iterators iterate over references, this
+ /// leads to a possibly confusing situation where the argument is a double reference. You can
+ /// see this effect in the examples below, with `&&x`.
+ ///
+ /// [`Some(element)`]: Some
+ /// [`last`]: Iterator::last
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(iter_find_or_fnl)]
+ ///
+ /// let a = [0, 1, 2, 3];
+ ///
+ /// assert_eq!(
+ /// a.iter().find_or_last(|&&x| x > 1),
+ /// Some(&2) // predicate is satisfied
+ /// );
+ /// assert_eq!(
+ /// a.iter().find_or_last(|&&x| x > 10),
+ /// Some(&3) // predicate not satisfied, last element is returned
+ /// );
+ /// ```
+ #[inline]
+ #[unstable(feature = "iter_find_or_fnl", reason = "recently added", issue = "none")]
+ fn find_or_last(&mut self, predicate: P) -> Option
+ where
+ Self: Sized,
+ P: FnMut(&Self::Item) -> bool,
+ {
+ #[inline]
+ fn check(
+ mut predicate: impl FnMut(&T) -> bool,
+ ) -> impl FnMut(Option, T) -> ControlFlow> {
+ move |_, cur| {
+ if predicate(&cur) {
+ ControlFlow::Break(cur)
+ } else {
+ ControlFlow::Continue(Some(cur))
+ }
+ }
+ }
+ self.try_fold(None, check(predicate)).into_result().unwrap_or_else(Some)
+ }
+
/// Applies function to the elements of iterator and returns
/// the first non-none result.
///
diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs
index 75ca897cadc91..176f0b231b100 100644
--- a/library/core/tests/iter.rs
+++ b/library/core/tests/iter.rs
@@ -1930,6 +1930,62 @@ fn test_find() {
assert!(v.iter().find(|&&x| x % 12 == 0).is_none());
}
+#[test]
+fn find_or_first() {
+ assert_eq!([0, 1, 2, 3].iter().find_or_first(|&&n| n > 1), Some(2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_first(|&&n| n > 2), Some(3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_first(|&&n| n > 3), Some(0));
+ assert_eq!([3, 2, 1, 0].iter().find_or_first(|&&n| n > 1), Some(3));
+ assert_eq!([1].iter().find_or_first(|&&n| n > 1), Some(1));
+ assert_eq!([2].iter().find_or_first(|&&n| n > 1), Some(2));
+ assert_eq!([(); 0].iter().find_or_first(|()| unreachable!()), None);
+}
+
+#[test]
+fn find_or_nth() {
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 0), Some(2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 1), Some(2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 2), Some(2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 3), Some(2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 4), Some(2));
+
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 0), Some(3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 1), Some(3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 2), Some(3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 3), Some(3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 4), Some(3));
+
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 0), Some(0));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 1), Some(1));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 2), Some(2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 3), Some(3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 4), None);
+
+ assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 0), Some(3));
+ assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 1), Some(3));
+ assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 2), Some(3));
+ assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 3), Some(3));
+ assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 4), Some(3));
+
+ assert_eq!([1].iter().find_or_nth(|&&n| n > 1, 0), Some(1));
+ assert_eq!([1].iter().find_or_nth(|&&n| n > 1, 1), None);
+ assert_eq!([2].iter().find_or_nth(|&&n| n > 1, 0), Some(2));
+ assert_eq!([2].iter().find_or_nth(|&&n| n > 1, 1), Some(2));
+
+ assert_eq!([(); 0].iter().find_or_nth(|()| unreachable!(), 0), None);
+}
+
+#[test]
+fn find_or_last() {
+ assert_eq!([0, 1, 2, 3].iter().find_or_last(|&&n| n > 1), Some(2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_last(|&&n| n > 2), Some(3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_last(|&&n| n > 3), Some(3));
+ assert_eq!([3, 2, 1, 0].iter().find_or_last(|&&n| n > 1), Some(3));
+ assert_eq!([1].iter().find_or_last(|&&n| n > 1), Some(1));
+ assert_eq!([2].iter().find_or_last(|&&n| n > 1), Some(2));
+ assert_eq!([(); 0].iter().find_or_last(|()| unreachable!()), None);
+}
+
#[test]
fn test_find_map() {
let xs: &[isize] = &[];
From df3133b9b30285e56fbbb6ed88c4c494ec16f306 Mon Sep 17 00:00:00 2001
From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com>
Date: Sat, 21 Nov 2020 19:09:44 +0100
Subject: [PATCH 2/4] Enable iter_find_or_fnl feature in libcore tests
---
library/core/tests/lib.rs | 1 +
1 file changed, 1 insertion(+)
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 14ef03fd53eba..ec9a454462261 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -43,6 +43,7 @@
#![feature(int_error_matching)]
#![feature(array_value_iter)]
#![feature(iter_advance_by)]
+#![feature(iter_next_or_fnl)]
#![feature(iter_partition_in_place)]
#![feature(iter_is_partitioned)]
#![feature(iter_order_by)]
From ce70e32c6f94dcd67ddd8b6e2aaf171e1c319372 Mon Sep 17 00:00:00 2001
From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com>
Date: Sat, 21 Nov 2020 19:45:31 +0100
Subject: [PATCH 3/4] Fix typos
---
library/core/src/iter/traits/iterator.rs | 2 +-
library/core/tests/lib.rs | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 2805d2c827229..8cda5d731aa90 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -2284,7 +2284,7 @@ pub trait Iterator {
/// `find_or_nth()` takes a closure that returns `true` or `false`. It applies this closure to
/// each element of the iterator, and if any of them return `true`, then `find_or_nth()`
/// returns [`Some(element)`]. If they all return `false`, it returns the same as if [`nth(n)`]
- /// was invoked instead, though the iterator will be empty end.
+ /// was invoked instead, though the iterator will be empty.
///
/// Like most indexing operations, the count starts from zero, so if `predicate` is never
/// satisfied, `find_or_nth(predicate, 0)` returns the first item, `find_or_nth(1)` the second,
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index ec9a454462261..fabf3c36f3417 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -43,7 +43,7 @@
#![feature(int_error_matching)]
#![feature(array_value_iter)]
#![feature(iter_advance_by)]
-#![feature(iter_next_or_fnl)]
+#![feature(iter_find_or_fnl)]
#![feature(iter_partition_in_place)]
#![feature(iter_is_partitioned)]
#![feature(iter_order_by)]
From c83d276bb0f2410553320bab33174a5dd17e3060 Mon Sep 17 00:00:00 2001
From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com>
Date: Sat, 21 Nov 2020 20:31:52 +0100
Subject: [PATCH 4/4] Fix iter_find_or_fnl tests
---
library/core/tests/iter.rs | 72 +++++++++++++++++++-------------------
1 file changed, 36 insertions(+), 36 deletions(-)
diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs
index 176f0b231b100..013989b5d32dd 100644
--- a/library/core/tests/iter.rs
+++ b/library/core/tests/iter.rs
@@ -1932,57 +1932,57 @@ fn test_find() {
#[test]
fn find_or_first() {
- assert_eq!([0, 1, 2, 3].iter().find_or_first(|&&n| n > 1), Some(2));
- assert_eq!([0, 1, 2, 3].iter().find_or_first(|&&n| n > 2), Some(3));
- assert_eq!([0, 1, 2, 3].iter().find_or_first(|&&n| n > 3), Some(0));
- assert_eq!([3, 2, 1, 0].iter().find_or_first(|&&n| n > 1), Some(3));
- assert_eq!([1].iter().find_or_first(|&&n| n > 1), Some(1));
- assert_eq!([2].iter().find_or_first(|&&n| n > 1), Some(2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_first(|&&n| n > 1), Some(&2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_first(|&&n| n > 2), Some(&3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_first(|&&n| n > 3), Some(&0));
+ assert_eq!([3, 2, 1, 0].iter().find_or_first(|&&n| n > 1), Some(&3));
+ assert_eq!([1].iter().find_or_first(|&&n| n > 1), Some(&1));
+ assert_eq!([2].iter().find_or_first(|&&n| n > 1), Some(&2));
assert_eq!([(); 0].iter().find_or_first(|()| unreachable!()), None);
}
#[test]
fn find_or_nth() {
- assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 0), Some(2));
- assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 1), Some(2));
- assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 2), Some(2));
- assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 3), Some(2));
- assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 4), Some(2));
-
- assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 0), Some(3));
- assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 1), Some(3));
- assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 2), Some(3));
- assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 3), Some(3));
- assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 4), Some(3));
-
- assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 0), Some(0));
- assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 1), Some(1));
- assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 2), Some(2));
- assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 3), Some(3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 0), Some(&2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 1), Some(&2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 2), Some(&2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 3), Some(&2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 4), Some(&2));
+
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 0), Some(&3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 1), Some(&3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 2), Some(&3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 3), Some(&3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 4), Some(&3));
+
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 0), Some(&0));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 1), Some(&1));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 2), Some(&2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 3), Some(&3));
assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 4), None);
- assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 0), Some(3));
- assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 1), Some(3));
- assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 2), Some(3));
- assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 3), Some(3));
- assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 4), Some(3));
+ assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 0), Some(&3));
+ assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 1), Some(&3));
+ assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 2), Some(&3));
+ assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 3), Some(&3));
+ assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 4), Some(&3));
- assert_eq!([1].iter().find_or_nth(|&&n| n > 1, 0), Some(1));
+ assert_eq!([1].iter().find_or_nth(|&&n| n > 1, 0), Some(&1));
assert_eq!([1].iter().find_or_nth(|&&n| n > 1, 1), None);
- assert_eq!([2].iter().find_or_nth(|&&n| n > 1, 0), Some(2));
- assert_eq!([2].iter().find_or_nth(|&&n| n > 1, 1), Some(2));
+ assert_eq!([2].iter().find_or_nth(|&&n| n > 1, 0), Some(&2));
+ assert_eq!([2].iter().find_or_nth(|&&n| n > 1, 1), Some(&2));
assert_eq!([(); 0].iter().find_or_nth(|()| unreachable!(), 0), None);
}
#[test]
fn find_or_last() {
- assert_eq!([0, 1, 2, 3].iter().find_or_last(|&&n| n > 1), Some(2));
- assert_eq!([0, 1, 2, 3].iter().find_or_last(|&&n| n > 2), Some(3));
- assert_eq!([0, 1, 2, 3].iter().find_or_last(|&&n| n > 3), Some(3));
- assert_eq!([3, 2, 1, 0].iter().find_or_last(|&&n| n > 1), Some(3));
- assert_eq!([1].iter().find_or_last(|&&n| n > 1), Some(1));
- assert_eq!([2].iter().find_or_last(|&&n| n > 1), Some(2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_last(|&&n| n > 1), Some(&2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_last(|&&n| n > 2), Some(&3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_last(|&&n| n > 3), Some(&3));
+ assert_eq!([3, 2, 1, 0].iter().find_or_last(|&&n| n > 1), Some(&3));
+ assert_eq!([1].iter().find_or_last(|&&n| n > 1), Some(&1));
+ assert_eq!([2].iter().find_or_last(|&&n| n > 1), Some(&2));
assert_eq!([(); 0].iter().find_or_last(|()| unreachable!()), None);
}