From 6f5e933adb5705e15380b17ee9a2d7afb19748f2 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 30 Jun 2021 16:10:33 -0700 Subject: [PATCH] Make the specialized Fuse still deal with None --- library/core/src/iter/adapters/fuse.rs | 254 +++++++------------------ 1 file changed, 66 insertions(+), 188 deletions(-) diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index 0c21df4f12c60..408328adeecf4 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -1,5 +1,5 @@ use crate::intrinsics; -use crate::iter::adapters::{zip::try_get_unchecked, InPlaceIterable, SourceIter}; +use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::{ DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccess, }; @@ -14,7 +14,9 @@ use crate::ops::Try; #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] pub struct Fuse { - // NOTE: for `I: FusedIterator`, this is always assumed `Some`! + // NOTE: for `I: FusedIterator`, we never bother setting `None`, but + // we still have to be prepared for that state due to variance. + // See rust-lang/rust#85863 iter: Option, } impl Fuse { @@ -42,19 +44,19 @@ macro_rules! fuse { }; } -// NOTE: for `I: FusedIterator`, we assume that the iterator is always `Some`. -// Implementing this as a directly-expanded macro helps codegen performance. -macro_rules! unchecked { - ($self:ident) => { - match $self { - Fuse { iter: Some(iter) } => iter, - // SAFETY: the specialized iterator never sets `None` - Fuse { iter: None } => unsafe { intrinsics::unreachable() }, +/// Specialized macro that doesn't check if the expression is `None`. +/// (We trust that a `FusedIterator` will fuse itself.) +macro_rules! spec { + ($self:ident . iter . $($call:tt)+) => { + match $self.iter { + Some(ref mut iter) => iter.$($call)+, + None => None, } }; } -// Any implementation here is made internal to avoid exposing default fns outside this trait +// Any specialized implementation here is made internal +// to avoid exposing default fns outside this trait. #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for Fuse where @@ -74,17 +76,26 @@ where #[inline] fn last(self) -> Option { - FuseImpl::last(self) + match self.iter { + Some(iter) => iter.last(), + None => None, + } } #[inline] fn count(self) -> usize { - FuseImpl::count(self) + match self.iter { + Some(iter) => iter.count(), + None => 0, + } } #[inline] fn size_hint(&self) -> (usize, Option) { - FuseImpl::size_hint(self) + match self.iter { + Some(ref iter) => iter.size_hint(), + None => (0, Some(0)), + } } #[inline] @@ -98,11 +109,14 @@ where } #[inline] - fn fold(self, acc: Acc, fold: Fold) -> Acc + fn fold(self, mut acc: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { - FuseImpl::fold(self, acc, fold) + if let Some(iter) = self.iter { + acc = iter.fold(acc, fold); + } + acc } #[inline] @@ -155,11 +169,14 @@ where } #[inline] - fn rfold(self, acc: Acc, fold: Fold) -> Acc + fn rfold(self, mut acc: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { - FuseImpl::rfold(self, acc, fold) + if let Some(iter) = self.iter { + acc = iter.rfold(acc, fold); + } + acc } #[inline] @@ -177,11 +194,17 @@ where I: ExactSizeIterator, { fn len(&self) -> usize { - FuseImpl::len(self) + match self.iter { + Some(ref iter) => iter.len(), + None => 0, + } } fn is_empty(&self) -> bool { - FuseImpl::is_empty(self) + match self.iter { + Some(ref iter) => iter.is_empty(), + None => true, + } } } @@ -205,7 +228,10 @@ where const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT; } -// Fuse specialization trait +/// Fuse specialization trait +/// +/// We only need to worry about `&mut self` methods, which +/// may exhaust the iterator without consuming it. #[doc(hidden)] trait FuseImpl { type Item; @@ -213,17 +239,11 @@ trait FuseImpl { // Functions specific to any normal Iterators fn next(&mut self) -> Option; fn nth(&mut self, n: usize) -> Option; - fn last(self) -> Option; - fn count(self) -> usize; - fn size_hint(&self) -> (usize, Option); fn try_fold(&mut self, acc: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try; - fn fold(self, acc: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc; fn find

