Skip to content

Commit 63bacf1

Browse files
committed
Auto merge of #82162 - cuviper:flat-fold, r=Mark-Simulacrum
Expand FlattenCompat folds The former `chain`+`chain`+`fold` implementation looked nice from a functional-programming perspective, but it introduced unnecessary layers of abstraction on every `flat_map`/`flatten` fold. It's straightforward to just fold each part in turn, and this makes it look like a simplified version of the existing `try_fold` implementation. For the `iter::bench_flat_map*` benchmarks, I get a large improvement in `bench_flat_map_chain_sum`, from 1,598,473 ns/iter to 499,889 ns/iter, and the rest are unchanged.
2 parents 1fdadbf + fc150d1 commit 63bacf1

File tree

1 file changed

+35
-20
lines changed

1 file changed

+35
-20
lines changed

library/core/src/iter/adapters/flatten.rs

+35-20
Original file line numberDiff line numberDiff line change
@@ -325,22 +325,28 @@ where
325325
}
326326

327327
#[inline]
328-
fn fold<Acc, Fold>(self, init: Acc, ref mut fold: Fold) -> Acc
328+
fn fold<Acc, Fold>(self, mut init: Acc, mut fold: Fold) -> Acc
329329
where
330330
Fold: FnMut(Acc, Self::Item) -> Acc,
331331
{
332332
#[inline]
333-
fn flatten<U: Iterator, Acc>(
334-
fold: &mut impl FnMut(Acc, U::Item) -> Acc,
335-
) -> impl FnMut(Acc, U) -> Acc + '_ {
336-
move |acc, iter| iter.fold(acc, &mut *fold)
333+
fn flatten<T: IntoIterator, Acc>(
334+
fold: &mut impl FnMut(Acc, T::Item) -> Acc,
335+
) -> impl FnMut(Acc, T) -> Acc + '_ {
336+
move |acc, x| x.into_iter().fold(acc, &mut *fold)
337337
}
338338

339-
self.frontiter
340-
.into_iter()
341-
.chain(self.iter.map(IntoIterator::into_iter))
342-
.chain(self.backiter)
343-
.fold(init, flatten(fold))
339+
if let Some(front) = self.frontiter {
340+
init = front.fold(init, &mut fold);
341+
}
342+
343+
init = self.iter.fold(init, flatten(&mut fold));
344+
345+
if let Some(back) = self.backiter {
346+
init = back.fold(init, &mut fold);
347+
}
348+
349+
init
344350
}
345351
}
346352

@@ -411,21 +417,30 @@ where
411417
}
412418

413419
#[inline]
414-
fn rfold<Acc, Fold>(self, init: Acc, ref mut fold: Fold) -> Acc
420+
fn rfold<Acc, Fold>(self, mut init: Acc, mut fold: Fold) -> Acc
415421
where
416422
Fold: FnMut(Acc, Self::Item) -> Acc,
417423
{
418424
#[inline]
419-
fn flatten<U: DoubleEndedIterator, Acc>(
420-
fold: &mut impl FnMut(Acc, U::Item) -> Acc,
421-
) -> impl FnMut(Acc, U) -> Acc + '_ {
422-
move |acc, iter| iter.rfold(acc, &mut *fold)
425+
fn flatten<T: IntoIterator, Acc>(
426+
fold: &mut impl FnMut(Acc, T::Item) -> Acc,
427+
) -> impl FnMut(Acc, T) -> Acc + '_
428+
where
429+
T::IntoIter: DoubleEndedIterator,
430+
{
431+
move |acc, x| x.into_iter().rfold(acc, &mut *fold)
432+
}
433+
434+
if let Some(back) = self.backiter {
435+
init = back.rfold(init, &mut fold);
436+
}
437+
438+
init = self.iter.rfold(init, flatten(&mut fold));
439+
440+
if let Some(front) = self.frontiter {
441+
init = front.rfold(init, &mut fold);
423442
}
424443

425-
self.frontiter
426-
.into_iter()
427-
.chain(self.iter.map(IntoIterator::into_iter))
428-
.chain(self.backiter)
429-
.rfold(init, flatten(fold))
444+
init
430445
}
431446
}

0 commit comments

Comments
 (0)