Auto merge of #111200 - a1phyr:spec_sized_iterators, r=the8472

Optimize `Iterator` implementation for `&mut impl Iterator + Sized`

This adds a specialization trait to forward `fold`, `try_fold`,... to the inner iterator where possible
This commit is contained in:
bors 2023-08-05 17:38:26 +00:00
commit eb088b8b9d
3 changed files with 130 additions and 0 deletions

View File

@ -361,6 +361,12 @@ macro_rules! impl_fold_via_try_fold {
(rfold -> try_rfold) => {
impl_fold_via_try_fold! { @internal rfold -> try_rfold }
};
(spec_fold -> spec_try_fold) => {
impl_fold_via_try_fold! { @internal spec_fold -> spec_try_fold }
};
(spec_rfold -> spec_try_rfold) => {
impl_fold_via_try_fold! { @internal spec_rfold -> spec_try_rfold }
};
(@internal $fold:ident -> $try_fold:ident) => {
#[inline]
fn $fold<AAA, FFF>(mut self, init: AAA, fold: FFF) -> AAA

View File

@ -379,4 +379,66 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
fn nth_back(&mut self, n: usize) -> Option<I::Item> {
(**self).nth_back(n)
}
fn rfold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
self.spec_rfold(init, f)
}
fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
where
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
self.spec_try_rfold(init, f)
}
}
/// Helper trait to specialize `rfold` and `rtry_fold` for `&mut I where I: Sized`
trait DoubleEndedIteratorRefSpec: DoubleEndedIterator {
fn spec_rfold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B;
fn spec_try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
where
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>;
}
impl<I: DoubleEndedIterator + ?Sized> DoubleEndedIteratorRefSpec for &mut I {
default fn spec_rfold<B, F>(self, init: B, mut f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
let mut accum = init;
while let Some(x) = self.next_back() {
accum = f(accum, x);
}
accum
}
default fn spec_try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
where
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
let mut accum = init;
while let Some(x) = self.next_back() {
accum = f(accum, x)?;
}
try { accum }
}
}
impl<I: DoubleEndedIterator> DoubleEndedIteratorRefSpec for &mut I {
impl_fold_via_try_fold! { spec_rfold -> spec_try_rfold }
fn spec_try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
where
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
(**self).try_rfold(init, f)
}
}

View File

@ -4018,4 +4018,66 @@ impl<I: Iterator + ?Sized> Iterator for &mut I {
fn nth(&mut self, n: usize) -> Option<Self::Item> {
(**self).nth(n)
}
fn fold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
self.spec_fold(init, f)
}
fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
where
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
self.spec_try_fold(init, f)
}
}
/// Helper trait to specialize `fold` and `try_fold` for `&mut I where I: Sized`
trait IteratorRefSpec: Iterator {
fn spec_fold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B;
fn spec_try_fold<B, F, R>(&mut self, init: B, f: F) -> R
where
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>;
}
impl<I: Iterator + ?Sized> IteratorRefSpec for &mut I {
default fn spec_fold<B, F>(self, init: B, mut f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
let mut accum = init;
while let Some(x) = self.next() {
accum = f(accum, x);
}
accum
}
default fn spec_try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
where
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
let mut accum = init;
while let Some(x) = self.next() {
accum = f(accum, x)?;
}
try { accum }
}
}
impl<I: Iterator> IteratorRefSpec for &mut I {
impl_fold_via_try_fold! { spec_fold -> spec_try_fold }
fn spec_try_fold<B, F, R>(&mut self, init: B, f: F) -> R
where
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
(**self).try_fold(init, f)
}
}