Skip to content

Commit 5c52f9f

Browse files
authored
Rollup merge of #72139 - nnethercote:standalone-fold, r=cuviper
Make `fold` standalone. `fold` is currently implemented via `try_fold`, but implementing it directly results in slightly less LLVM IR being generated, speeding up compilation of some benchmarks. r? @cuviper
2 parents 14c4391 + 959bd48 commit 5c52f9f

File tree

6 files changed

+199
-44
lines changed

6 files changed

+199
-44
lines changed

src/libcore/iter/adapters/mod.rs

+144
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,9 @@ where
512512
acc = self.iter.try_fold(acc, &mut f)?;
513513
}
514514
}
515+
516+
// No `fold` override, because `fold` doesn't make much sense for `Cycle`,
517+
// and we can't do anything better than the default.
515518
}
516519

517520
#[stable(feature = "fused", since = "1.26.0")]
@@ -643,6 +646,25 @@ where
643646
}
644647
from_fn(nth(&mut self.iter, self.step)).try_fold(acc, f)
645648
}
649+
650+
fn fold<Acc, F>(mut self, mut acc: Acc, mut f: F) -> Acc
651+
where
652+
F: FnMut(Acc, Self::Item) -> Acc,
653+
{
654+
#[inline]
655+
fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ {
656+
move || iter.nth(step)
657+
}
658+
659+
if self.first_take {
660+
self.first_take = false;
661+
match self.iter.next() {
662+
None => return acc,
663+
Some(x) => acc = f(acc, x),
664+
}
665+
}
666+
from_fn(nth(&mut self.iter, self.step)).fold(acc, f)
667+
}
646668
}
647669

648670
impl<I> StepBy<I>
@@ -702,6 +724,29 @@ where
702724
}
703725
}
704726
}
727+
728+
#[inline]
729+
fn rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
730+
where
731+
Self: Sized,
732+
F: FnMut(Acc, Self::Item) -> Acc,
733+
{
734+
#[inline]
735+
fn nth_back<I: DoubleEndedIterator>(
736+
iter: &mut I,
737+
step: usize,
738+
) -> impl FnMut() -> Option<I::Item> + '_ {
739+
move || iter.nth_back(step)
740+
}
741+
742+
match self.next_back() {
743+
None => init,
744+
Some(x) => {
745+
let acc = f(init, x);
746+
from_fn(nth_back(&mut self.iter, self.step)).fold(acc, f)
747+
}
748+
}
749+
}
705750
}
706751

707752
// StepBy can only make the iterator shorter, so the len will still fit.
@@ -1767,6 +1812,20 @@ where
17671812
self.iter.try_fold(init, check(flag, p, fold)).into_try()
17681813
}
17691814
}
1815+
1816+
#[inline]
1817+
fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
1818+
where
1819+
Self: Sized,
1820+
Fold: FnMut(Acc, Self::Item) -> Acc,
1821+
{
1822+
#[inline]
1823+
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
1824+
move |acc, x| Ok(f(acc, x))
1825+
}
1826+
1827+
self.try_fold(init, ok(fold)).unwrap()
1828+
}
17701829
}
17711830

17721831
#[stable(feature = "fused", since = "1.26.0")]
@@ -1838,6 +1897,20 @@ where
18381897
})
18391898
.into_try()
18401899
}
1900+
1901+
#[inline]
1902+
fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
1903+
where
1904+
Self: Sized,
1905+
Fold: FnMut(Acc, Self::Item) -> Acc,
1906+
{
1907+
#[inline]
1908+
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
1909+
move |acc, x| Ok(f(acc, x))
1910+
}
1911+
1912+
self.try_fold(init, ok(fold)).unwrap()
1913+
}
18411914
}
18421915

18431916
/// An iterator that skips over `n` elements of `iter`.
@@ -2006,6 +2079,18 @@ where
20062079
self.iter.try_rfold(init, check(n, fold)).into_try()
20072080
}
20082081
}
2082+
2083+
fn rfold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
2084+
where
2085+
Fold: FnMut(Acc, Self::Item) -> Acc,
2086+
{
2087+
#[inline]
2088+
fn ok<Acc, T>(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, T) -> Result<Acc, !> {
2089+
move |acc, x| Ok(f(acc, x))
2090+
}
2091+
2092+
self.try_rfold(init, ok(fold)).unwrap()
2093+
}
20092094
}
20102095

