Skip to content

Commit 6c400e0

Browse files
Owen-CH-Leungjswrenn
authored andcommitted
Implement custom fold for ZipLongest
Add custom fold logic and benchmark
1 parent e01c929 commit 6c400e0

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

benches/bench1.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use criterion::{black_box, criterion_group, criterion_main, Criterion};
22
use itertools::free::cloned;
3-
use itertools::iproduct;
3+
use itertools::{EitherOrBoth, iproduct};
44
use itertools::Itertools;
55

66
use std::cmp;
@@ -390,6 +390,23 @@ fn zip_unchecked_counted_loop3(c: &mut Criterion) {
390390
});
391391
}
392392

393+
fn ziplongest(c: &mut Criterion) {
394+
c.bench_function("ziplongest", move |b| {
395+
b.iter(|| {
396+
let zip = (0..768).zip_longest(0..1024);
397+
let sum = zip.fold(0u32, |mut acc, val| {
398+
match val {
399+
EitherOrBoth::Both(x, y) => acc += x * y,
400+
EitherOrBoth::Left(x) => acc += x,
401+
EitherOrBoth::Right(y) => acc += y,
402+
}
403+
acc
404+
});
405+
sum
406+
})
407+
});
408+
}
409+
393410
fn group_by_lazy_1(c: &mut Criterion) {
394411
let mut data = vec![0; 1024];
395412
for (index, elt) in data.iter_mut().enumerate() {
@@ -821,6 +838,7 @@ criterion_group!(
821838
zipdot_i32_unchecked_counted_loop,
822839
zipdot_f32_unchecked_counted_loop,
823840
zip_unchecked_counted_loop3,
841+
ziplongest,
824842
group_by_lazy_1,
825843
group_by_lazy_2,
826844
slice_chunks,

src/zip_longest.rs

+25
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,31 @@ where
5252
fn size_hint(&self) -> (usize, Option<usize>) {
5353
size_hint::max(self.a.size_hint(), self.b.size_hint())
5454
}
55+
56+
#[inline]
57+
fn fold<B, F>(self, mut acc: B, mut f: F) -> B
58+
where
59+
Self: Sized, F: FnMut(B, Self::Item) -> B
60+
{
61+
let ZipLongest { mut a, mut b } = self;
62+
63+
loop {
64+
match (a.next(), b.next()) {
65+
(Some(x), Some(y)) => acc = f(acc, EitherOrBoth::Both(x, y)),
66+
(Some(x), None) => {
67+
acc = f(acc, EitherOrBoth::Left(x));
68+
// b is exhausted, so we can drain a.
69+
return a.fold(acc, |acc, x| f(acc, EitherOrBoth::Left(x)));
70+
}
71+
(None, Some(y)) => {
72+
acc = f(acc, EitherOrBoth::Right(y));
73+
// a is exhausted, so we can drain b.
74+
return b.fold(acc, |acc, y| f(acc, EitherOrBoth::Right(y)));
75+
}
76+
(None, None) => return acc, // Both iterators are exhausted.
77+
}
78+
}
79+
}
5580
}
5681

5782
impl<T, U> DoubleEndedIterator for ZipLongest<T, U>

0 commit comments

Comments
 (0)