(&mut self, predicate: P) -> Option where P: FnMut(&Self::Item) -> bool; @@ -241,25 +261,13 @@ trait FuseImpl { Fold: FnMut(Acc, Self::Item) -> R, R: Try, I: DoubleEndedIterator; - fn rfold(self, acc: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - I: DoubleEndedIterator; fn rfind

(&mut self, predicate: P) -> Option where P: FnMut(&Self::Item) -> bool, I: DoubleEndedIterator; - - // Functions specific to ExactSizeIterator - fn len(&self) -> usize - where - I: ExactSizeIterator; - fn is_empty(&self) -> bool - where - I: ExactSizeIterator; } -// General Fuse impl +/// General `Fuse` impl which sets `iter = None` when exhausted. #[doc(hidden)] impl FuseImpl for Fuse where @@ -277,30 +285,6 @@ where fuse!(self.iter.nth(n)) } - #[inline] - default fn last(self) -> Option { - match self.iter { - Some(iter) => iter.last(), - None => None, - } - } - - #[inline] - default fn count(self) -> usize { - match self.iter { - Some(iter) => iter.count(), - None => 0, - } - } - - #[inline] - default fn size_hint(&self) -> (usize, Option) { - match self.iter { - Some(ref iter) => iter.size_hint(), - None => (0, Some(0)), - } - } - #[inline] default fn try_fold(&mut self, mut acc: Acc, fold: Fold) -> R where @@ -315,17 +299,6 @@ where try { acc } } - #[inline] - default fn fold(self, mut acc: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - if let Some(iter) = self.iter { - acc = iter.fold(acc, fold); - } - acc - } - #[inline] default fn find

(&mut self, predicate: P) -> Option where @@ -365,18 +338,6 @@ where try { acc } } - #[inline] - default fn rfold(self, mut acc: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - I: DoubleEndedIterator, - { - if let Some(iter) = self.iter { - acc = iter.rfold(acc, fold); - } - acc - } - #[inline] default fn rfind

(&mut self, predicate: P) -> Option where @@ -385,30 +346,10 @@ where { fuse!(self.iter.rfind(predicate)) } - - #[inline] - default fn len(&self) -> usize - where - I: ExactSizeIterator, - { - match self.iter { - Some(ref iter) => iter.len(), - None => 0, - } - } - - #[inline] - default fn is_empty(&self) -> bool - where - I: ExactSizeIterator, - { - match self.iter { - Some(ref iter) => iter.is_empty(), - None => true, - } - } } +/// Specialized `Fuse` impl which doesn't bother clearing `iter` when exhausted. +/// However, we must still be prepared for the possibility that it was already cleared! #[doc(hidden)] impl FuseImpl for Fuse where @@ -416,45 +357,25 @@ where { #[inline] fn next(&mut self) -> Option<::Item> { - unchecked!(self).next() + spec!(self.iter.next()) } #[inline] fn nth(&mut self, n: usize) -> Option { - unchecked!(self).nth(n) - } - - #[inline] - fn last(self) -> Option { - unchecked!(self).last() + spec!(self.iter.nth(n)) } #[inline] - fn count(self) -> usize { - unchecked!(self).count() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - unchecked!(self).size_hint() - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R + fn try_fold(&mut self, mut acc: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try, { - unchecked!(self).try_fold(init, fold) - } - - #[inline] - fn fold(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - unchecked!(self).fold(init, fold) + if let Some(ref mut iter) = self.iter { + acc = iter.try_fold(acc, fold)?; + } + try { acc } } #[inline] @@ -462,7 +383,7 @@ where where P: FnMut(&Self::Item) -> bool, { - unchecked!(self).find(predicate) + spec!(self.iter.find(predicate)) } #[inline] @@ -470,7 +391,7 @@ where where I: DoubleEndedIterator, { - unchecked!(self).next_back() + spec!(self.iter.next_back()) } #[inline] @@ -478,27 +399,21 @@ where where I: DoubleEndedIterator, { - unchecked!(self).nth_back(n) + spec!(self.iter.nth_back(n)) } #[inline] - fn try_rfold(&mut self, init: Acc, fold: Fold) -> R + fn try_rfold(&mut self, mut acc: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try, I: DoubleEndedIterator, { - unchecked!(self).try_rfold(init, fold) - } - - #[inline] - fn rfold(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - I: DoubleEndedIterator, - { - unchecked!(self).rfold(init, fold) + if let Some(ref mut iter) = self.iter { + acc = iter.try_rfold(acc, fold)?; + } + try { acc } } #[inline] @@ -507,43 +422,6 @@ where P: FnMut(&Self::Item) -> bool, I: DoubleEndedIterator, { - unchecked!(self).rfind(predicate) - } - - #[inline] - fn len(&self) -> usize - where - I: ExactSizeIterator, - { - unchecked!(self).len() - } - - #[inline] - fn is_empty(&self) -> bool - where - I: ExactSizeIterator, - { - unchecked!(self).is_empty() + spec!(self.iter.rfind(predicate)) } } - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Fuse -where - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - match self.iter { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - Some(ref mut iter) => unsafe { SourceIter::as_inner(iter) }, - // SAFETY: the specialized iterator never sets `None` - None => unsafe { intrinsics::unreachable() }, - } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Fuse {}