20112096
#[stable(feature = "fused", since = "1.26.0")]
@@ -2105,6 +2190,20 @@ where
21052190
self.iter.try_fold(init, check(n, fold)).into_try()
21062191
}
21072192
}
2193+
2194+
#[inline]
2195+
fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
2196+
where
2197+
Self: Sized,
2198+
Fold: FnMut(Acc, Self::Item) -> Acc,
2199+
{
2200+
#[inline]
2201+
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
2202+
move |acc, x| Ok(f(acc, x))
2203+
}
2204+
2205+
self.try_fold(init, ok(fold)).unwrap()
2206+
}
21082207
}
21092208

21102209
#[stable(feature = "double_ended_take_iterator", since = "1.38.0")]
@@ -2156,6 +2255,24 @@ where
21562255
}
21572256
}
21582257
}
2258+
2259+
#[inline]
2260+
fn rfold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
2261+
where
2262+
Self: Sized,
2263+
Fold: FnMut(Acc, Self::Item) -> Acc,
2264+
{
2265+
if self.n == 0 {
2266+
init
2267+
} else {
2268+
let len = self.iter.len();
2269+
if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() {
2270+
init
2271+
} else {
2272+
self.iter.rfold(init, fold)
2273+
}
2274+
}
2275+
}
21592276
}
21602277

21612278
#[stable(feature = "rust1", since = "1.0.0")]
@@ -2237,6 +2354,20 @@ where
22372354
let f = &mut self.f;
22382355
self.iter.try_fold(init, scan(state, f, fold)).into_try()
22392356
}
2357+
2358+
#[inline]
2359+
fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
2360+
where
2361+
Self: Sized,
2362+
Fold: FnMut(Acc, Self::Item) -> Acc,
2363+
{
2364+
#[inline]
2365+
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
2366+
move |acc, x| Ok(f(acc, x))
2367+
}
2368+
2369+
self.try_fold(init, ok(fold)).unwrap()
2370+
}
22402371
}
22412372

22422373
/// An iterator that calls a function with a reference to each element before
@@ -2444,4 +2575,17 @@ where
24442575
})
24452576
.into_try()
24462577
}
2578+
2579+
fn fold<B, F>(mut self, init: B, fold: F) -> B
2580+
where
2581+
Self: Sized,
2582+
F: FnMut(B, Self::Item) -> B,
2583+
{
2584+
#[inline]
2585+
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
2586+
move |acc, x| Ok(f(acc, x))
2587+
}
2588+
2589+
self.try_fold(init, ok(fold)).unwrap()
2590+
}
24472591
}

src/libcore/iter/range.rs

+28
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,20 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
658658
Try::from_ok(accum)
659659
}
660660

661+
#[inline]
662+
fn fold<B, F>(mut self, init: B, f: F) -> B
663+
where
664+
Self: Sized,
665+
F: FnMut(B, Self::Item) -> B,
666+
{
667+
#[inline]
668+
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
669+
move |acc, x| Ok(f(acc, x))
670+
}
671+
672+
self.try_fold(init, ok(f)).unwrap()
673+
}
674+
661675
#[inline]
662676
fn last(mut self) -> Option<A> {
663677
self.next_back()
@@ -746,6 +760,20 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
746760

747761
Try::from_ok(accum)
748762
}
763+
764+
#[inline]
765+
fn rfold<B, F>(mut self, init: B, f: F) -> B
766+
where
767+
Self: Sized,
768+
F: FnMut(B, Self::Item) -> B,
769+
{
770+
#[inline]
771+
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
772+
move |acc, x| Ok(f(acc, x))
773+
}
774+
775+
self.try_rfold(init, ok(f)).unwrap()
776+
}
749777
}
750778

751779
#[unstable(feature = "trusted_len", issue = "37572")]

