Skip to content

Commit bdef2ad

Browse files
committed
[Perf Experiment] Introduce NeverShortCircuit to see if it helps fold-via-try_fold
1 parent 14a2fd6 commit bdef2ad

File tree

4 files changed

+50
-12
lines changed

4 files changed

+50
-12
lines changed

library/core/src/iter/traits/double_ended.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::ops::{ControlFlow, Try};
1+
use crate::ops::{ControlFlow, NeverShortCircuit, Try};
22

33
/// An iterator able to yield elements from both ends.
44
///
@@ -292,16 +292,17 @@ pub trait DoubleEndedIterator: Iterator {
292292
#[doc(alias = "foldr")]
293293
#[inline]
294294
#[stable(feature = "iter_rfold", since = "1.27.0")]
295-
fn rfold<B, F>(mut self, init: B, mut f: F) -> B
295+
fn rfold<B, F>(mut self, init: B, f: F) -> B
296296
where
297297
Self: Sized,
298298
F: FnMut(B, Self::Item) -> B,
299299
{
300-
let mut accum = init;
301-
while let Some(x) = self.next_back() {
302-
accum = f(accum, x);
300+
#[inline]
301+
fn call<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> NeverShortCircuit<B> {
302+
move |accum, item| NeverShortCircuit(f(accum, item))
303303
}
304-
accum
304+
305+
self.try_rfold(init, call(f)).0
305306
}
306307

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

library/core/src/iter/traits/iterator.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::cmp::{self, Ordering};
2-
use crate::ops::{ControlFlow, Try};
2+
use crate::ops::{ControlFlow, NeverShortCircuit, Try};
33

44
use super::super::TrustedRandomAccessNoCoerce;
55
use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
@@ -2161,16 +2161,17 @@ pub trait Iterator {
21612161
#[doc(alias = "inject", alias = "foldl")]
21622162
#[inline]
21632163
#[stable(feature = "rust1", since = "1.0.0")]
2164-
fn fold<B, F>(mut self, init: B, mut f: F) -> B
2164+
fn fold<B, F>(mut self, init: B, f: F) -> B
21652165
where
21662166
Self: Sized,
21672167
F: FnMut(B, Self::Item) -> B,
21682168
{
2169-
let mut accum = init;
2170-
while let Some(x) = self.next() {
2171-
accum = f(accum, x);
2169+
#[inline]
2170+
fn call<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> NeverShortCircuit<B> {
2171+
move |accum, item| NeverShortCircuit(f(accum, item))
21722172
}
2173-
accum
2173+
2174+
self.try_fold(init, call(f)).0
21742175
}
21752176

21762177
/// Reduces the elements to a single one, by repeatedly applying a reducing

library/core/src/ops/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive};
184184
#[unstable(feature = "try_trait_v2", issue = "84277")]
185185
pub use self::try_trait::{FromResidual, Try};
186186

187+
pub(crate) use self::try_trait::NeverShortCircuit;
188+
187189
#[unstable(feature = "generator_trait", issue = "43122")]
188190
pub use self::generator::{Generator, GeneratorState};
189191

library/core/src/ops/try_trait.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,3 +338,37 @@ pub trait FromResidual<R = <Self as Try>::Residual> {
338338
#[unstable(feature = "try_trait_v2", issue = "84277")]
339339
fn from_residual(residual: R) -> Self;
340340
}
341+
342+
/// An adapter for implementing non-try methods via the `Try` implementation.
343+
///
344+
/// Conceptually the same as `Result<T, !>`, but requiring less work in trait
345+
/// solving and inhabited-ness checking and such, by being an obvious newtype
346+
/// and not having `From` bounds lying around.
347+
///
348+
/// Not currently planned to be exposed publicly, so just `pub(crate)`.
349+
#[repr(transparent)]
350+
pub(crate) struct NeverShortCircuit<T>(pub T);
351+
352+
pub(crate) enum NeverShortCircuitResidual {}
353+
354+
impl<T> Try for NeverShortCircuit<T> {
355+
type Output = T;
356+
type Residual = NeverShortCircuitResidual;
357+
358+
#[inline]
359+
fn branch(self) -> ControlFlow<NeverShortCircuitResidual, T> {
360+
ControlFlow::Continue(self.0)
361+
}
362+
363+
#[inline]
364+
fn from_output(x: T) -> Self {
365+
NeverShortCircuit(x)
366+
}
367+
}
368+
369+
impl<T> FromResidual for NeverShortCircuit<T> {
370+
#[inline]
371+
fn from_residual(never: NeverShortCircuitResidual) -> Self {
372+
match never {}
373+
}
374+
}

0 commit comments

Comments
 (0)