Skip to content

Commit 5be48aa

Browse files
committed
Auto merge of #64572 - nnethercote:simplify-Iterator-methods, r=<try>
Simplify some `Iterator` methods. PR #64545 got a big speed-up by replacing a hot call to `all()` with explicit iteration. This is because the implementation of `all()` is excessively complex: it wraps the given predicate in a closure that returns a `LoopState`, passes that closure to `try_for_each()`, which wraps the first closure in a second closure, passes that second closure to `try_fold()`, which does the actual iteration using the second closure. A sufficient smart compiler could optimize all this away; rustc is currently not sufficiently smart. This commit does the following. - Changes the implementations of `all()`, `any()`, `find()` and `find_map()` to use the simplest possible code, rather than using `try_for_each()`. (I am reminded of "The Evolution of a Haskell Programmer".) These are both shorter and faster than the current implementations, and will permit the undoing of the `all()` removal in #64545. - Changes `ResultShunt::next()` so it doesn't call `self.find()`, because that was causing infinite recursion with the new implementation of `find()`, which itself calls `self.next()`. (I honestly don't know how the old implementation of `ResultShunt::next()` didn't cause an infinite loop, given that it also called `self.next()`, albeit via `try_for_each()` and `try_fold()`.) - Changes `nth()` to use `self.next()` in a while loop rather than `for x in self`, because using self-iteration within an iterator method seems dubious, and `self.next()` is used in all the other iterator methods.
2 parents 5283791 + 7e98fb9 commit 5be48aa

File tree

2 files changed

+26
-33
lines changed

2 files changed

+26
-33
lines changed

src/libcore/iter/adapters/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -2404,7 +2404,11 @@ impl<I, T, E> Iterator for ResultShunt<'_, I, E>
24042404
type Item = T;
24052405

24062406
fn next(&mut self) -> Option<Self::Item> {
2407-
self.find(|_| true)
2407+
match self.iter.next() {
2408+
Some(Ok(v)) => Some(v),
2409+
Some(Err(e)) => { *self.error = Err(e); None },
2410+
None => None,
2411+
}
24082412
}
24092413

24102414
fn size_hint(&self) -> (usize, Option<usize>) {

src/libcore/iter/traits/iterator.rs

+21-32
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ pub trait Iterator {
319319
#[inline]
320320
#[stable(feature = "rust1", since = "1.0.0")]
321321
fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
322-
for x in self {
322+
while let Some(x) = self.next() {
323323
if n == 0 { return Some(x) }
324324
n -= 1;
325325
}
@@ -1855,18 +1855,15 @@ pub trait Iterator {
18551855
/// ```
18561856
#[inline]
18571857
#[stable(feature = "rust1", since = "1.0.0")]
1858-
fn all<F>(&mut self, f: F) -> bool where
1858+
fn all<F>(&mut self, mut f: F) -> bool where
18591859
Self: Sized, F: FnMut(Self::Item) -> bool
18601860
{
1861-
#[inline]
1862-
fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut(T) -> LoopState<(), ()> {
1863-
move |x| {
1864-
if f(x) { LoopState::Continue(()) }
1865-
else { LoopState::Break(()) }
1861+
while let Some(x) = self.next() {
1862+
if !f(x) {
1863+
return false;
18661864
}
18671865
}
1868-
1869-
self.try_for_each(check(f)) == LoopState::Continue(())
1866+
true
18701867
}
18711868

18721869
/// Tests if any element of the iterator matches a predicate.
@@ -1908,19 +1905,16 @@ pub trait Iterator {
19081905
/// ```
19091906
#[inline]
19101907
#[stable(feature = "rust1", since = "1.0.0")]
1911-
fn any<F>(&mut self, f: F) -> bool where
1908+
fn any<F>(&mut self, mut f: F) -> bool where
19121909
Self: Sized,
19131910
F: FnMut(Self::Item) -> bool
19141911
{
1915-
#[inline]
1916-
fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut(T) -> LoopState<(), ()> {
1917-
move |x| {
1918-
if f(x) { LoopState::Break(()) }
1919-
else { LoopState::Continue(()) }
1912+
while let Some(x) = self.next() {
1913+
if f(x) {
1914+
return true;
19201915
}
19211916
}
1922-
1923-
self.try_for_each(check(f)) == LoopState::Break(())
1917+
false
19241918
}
19251919

19261920
/// Searches for an element of an iterator that satisfies a predicate.
@@ -1967,19 +1961,16 @@ pub trait Iterator {
19671961
/// ```
19681962
#[inline]
19691963
#[stable(feature = "rust1", since = "1.0.0")]
1970-
fn find<P>(&mut self, predicate: P) -> Option<Self::Item> where
1964+
fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item> where
19711965
Self: Sized,
19721966
P: FnMut(&Self::Item) -> bool,
19731967
{
1974-
#[inline]
1975-
fn check<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut(T) -> LoopState<(), T> {
1976-
move |x| {
1977-
if predicate(&x) { LoopState::Break(x) }
1978-
else { LoopState::Continue(()) }
1968+
while let Some(x) = self.next() {
1969+
if predicate(&x) {
1970+
return Some(x);
19791971
}
19801972
}
1981-
1982-
self.try_for_each(check(predicate)).break_value()
1973+
None
19831974
}
19841975

19851976
/// Applies function to the elements of iterator and returns
@@ -1999,19 +1990,17 @@ pub trait Iterator {
19991990
/// ```
20001991
#[inline]
20011992
#[stable(feature = "iterator_find_map", since = "1.30.0")]
2002-
fn find_map<B, F>(&mut self, f: F) -> Option<B> where
1993+
fn find_map<B, F>(&mut self, mut f: F) -> Option<B> where
20031994
Self: Sized,
20041995
F: FnMut(Self::Item) -> Option<B>,
20051996
{
2006-
#[inline]
2007-
fn check<T, B>(mut f: impl FnMut(T) -> Option<B>) -> impl FnMut(T) -> LoopState<(), B> {
2008-
move |x| match f(x) {
2009-
Some(x) => LoopState::Break(x),
2010-
None => LoopState::Continue(()),
1997+
while let Some(x) = self.next() {
1998+
if let Some(y) = f(x) {
1999+
return Some(y);
20112000
}
20122001
}
2002+
None
20132003

2014-
self.try_for_each(check(f)).break_value()
20152004
}
20162005

20172006
/// Searches for an element in an iterator, returning its index.

0 commit comments

Comments
 (0)