src/libcore/iter/traits/double_ended.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -221,17 +221,16 @@ pub trait DoubleEndedIterator: Iterator {
221221
/// ```
222222
#[inline]
223223
#[stable(feature = "iter_rfold", since = "1.27.0")]
224-
fn rfold<B, F>(mut self, accum: B, f: F) -> B
224+
fn rfold<B, F>(mut self, init: B, mut f: F) -> B
225225
where
226226
Self: Sized,
227227
F: FnMut(B, Self::Item) -> B,
228228
{
229-
#[inline]
230-
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
231-
move |acc, x| Ok(f(acc, x))
229+
let mut accum = init;
230+
while let Some(x) = self.next_back() {
231+
accum = f(accum, x);
232232
}
233-
234-
self.try_rfold(accum, ok(f)).unwrap()
233+
accum
235234
}
236235

237236
/// Searches for an element of an iterator from the back that satisfies a predicate.

src/libcore/iter/traits/iterator.rs

+22-14
Original file line numberDiff line numberDiff line change
@@ -1697,8 +1697,8 @@ pub trait Iterator {
16971697
mut f: impl FnMut(&T) -> bool + 'a,
16981698
left: &'a mut B,
16991699
right: &'a mut B,
1700-
) -> impl FnMut(T) + 'a {
1701-
move |x| {
1700+
) -> impl FnMut((), T) + 'a {
1701+
move |(), x| {
17021702
if f(&x) {
17031703
left.extend(Some(x));
17041704
} else {
@@ -1710,7 +1710,7 @@ pub trait Iterator {
17101710
let mut left: B = Default::default();
17111711
let mut right: B = Default::default();
17121712

1713-
self.for_each(extend(f, &mut left, &mut right));
1713+
self.fold((), extend(f, &mut left, &mut right));
17141714

17151715
(left, right)
17161716
}
@@ -1826,7 +1826,7 @@ pub trait Iterator {
18261826
///
18271827
/// # Note to Implementors
18281828
///
1829-
/// Most of the other (forward) methods have default implementations in
1829+
/// Several of the other (forward) methods have default implementations in
18301830
/// terms of this one, so try to implement this explicitly if it can
18311831
/// do something better than the default `for` loop implementation.
18321832
///
@@ -1944,6 +1944,15 @@ pub trait Iterator {
19441944
/// may not terminate for infinite iterators, even on traits for which a
19451945
/// result is determinable in finite time.
19461946
///
1947+
/// # Note to Implementors
1948+
///
1949+
/// Several of the other (forward) methods have default implementations in
1950+
/// terms of this one, so try to implement this explicitly if it can
1951+
/// do something better than the default `for` loop implementation.
1952+
///
1953+
/// In particular, try to have this call `fold()` on the internal parts
1954+
/// from which this iterator is composed.
1955+
///
19471956
/// # Examples
19481957
///
19491958
/// Basic usage:
@@ -1992,17 +2001,16 @@ pub trait Iterator {
19922001
/// ```
19932002
#[inline]
19942003
#[stable(feature = "rust1", since = "1.0.0")]
1995-
fn fold<B, F>(mut self, init: B, f: F) -> B
2004+
fn fold<B, F>(mut self, init: B, mut f: F) -> B
19962005
where
19972006
Self: Sized,
19982007
F: FnMut(B, Self::Item) -> B,
19992008
{
2000-
#[inline]
2001-
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
2002-
move |acc, x| Ok(f(acc, x))
2009+
let mut accum = init;
2010+
while let Some(x) = self.next() {
2011+
accum = f(accum, x);
20032012
}
2004-
2005-
self.try_fold(init, ok(f)).unwrap()
2013+
accum
20062014
}
20072015

20082016
/// The same as [`fold()`](#method.fold), but uses the first element in the
@@ -2273,7 +2281,7 @@ pub trait Iterator {
22732281
F: FnMut(&Self::Item) -> R,
22742282
R: Try<Ok = bool, Error = E>,
22752283
{
2276-
self.try_for_each(move |x| match f(&x).into_result() {
2284+
self.try_fold((), move |(), x| match f(&x).into_result() {
22772285
Ok(false) => LoopState::Continue(()),
22782286
Ok(true) => LoopState::Break(Ok(x)),
22792287
Err(x) => LoopState::Break(Err(x)),
@@ -2665,8 +2673,8 @@ pub trait Iterator {
26652673
fn extend<'a, A, B>(
26662674
ts: &'a mut impl Extend<A>,
26672675
us: &'a mut impl Extend<B>,
2668-
) -> impl FnMut((A, B)) + 'a {
2669-
move |(t, u)| {
2676+
) -> impl FnMut((), (A, B)) + 'a {
2677+
move |(), (t, u)| {
26702678
ts.extend(Some(t));
26712679
us.extend(Some(u));
26722680
}
@@ -2675,7 +2683,7 @@ pub trait Iterator {
26752683
let mut ts: FromA = Default::default();
26762684
let mut us: FromB = Default::default();
26772685

2678-
self.for_each(extend(&mut ts, &mut us));
2686+
self.fold((), extend(&mut ts, &mut us));
26792687

26802688
(ts, us)
26812689
}

src/test/codegen/iter-fold-closure-no-dupes.rs

-14
This file was deleted.

src/test/codegen/iter-fold-closure-no-iterator.rs

-10
This file was deleted.

0 commit comments

Comments
 (0)