Override try_[r]fold for RangeInclusive
Because the last item needs special handling, it seems that LLVM has trouble canonicalizing the loops in external iteration. With the override, it becomes obvious that the start==end case exits the loop (as opposed to the one *after* that exiting the loop in external iteration).
This commit is contained in:
parent
b8f2674ea4
commit
1b1e887f4d
2 changed files with 65 additions and 1 deletions
|
@ -10,7 +10,7 @@
|
|||
|
||||
use convert::TryFrom;
|
||||
use mem;
|
||||
use ops::{self, Add, Sub};
|
||||
use ops::{self, Add, Sub, Try};
|
||||
use usize;
|
||||
|
||||
use super::{FusedIterator, TrustedLen};
|
||||
|
@ -397,6 +397,28 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
|
|||
fn max(mut self) -> Option<A> {
|
||||
self.next_back()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R where
|
||||
Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
|
||||
{
|
||||
let mut accum = init;
|
||||
if self.start <= self.end {
|
||||
loop {
|
||||
let (x, done) =
|
||||
if self.start < self.end {
|
||||
let n = self.start.add_one();
|
||||
(mem::replace(&mut self.start, n), false)
|
||||
} else {
|
||||
self.end.replace_zero();
|
||||
(self.start.replace_one(), true)
|
||||
};
|
||||
accum = f(accum, x)?;
|
||||
if done { break }
|
||||
}
|
||||
}
|
||||
Try::from_ok(accum)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
|
||||
|
@ -418,6 +440,28 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where
|
||||
Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
|
||||
{
|
||||
let mut accum = init;
|
||||
if self.start <= self.end {
|
||||
loop {
|
||||
let (x, done) =
|
||||
if self.start < self.end {
|
||||
let n = self.end.sub_one();
|
||||
(mem::replace(&mut self.end, n), false)
|
||||
} else {
|
||||
self.start.replace_one();
|
||||
(self.end.replace_zero(), true)
|
||||
};
|
||||
accum = f(accum, x)?;
|
||||
if done { break }
|
||||
}
|
||||
}
|
||||
Try::from_ok(accum)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
|
|
|
@ -1397,6 +1397,26 @@ fn test_range_inclusive_min() {
|
|||
assert_eq!(r.min(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_inclusive_folds() {
|
||||
assert_eq!((1..=10).sum::<i32>(), 55);
|
||||
assert_eq!((1..=10).rev().sum::<i32>(), 55);
|
||||
|
||||
let mut it = 40..=50;
|
||||
assert_eq!(it.try_fold(0, i8::checked_add), None);
|
||||
assert_eq!(it, 44..=50);
|
||||
assert_eq!(it.try_rfold(0, i8::checked_add), None);
|
||||
assert_eq!(it, 44..=47);
|
||||
|
||||
let mut it = 10..=20;
|
||||
assert_eq!(it.try_fold(0, |a,b| Some(a+b)), Some(165));
|
||||
assert_eq!(it, 1..=0);
|
||||
|
||||
let mut it = 10..=20;
|
||||
assert_eq!(it.try_rfold(0, |a,b| Some(a+b)), Some(165));
|
||||
assert_eq!(it, 1..=0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_repeat() {
|
||||
let mut it = repeat(42);
|
||||
|
|
Loading…
Add table
Reference in a new issue