mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 17:24:06 +00:00
Add more custom folding to core::iter
adaptors
Many of the iterator adaptors will perform faster folds if they forward to their inner iterator's folds, especially for inner types like `Chain` which are optimized too. The following types are newly specialized: | Type | `fold` | `rfold` | | ----------- | ------ | ------- | | `Enumerate` | ✓ | ✓ | | `Filter` | ✓ | ✓ | | `FilterMap` | ✓ | ✓ | | `FlatMap` | exists | ✓ | | `Fuse` | ✓ | ✓ | | `Inspect` | ✓ | ✓ | | `Peekable` | ✓ | N/A¹ | | `Skip` | ✓ | N/A² | | `SkipWhile` | ✓ | N/A¹ | ¹ not a `DoubleEndedIterator` ² `Skip::next_back` doesn't pull skipped items at all, but this couldn't be avoided if `Skip::rfold` were to call its inner iterator's `rfold`. Benchmarks ---------- In the following results, plain `_sum` computes the sum of a million integers -- note that `sum()` is implemented with `fold()`. The `_ref_sum` variants do the same on a `by_ref()` iterator, which is limited to calling `next()` one by one, without specialized `fold`. The `chain` variants perform the same tests on two iterators chained together, to show a greater benefit of forwarding `fold` internally. test iter::bench_enumerate_chain_ref_sum ... bench: 2,216,264 ns/iter (+/- 29,228) test iter::bench_enumerate_chain_sum ... bench: 922,380 ns/iter (+/- 2,676) test iter::bench_enumerate_ref_sum ... bench: 476,094 ns/iter (+/- 7,110) test iter::bench_enumerate_sum ... bench: 476,438 ns/iter (+/- 3,334) test iter::bench_filter_chain_ref_sum ... bench: 2,266,095 ns/iter (+/- 6,051) test iter::bench_filter_chain_sum ... bench: 745,594 ns/iter (+/- 2,013) test iter::bench_filter_ref_sum ... bench: 889,696 ns/iter (+/- 1,188) test iter::bench_filter_sum ... bench: 667,325 ns/iter (+/- 1,894) test iter::bench_filter_map_chain_ref_sum ... bench: 2,259,195 ns/iter (+/- 353,440) test iter::bench_filter_map_chain_sum ... bench: 1,223,280 ns/iter (+/- 1,972) test iter::bench_filter_map_ref_sum ... bench: 611,607 ns/iter (+/- 2,507) test iter::bench_filter_map_sum ... bench: 611,610 ns/iter (+/- 472) test iter::bench_fuse_chain_ref_sum ... bench: 2,246,106 ns/iter (+/- 22,395) test iter::bench_fuse_chain_sum ... bench: 634,887 ns/iter (+/- 1,341) test iter::bench_fuse_ref_sum ... bench: 444,816 ns/iter (+/- 1,748) test iter::bench_fuse_sum ... bench: 316,954 ns/iter (+/- 2,616) test iter::bench_inspect_chain_ref_sum ... bench: 2,245,431 ns/iter (+/- 21,371) test iter::bench_inspect_chain_sum ... bench: 631,645 ns/iter (+/- 4,928) test iter::bench_inspect_ref_sum ... bench: 317,437 ns/iter (+/- 702) test iter::bench_inspect_sum ... bench: 315,942 ns/iter (+/- 4,320) test iter::bench_peekable_chain_ref_sum ... bench: 2,243,585 ns/iter (+/- 12,186) test iter::bench_peekable_chain_sum ... bench: 634,848 ns/iter (+/- 1,712) test iter::bench_peekable_ref_sum ... bench: 444,808 ns/iter (+/- 480) test iter::bench_peekable_sum ... bench: 317,133 ns/iter (+/- 3,309) test iter::bench_skip_chain_ref_sum ... bench: 1,778,734 ns/iter (+/- 2,198) test iter::bench_skip_chain_sum ... bench: 761,850 ns/iter (+/- 1,645) test iter::bench_skip_ref_sum ... bench: 478,207 ns/iter (+/- 119,252) test iter::bench_skip_sum ... bench: 315,614 ns/iter (+/- 3,054) test iter::bench_skip_while_chain_ref_sum ... bench: 2,486,370 ns/iter (+/- 4,845) test iter::bench_skip_while_chain_sum ... bench: 633,915 ns/iter (+/- 5,892) test iter::bench_skip_while_ref_sum ... bench: 666,926 ns/iter (+/- 804) test iter::bench_skip_while_sum ... bench: 444,405 ns/iter (+/- 571)
This commit is contained in:
parent
dcb4378e18
commit
13724fafdc
@ -147,40 +147,131 @@ fn bench_for_each_chain_ref_fold(b: &mut Bencher) {
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_flat_map_sum(b: &mut Bencher) {
|
||||
b.iter(|| -> i64 {
|
||||
(0i64..1000).flat_map(|x| x..x+1000)
|
||||
.map(black_box)
|
||||
.sum()
|
||||
});
|
||||
|
||||
/// Helper to benchmark `sum` for iterators taken by value which
|
||||
/// can optimize `fold`, and by reference which cannot.
|
||||
macro_rules! bench_sums {
|
||||
($bench_sum:ident, $bench_ref_sum:ident, $iter:expr) => {
|
||||
#[bench]
|
||||
fn $bench_sum(b: &mut Bencher) {
|
||||
b.iter(|| -> i64 {
|
||||
$iter.map(black_box).sum()
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn $bench_ref_sum(b: &mut Bencher) {
|
||||
b.iter(|| -> i64 {
|
||||
$iter.map(black_box).by_ref().sum()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_flat_map_ref_sum(b: &mut Bencher) {
|
||||
b.iter(|| -> i64 {
|
||||
(0i64..1000).flat_map(|x| x..x+1000)
|
||||
.map(black_box)
|
||||
.by_ref()
|
||||
.sum()
|
||||
});
|
||||
bench_sums! {
|
||||
bench_flat_map_sum,
|
||||
bench_flat_map_ref_sum,
|
||||
(0i64..1000).flat_map(|x| x..x+1000)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_flat_map_chain_sum(b: &mut Bencher) {
|
||||
b.iter(|| -> i64 {
|
||||
(0i64..1000000).flat_map(|x| once(x).chain(once(x)))
|
||||
.map(black_box)
|
||||
.sum()
|
||||
});
|
||||
bench_sums! {
|
||||
bench_flat_map_chain_sum,
|
||||
bench_flat_map_chain_ref_sum,
|
||||
(0i64..1000000).flat_map(|x| once(x).chain(once(x)))
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_flat_map_chain_ref_sum(b: &mut Bencher) {
|
||||
b.iter(|| -> i64 {
|
||||
(0i64..1000000).flat_map(|x| once(x).chain(once(x)))
|
||||
.map(black_box)
|
||||
.by_ref()
|
||||
.sum()
|
||||
});
|
||||
bench_sums! {
|
||||
bench_enumerate_sum,
|
||||
bench_enumerate_ref_sum,
|
||||
(0i64..1000000).enumerate().map(|(i, x)| x * i as i64)
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_enumerate_chain_sum,
|
||||
bench_enumerate_chain_ref_sum,
|
||||
(0i64..1000000).chain(0..1000000).enumerate().map(|(i, x)| x * i as i64)
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_filter_sum,
|
||||
bench_filter_ref_sum,
|
||||
(0i64..1000000).filter(|x| x % 2 == 0)
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_filter_chain_sum,
|
||||
bench_filter_chain_ref_sum,
|
||||
(0i64..1000000).chain(0..1000000).filter(|x| x % 2 == 0)
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_filter_map_sum,
|
||||
bench_filter_map_ref_sum,
|
||||
(0i64..1000000).filter_map(|x| x.checked_mul(x))
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_filter_map_chain_sum,
|
||||
bench_filter_map_chain_ref_sum,
|
||||
(0i64..1000000).chain(0..1000000).filter_map(|x| x.checked_mul(x))
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_fuse_sum,
|
||||
bench_fuse_ref_sum,
|
||||
(0i64..1000000).fuse()
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_fuse_chain_sum,
|
||||
bench_fuse_chain_ref_sum,
|
||||
(0i64..1000000).chain(0..1000000).fuse()
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_inspect_sum,
|
||||
bench_inspect_ref_sum,
|
||||
(0i64..1000000).inspect(|_| {})
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_inspect_chain_sum,
|
||||
bench_inspect_chain_ref_sum,
|
||||
(0i64..1000000).chain(0..1000000).inspect(|_| {})
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_peekable_sum,
|
||||
bench_peekable_ref_sum,
|
||||
(0i64..1000000).peekable()
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_peekable_chain_sum,
|
||||
bench_peekable_chain_ref_sum,
|
||||
(0i64..1000000).chain(0..1000000).peekable()
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_skip_sum,
|
||||
bench_skip_ref_sum,
|
||||
(0i64..1000000).skip(1000)
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_skip_chain_sum,
|
||||
bench_skip_chain_ref_sum,
|
||||
(0i64..1000000).chain(0..1000000).skip(1000)
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_skip_while_sum,
|
||||
bench_skip_while_ref_sum,
|
||||
(0i64..1000000).skip_while(|&x| x < 1000)
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_skip_while_chain_sum,
|
||||
bench_skip_while_chain_ref_sum,
|
||||
(0i64..1000000).chain(0..1000000).skip_while(|&x| x < 1000)
|
||||
}
|
||||
|
@ -1238,6 +1238,18 @@ impl<I: Iterator, P> Iterator for Filter<I, P> where P: FnMut(&I::Item) -> bool
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut predicate = self.predicate;
|
||||
self.iter.fold(init, move |acc, item| if predicate(&item) {
|
||||
fold(acc, item)
|
||||
} else {
|
||||
acc
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -1253,6 +1265,18 @@ impl<I: DoubleEndedIterator, P> DoubleEndedIterator for Filter<I, P>
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut predicate = self.predicate;
|
||||
self.iter.rfold(init, move |acc, item| if predicate(&item) {
|
||||
fold(acc, item)
|
||||
} else {
|
||||
acc
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
@ -1304,6 +1328,17 @@ impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
|
||||
let (_, upper) = self.iter.size_hint();
|
||||
(0, upper) // can't know a lower bound, due to the predicate
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut f = self.f;
|
||||
self.iter.fold(init, move |acc, item| match f(item) {
|
||||
Some(x) => fold(acc, x),
|
||||
None => acc,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -1319,6 +1354,17 @@ impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for FilterMap<I, F>
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut f = self.f;
|
||||
self.iter.rfold(init, move |acc, item| match f(item) {
|
||||
Some(x) => fold(acc, x),
|
||||
None => acc,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
@ -1383,6 +1429,19 @@ impl<I> Iterator for Enumerate<I> where I: Iterator {
|
||||
fn count(self) -> usize {
|
||||
self.iter.count()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut count = self.count;
|
||||
self.iter.fold(init, move |acc, item| {
|
||||
let acc = fold(acc, (count, item));
|
||||
count += 1;
|
||||
acc
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -1398,6 +1457,19 @@ impl<I> DoubleEndedIterator for Enumerate<I> where
|
||||
(self.count + len, a)
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
// Can safely add and subtract the count, as `ExactSizeIterator` promises
|
||||
// that the number of elements fits into a `usize`.
|
||||
let mut count = self.count + self.iter.len();
|
||||
self.iter.rfold(init, move |acc, item| {
|
||||
count -= 1;
|
||||
fold(acc, (count, item))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -1509,6 +1581,18 @@ impl<I: Iterator> Iterator for Peekable<I> {
|
||||
let hi = hi.and_then(|x| x.checked_add(peek_len));
|
||||
(lo, hi)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let acc = match self.peeked {
|
||||
Some(None) => return init,
|
||||
Some(Some(v)) => fold(init, v),
|
||||
None => init,
|
||||
};
|
||||
self.iter.fold(acc, fold)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -1617,6 +1701,19 @@ impl<I: Iterator, P> Iterator for SkipWhile<I, P>
|
||||
let (_, upper) = self.iter.size_hint();
|
||||
(0, upper) // can't know a lower bound, due to the predicate
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(mut self, mut init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
if !self.flag {
|
||||
match self.next() {
|
||||
Some(v) => init = fold(init, v),
|
||||
None => return init,
|
||||
}
|
||||
}
|
||||
self.iter.fold(init, fold)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
@ -1757,6 +1854,19 @@ impl<I> Iterator for Skip<I> where I: Iterator {
|
||||
|
||||
(lower, upper)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
if self.n > 0 {
|
||||
// nth(n) skips n+1
|
||||
if self.iter.nth(self.n - 1).is_none() {
|
||||
return init;
|
||||
}
|
||||
}
|
||||
self.iter.fold(init, fold)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -1979,6 +2089,16 @@ impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F> wher
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.frontiter.into_iter()
|
||||
.chain(self.iter.map(self.f).map(U::into_iter))
|
||||
.chain(self.backiter)
|
||||
.rfold(init, |acc, iter| iter.rfold(acc, &mut fold))
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
@ -2056,6 +2176,17 @@ impl<I> Iterator for Fuse<I> where I: Iterator {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
if self.done {
|
||||
init
|
||||
} else {
|
||||
self.iter.fold(init, fold)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -2070,6 +2201,17 @@ impl<I> DoubleEndedIterator for Fuse<I> where I: DoubleEndedIterator {
|
||||
next
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
if self.done {
|
||||
init
|
||||
} else {
|
||||
self.iter.rfold(init, fold)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<I> TrustedRandomAccess for Fuse<I>
|
||||
@ -2110,6 +2252,13 @@ impl<I> Iterator for Fuse<I> where I: FusedIterator {
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.iter.fold(init, fold)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "fused", reason = "recently added", issue = "35602")]
|
||||
@ -2120,6 +2269,13 @@ impl<I> DoubleEndedIterator for Fuse<I>
|
||||
fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
|
||||
self.iter.next_back()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.iter.rfold(init, fold)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2184,6 +2340,14 @@ impl<I: Iterator, F> Iterator for Inspect<I, F> where F: FnMut(&I::Item) {
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut f = self.f;
|
||||
self.iter.fold(init, move |acc, item| { f(&item); fold(acc, item) })
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -2195,6 +2359,14 @@ impl<I: DoubleEndedIterator, F> DoubleEndedIterator for Inspect<I, F>
|
||||
let next = self.iter.next_back();
|
||||
self.do_inspect(next)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut f = self.f;
|
||||
self.iter.rfold(init, move |acc, item| { f(&item); fold(acc, item) })
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -248,6 +248,25 @@ fn test_filter_map() {
|
||||
assert_eq!(it.collect::<Vec<usize>>(), [0*0, 2*2, 4*4, 6*6, 8*8]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_filter_map_fold() {
|
||||
let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||
let ys = [0*0, 2*2, 4*4, 6*6, 8*8];
|
||||
let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x*x) } else { None });
|
||||
let i = it.fold(0, |i, x| {
|
||||
assert_eq!(x, ys[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, ys.len());
|
||||
|
||||
let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x*x) } else { None });
|
||||
let i = it.rfold(ys.len(), |i, x| {
|
||||
assert_eq!(x, ys[i - 1]);
|
||||
i - 1
|
||||
});
|
||||
assert_eq!(i, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_enumerate() {
|
||||
let xs = [0, 1, 2, 3, 4, 5];
|
||||
@ -282,7 +301,31 @@ fn test_iterator_enumerate_nth() {
|
||||
#[test]
|
||||
fn test_iterator_enumerate_count() {
|
||||
let xs = [0, 1, 2, 3, 4, 5];
|
||||
assert_eq!(xs.iter().count(), 6);
|
||||
assert_eq!(xs.iter().enumerate().count(), 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_enumerate_fold() {
|
||||
let xs = [0, 1, 2, 3, 4, 5];
|
||||
let mut it = xs.iter().enumerate();
|
||||
// steal a couple to get an interesting offset
|
||||
assert_eq!(it.next(), Some((0, &0)));
|
||||
assert_eq!(it.next(), Some((1, &1)));
|
||||
let i = it.fold(2, |i, (j, &x)| {
|
||||
assert_eq!(i, j);
|
||||
assert_eq!(x, xs[j]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, xs.len());
|
||||
|
||||
let mut it = xs.iter().enumerate();
|
||||
assert_eq!(it.next(), Some((0, &0)));
|
||||
let i = it.rfold(xs.len() - 1, |i, (j, &x)| {
|
||||
assert_eq!(i, j);
|
||||
assert_eq!(x, xs[j]);
|
||||
i - 1
|
||||
});
|
||||
assert_eq!(i, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -291,6 +334,25 @@ fn test_iterator_filter_count() {
|
||||
assert_eq!(xs.iter().filter(|&&x| x % 2 == 0).count(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_filter_fold() {
|
||||
let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||
let ys = [0, 2, 4, 6, 8];
|
||||
let it = xs.iter().filter(|&&x| x % 2 == 0);
|
||||
let i = it.fold(0, |i, &x| {
|
||||
assert_eq!(x, ys[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, ys.len());
|
||||
|
||||
let it = xs.iter().filter(|&&x| x % 2 == 0);
|
||||
let i = it.rfold(ys.len(), |i, &x| {
|
||||
assert_eq!(x, ys[i - 1]);
|
||||
i - 1
|
||||
});
|
||||
assert_eq!(i, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_peekable() {
|
||||
let xs = vec![0, 1, 2, 3, 4, 5];
|
||||
@ -381,6 +443,18 @@ fn test_iterator_peekable_last() {
|
||||
assert_eq!(it.last(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_peekable_fold() {
|
||||
let xs = [0, 1, 2, 3, 4, 5];
|
||||
let mut it = xs.iter().peekable();
|
||||
assert_eq!(it.peek(), Some(&&0));
|
||||
let i = it.fold(0, |i, &x| {
|
||||
assert_eq!(x, xs[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, xs.len());
|
||||
}
|
||||
|
||||
/// This is an iterator that follows the Iterator contract,
|
||||
/// but it is not fused. After having returned None once, it will start
|
||||
/// producing elements if .next() is called again.
|
||||
@ -470,6 +544,26 @@ fn test_iterator_skip_while() {
|
||||
assert_eq!(i, ys.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_skip_while_fold() {
|
||||
let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
|
||||
let ys = [15, 16, 17, 19];
|
||||
let it = xs.iter().skip_while(|&x| *x < 15);
|
||||
let i = it.fold(0, |i, &x| {
|
||||
assert_eq!(x, ys[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, ys.len());
|
||||
|
||||
let mut it = xs.iter().skip_while(|&x| *x < 15);
|
||||
assert_eq!(it.next(), Some(&ys[0])); // process skips before folding
|
||||
let i = it.fold(1, |i, &x| {
|
||||
assert_eq!(x, ys[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, ys.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_skip() {
|
||||
let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
|
||||
@ -566,6 +660,26 @@ fn test_iterator_skip_last() {
|
||||
assert_eq!(it.last(), Some(&30));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_skip_fold() {
|
||||
let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
|
||||
let ys = [13, 15, 16, 17, 19, 20, 30];
|
||||
let it = xs.iter().skip(5);
|
||||
let i = it.fold(0, |i, &x| {
|
||||
assert_eq!(x, ys[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, ys.len());
|
||||
|
||||
let mut it = xs.iter().skip(5);
|
||||
assert_eq!(it.next(), Some(&ys[0])); // process skips before folding
|
||||
let i = it.fold(1, |i, &x| {
|
||||
assert_eq!(x, ys[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, ys.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_take() {
|
||||
let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
|
||||
@ -661,13 +775,22 @@ fn test_iterator_flat_map_fold() {
|
||||
let xs = [0, 3, 6];
|
||||
let ys = [1, 2, 3, 4, 5, 6, 7];
|
||||
let mut it = xs.iter().flat_map(|&x| x..x+3);
|
||||
it.next();
|
||||
it.next_back();
|
||||
assert_eq!(it.next(), Some(0));
|
||||
assert_eq!(it.next_back(), Some(8));
|
||||
let i = it.fold(0, |i, x| {
|
||||
assert_eq!(x, ys[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, ys.len());
|
||||
|
||||
let mut it = xs.iter().flat_map(|&x| x..x+3);
|
||||
assert_eq!(it.next(), Some(0));
|
||||
assert_eq!(it.next_back(), Some(8));
|
||||
let i = it.rfold(ys.len(), |i, x| {
|
||||
assert_eq!(x, ys[i - 1]);
|
||||
i - 1
|
||||
});
|
||||
assert_eq!(i, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -684,6 +807,32 @@ fn test_inspect() {
|
||||
assert_eq!(&xs[..], &ys[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inspect_fold() {
|
||||
let xs = [1, 2, 3, 4];
|
||||
let mut n = 0;
|
||||
{
|
||||
let it = xs.iter().inspect(|_| n += 1);
|
||||
let i = it.fold(0, |i, &x| {
|
||||
assert_eq!(x, xs[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, xs.len());
|
||||
}
|
||||
assert_eq!(n, xs.len());
|
||||
|
||||
let mut n = 0;
|
||||
{
|
||||
let it = xs.iter().inspect(|_| n += 1);
|
||||
let i = it.rfold(xs.len(), |i, &x| {
|
||||
assert_eq!(x, xs[i - 1]);
|
||||
i - 1
|
||||
});
|
||||
assert_eq!(i, 0);
|
||||
}
|
||||
assert_eq!(n, xs.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cycle() {
|
||||
let cycle_len = 3;
|
||||
@ -1241,6 +1390,31 @@ fn test_fuse_count() {
|
||||
// Can't check len now because count consumes.
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fuse_fold() {
|
||||
let xs = [0, 1, 2];
|
||||
let it = xs.iter(); // `FusedIterator`
|
||||
let i = it.fuse().fold(0, |i, &x| {
|
||||
assert_eq!(x, xs[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, xs.len());
|
||||
|
||||
let it = xs.iter(); // `FusedIterator`
|
||||
let i = it.fuse().rfold(xs.len(), |i, &x| {
|
||||
assert_eq!(x, xs[i - 1]);
|
||||
i - 1
|
||||
});
|
||||
assert_eq!(i, 0);
|
||||
|
||||
let it = xs.iter().scan((), |_, &x| Some(x)); // `!FusedIterator`
|
||||
let i = it.fuse().fold(0, |i, x| {
|
||||
assert_eq!(x, xs[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, xs.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_once() {
|
||||
let mut it = once(42);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#![feature(inclusive_range)]
|
||||
#![feature(inclusive_range_syntax)]
|
||||
#![feature(iter_rfind)]
|
||||
#![feature(iter_rfold)]
|
||||
#![feature(nonzero)]
|
||||
#![feature(rand)]
|
||||
#![feature(raw)]
|
||||
|
Loading…
Reference in New Issue
Block a user