Skip to content

Commit

Permalink
Auto merge of #62429 - cuviper:iter-closures, r=cramertj
Browse files Browse the repository at this point in the history
Reduce the genericity of closures in the iterator traits

By default, closures inherit the generic parameters of their scope,
including `Self`. However, in most cases, the closures used to implement
iterators don't need to be generic on the iterator type, only its `Item`
type. We can reduce this genericity by redirecting such closures through
local functions.

This does make the closures more cumbersome to write, but it will
hopefully reduce duplication in their monomorphizations, as well as
their related type lengths.
  • Loading branch information
bors committed Aug 15, 2019
2 parents 9e9a136 + bca6f28 commit 1cdcea9
Show file tree
Hide file tree
Showing 14 changed files with 714 additions and 324 deletions.
78 changes: 52 additions & 26 deletions src/libcore/iter/adapters/flatten.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,16 +229,16 @@ where
if let elt@Some(_) = inner.next() { return elt }
}
match self.iter.next() {
None => return self.backiter.as_mut().and_then(|it| it.next()),
None => return self.backiter.as_mut()?.next(),
Some(inner) => self.frontiter = Some(inner.into_iter()),
}
}
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), |it| it.size_hint());
let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), |it| it.size_hint());
let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), U::size_hint);
let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), U::size_hint);
let lo = flo.saturating_add(blo);
match (self.iter.size_hint(), fhi, bhi) {
((0, Some(0)), Some(a), Some(b)) => (lo, a.checked_add(b)),
Expand All @@ -250,20 +250,25 @@ where
fn try_fold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R where
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
{
#[inline]
fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>(
frontiter: &'a mut Option<T::IntoIter>,
fold: &'a mut impl FnMut(Acc, T::Item) -> R,
) -> impl FnMut(Acc, T) -> R + 'a {
move |acc, x| {
let mut mid = x.into_iter();
let r = mid.try_fold(acc, &mut *fold);
*frontiter = Some(mid);
r
}
}

if let Some(ref mut front) = self.frontiter {
init = front.try_fold(init, &mut fold)?;
}
self.frontiter = None;

{
let frontiter = &mut self.frontiter;
init = self.iter.try_fold(init, |acc, x| {
let mut mid = x.into_iter();
let r = mid.try_fold(acc, &mut fold);
*frontiter = Some(mid);
r
})?;
}
init = self.iter.try_fold(init, flatten(&mut self.frontiter, &mut fold))?;
self.frontiter = None;

if let Some(ref mut back) = self.backiter {
Expand All @@ -275,13 +280,20 @@ where
}

#[inline]
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
fn fold<Acc, Fold>(self, init: Acc, ref mut fold: Fold) -> Acc
where Fold: FnMut(Acc, Self::Item) -> Acc,
{
#[inline]
fn flatten<U: Iterator, Acc>(
fold: &mut impl FnMut(Acc, U::Item) -> Acc,
) -> impl FnMut(Acc, U) -> Acc + '_ {
move |acc, iter| iter.fold(acc, &mut *fold)
}

self.frontiter.into_iter()
.chain(self.iter.map(IntoIterator::into_iter))
.chain(self.backiter)
.fold(init, |acc, iter| iter.fold(acc, &mut fold))
.fold(init, flatten(fold))
}
}

Expand All @@ -297,7 +309,7 @@ where
if let elt@Some(_) = inner.next_back() { return elt }
}
match self.iter.next_back() {
None => return self.frontiter.as_mut().and_then(|it| it.next_back()),
None => return self.frontiter.as_mut()?.next_back(),
next => self.backiter = next.map(IntoIterator::into_iter),
}
}
Expand All @@ -307,20 +319,27 @@ where
fn try_rfold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R where
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
{
if let Some(ref mut back) = self.backiter {
init = back.try_rfold(init, &mut fold)?;
}
self.backiter = None;

#[inline]
fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>(
backiter: &'a mut Option<T::IntoIter>,
fold: &'a mut impl FnMut(Acc, T::Item) -> R,
) -> impl FnMut(Acc, T) -> R + 'a where
T::IntoIter: DoubleEndedIterator,
{
let backiter = &mut self.backiter;
init = self.iter.try_rfold(init, |acc, x| {
move |acc, x| {
let mut mid = x.into_iter();
let r = mid.try_rfold(acc, &mut fold);
let r = mid.try_rfold(acc, &mut *fold);
*backiter = Some(mid);
r
})?;
}
}

if let Some(ref mut back) = self.backiter {
init = back.try_rfold(init, &mut fold)?;
}
self.backiter = None;

init = self.iter.try_rfold(init, flatten(&mut self.backiter, &mut fold))?;
self.backiter = None;

if let Some(ref mut front) = self.frontiter {
Expand All @@ -332,12 +351,19 @@ where
}

#[inline]
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
fn rfold<Acc, Fold>(self, init: Acc, ref mut fold: Fold) -> Acc
where Fold: FnMut(Acc, Self::Item) -> Acc,
{
#[inline]
fn flatten<U: DoubleEndedIterator, Acc>(
fold: &mut impl FnMut(Acc, U::Item) -> Acc,
) -> impl FnMut(Acc, U) -> Acc + '_ {
move |acc, iter| iter.rfold(acc, &mut *fold)
}

self.frontiter.into_iter()
.chain(self.iter.map(IntoIterator::into_iter))
.chain(self.backiter)
.rfold(init, |acc, iter| iter.rfold(acc, &mut fold))
.rfold(init, flatten(fold))
}
}
Loading

0 comments on commit 1cdcea9

Please sign in to comment.