Skip to content

Commit 1cdcea9

Browse files
committed
Auto merge of #62429 - cuviper:iter-closures, r=cramertj
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.
2 parents 9e9a136 + bca6f28 commit 1cdcea9

14 files changed

+714
-324
lines changed

src/libcore/iter/adapters/flatten.rs

+52-26
Original file line numberDiff line numberDiff line change
@@ -229,16 +229,16 @@ where
229229
if let elt@Some(_) = inner.next() { return elt }
230230
}
231231
match self.iter.next() {
232-
None => return self.backiter.as_mut().and_then(|it| it.next()),
232+
None => return self.backiter.as_mut()?.next(),
233233
Some(inner) => self.frontiter = Some(inner.into_iter()),
234234
}
235235
}
236236
}
237237

238238
#[inline]
239239
fn size_hint(&self) -> (usize, Option<usize>) {
240-
let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), |it| it.size_hint());
241-
let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), |it| it.size_hint());
240+
let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), U::size_hint);
241+
let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), U::size_hint);
242242
let lo = flo.saturating_add(blo);
243243
match (self.iter.size_hint(), fhi, bhi) {
244244
((0, Some(0)), Some(a), Some(b)) => (lo, a.checked_add(b)),
@@ -250,20 +250,25 @@ where
250250
fn try_fold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R where
251251
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
252252
{
253+
#[inline]
254+
fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>(
255+
frontiter: &'a mut Option<T::IntoIter>,
256+
fold: &'a mut impl FnMut(Acc, T::Item) -> R,
257+
) -> impl FnMut(Acc, T) -> R + 'a {
258+
move |acc, x| {
259+
let mut mid = x.into_iter();
260+
let r = mid.try_fold(acc, &mut *fold);
261+
*frontiter = Some(mid);
262+
r
263+
}
264+
}
265+
253266
if let Some(ref mut front) = self.frontiter {
254267
init = front.try_fold(init, &mut fold)?;
255268
}
256269
self.frontiter = None;
257270

258-
{
259-
let frontiter = &mut self.frontiter;
260-
init = self.iter.try_fold(init, |acc, x| {
261-
let mut mid = x.into_iter();
262-
let r = mid.try_fold(acc, &mut fold);
263-
*frontiter = Some(mid);
264-
r
265-
})?;
266-
}
271+
init = self.iter.try_fold(init, flatten(&mut self.frontiter, &mut fold))?;
267272
self.frontiter = None;
268273

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

277282
#[inline]
278-
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
283+
fn fold<Acc, Fold>(self, init: Acc, ref mut fold: Fold) -> Acc
279284
where Fold: FnMut(Acc, Self::Item) -> Acc,
280285
{
286+
#[inline]
287+
fn flatten<U: Iterator, Acc>(
288+
fold: &mut impl FnMut(Acc, U::Item) -> Acc,
289+
) -> impl FnMut(Acc, U) -> Acc + '_ {
290+
move |acc, iter| iter.fold(acc, &mut *fold)
291+
}
292+
281293
self.frontiter.into_iter()
282294
.chain(self.iter.map(IntoIterator::into_iter))
283295
.chain(self.backiter)
284-
.fold(init, |acc, iter| iter.fold(acc, &mut fold))
296+
.fold(init, flatten(fold))
285297
}
286298
}
287299

@@ -297,7 +309,7 @@ where
297309
if let elt@Some(_) = inner.next_back() { return elt }
298310
}
299311
match self.iter.next_back() {
300-
None => return self.frontiter.as_mut().and_then(|it| it.next_back()),
312+
None => return self.frontiter.as_mut()?.next_back(),
301313
next => self.backiter = next.map(IntoIterator::into_iter),
302314
}
303315
}
@@ -307,20 +319,27 @@ where
307319
fn try_rfold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R where
308320
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
309321
{
310-
if let Some(ref mut back) = self.backiter {
311-
init = back.try_rfold(init, &mut fold)?;
312-
}
313-
self.backiter = None;
314-
322+
#[inline]
323+
fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>(
324+
backiter: &'a mut Option<T::IntoIter>,
325+
fold: &'a mut impl FnMut(Acc, T::Item) -> R,
326+
) -> impl FnMut(Acc, T) -> R + 'a where
327+
T::IntoIter: DoubleEndedIterator,
315328
{
316-
let backiter = &mut self.backiter;
317-
init = self.iter.try_rfold(init, |acc, x| {
329+
move |acc, x| {
318330
let mut mid = x.into_iter();
319-
let r = mid.try_rfold(acc, &mut fold);
331+
let r = mid.try_rfold(acc, &mut *fold);
320332
*backiter = Some(mid);
321333
r
322-
})?;
334+
}
323335
}
336+
337+
if let Some(ref mut back) = self.backiter {
338+
init = back.try_rfold(init, &mut fold)?;
339+
}
340+
self.backiter = None;
341+
342+
init = self.iter.try_rfold(init, flatten(&mut self.backiter, &mut fold))?;
324343
self.backiter = None;
325344

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

334353
#[inline]
335-
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
354+
fn rfold<Acc, Fold>(self, init: Acc, ref mut fold: Fold) -> Acc
336355
where Fold: FnMut(Acc, Self::Item) -> Acc,
337356
{
357+
#[inline]
358+
fn flatten<U: DoubleEndedIterator, Acc>(
359+
fold: &mut impl FnMut(Acc, U::Item) -> Acc,
360+
) -> impl FnMut(Acc, U) -> Acc + '_ {
361+
move |acc, iter| iter.rfold(acc, &mut *fold)
362+
}
363+
338364
self.frontiter.into_iter()
339365
.chain(self.iter.map(IntoIterator::into_iter))
340366
.chain(self.backiter)
341-
.rfold(init, |acc, iter| iter.rfold(acc, &mut fold))
367+
.rfold(init, flatten(fold))
342368
}
343369
}

0 commit comments

Comments
 (0)