1
Fork 0

Rollup merge of #58730 - timvermeulen:internal_iteration, r=scottmcm

Have all methods of Filter and FilterMap use internal iteration

This PR changes `Filter::{next, next_back, count}` and `FilterMap::{next, next_back}` to all use internal iteration. The `next` and `next_back` methods are changed to directly forward to `try_for_each` and `try_rfold` respectively, using `Result` as the `Try` type. I think that's okay? Alternatively, I could change their implementations to use `LoopState` instead if there's any benefit in doing so.

r? @scottmcm
This commit is contained in:
kennytm 2019-03-02 14:55:06 +08:00
commit 2e82d11de1
No known key found for this signature in database
GPG key ID: FEF6C8051D0E013C
2 changed files with 37 additions and 32 deletions

View file

@ -185,13 +185,13 @@ bench_sums! {
bench_sums! { bench_sums! {
bench_filter_sum, bench_filter_sum,
bench_filter_ref_sum, bench_filter_ref_sum,
(0i64..1000000).filter(|x| x % 2 == 0) (0i64..1000000).filter(|x| x % 3 == 0)
} }
bench_sums! { bench_sums! {
bench_filter_chain_sum, bench_filter_chain_sum,
bench_filter_chain_ref_sum, bench_filter_chain_ref_sum,
(0i64..1000000).chain(0..1000000).filter(|x| x % 2 == 0) (0i64..1000000).chain(0..1000000).filter(|x| x % 3 == 0)
} }
bench_sums! { bench_sums! {
@ -306,3 +306,31 @@ fn bench_skip_then_zip(b: &mut Bencher) {
assert_eq!(s, 2009900); assert_eq!(s, 2009900);
}); });
} }
#[bench]
fn bench_filter_count(b: &mut Bencher) {
b.iter(|| {
(0i64..1000000).map(black_box).filter(|x| x % 3 == 0).count()
})
}
#[bench]
fn bench_filter_ref_count(b: &mut Bencher) {
b.iter(|| {
(0i64..1000000).map(black_box).by_ref().filter(|x| x % 3 == 0).count()
})
}
#[bench]
fn bench_filter_chain_count(b: &mut Bencher) {
b.iter(|| {
(0i64..1000000).chain(0..1000000).map(black_box).filter(|x| x % 3 == 0).count()
})
}
#[bench]
fn bench_filter_chain_ref_count(b: &mut Bencher) {
b.iter(|| {
(0i64..1000000).chain(0..1000000).map(black_box).by_ref().filter(|x| x % 3 == 0).count()
})
}

View file

@ -681,12 +681,7 @@ impl<I: Iterator, P> Iterator for Filter<I, P> where P: FnMut(&I::Item) -> bool
#[inline] #[inline]
fn next(&mut self) -> Option<I::Item> { fn next(&mut self) -> Option<I::Item> {
for x in &mut self.iter { self.try_for_each(Err).err()
if (self.predicate)(&x) {
return Some(x);
}
}
None
} }
#[inline] #[inline]
@ -707,12 +702,9 @@ impl<I: Iterator, P> Iterator for Filter<I, P> where P: FnMut(&I::Item) -> bool
// Using the branchless version will also simplify the LLVM byte code, thus // Using the branchless version will also simplify the LLVM byte code, thus
// leaving more budget for LLVM optimizations. // leaving more budget for LLVM optimizations.
#[inline] #[inline]
fn count(mut self) -> usize { fn count(self) -> usize {
let mut count = 0; let mut predicate = self.predicate;
for x in &mut self.iter { self.iter.map(|x| predicate(&x) as usize).sum()
count += (self.predicate)(&x) as usize;
}
count
} }
#[inline] #[inline]
@ -746,12 +738,7 @@ impl<I: DoubleEndedIterator, P> DoubleEndedIterator for Filter<I, P>
{ {
#[inline] #[inline]
fn next_back(&mut self) -> Option<I::Item> { fn next_back(&mut self) -> Option<I::Item> {
for x in self.iter.by_ref().rev() { self.try_rfold((), |_, x| Err(x)).err()
if (self.predicate)(&x) {
return Some(x);
}
}
None
} }
#[inline] #[inline]
@ -820,12 +807,7 @@ impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
#[inline] #[inline]
fn next(&mut self) -> Option<B> { fn next(&mut self) -> Option<B> {
for x in self.iter.by_ref() { self.try_for_each(Err).err()
if let Some(y) = (self.f)(x) {
return Some(y);
}
}
None
} }
#[inline] #[inline]
@ -863,12 +845,7 @@ impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for FilterMap<I, F>
{ {
#[inline] #[inline]
fn next_back(&mut self) -> Option<B> { fn next_back(&mut self) -> Option<B> {
for x in self.iter.by_ref().rev() { self.try_rfold((), |_, x| Err(x)).err()
if let Some(y) = (self.f)(x) {
return Some(y);
}
}
None
} }
#[inline] #[inline]