Make the specialized Fuse still deal with None

This commit is contained in:
Josh Stone 2021-06-30 16:10:33 -07:00
parent 868c702d0c
commit 6f5e933adb

View File

@ -1,5 +1,5 @@
use crate::intrinsics; use crate::intrinsics;
use crate::iter::adapters::{zip::try_get_unchecked, InPlaceIterable, SourceIter}; use crate::iter::adapters::zip::try_get_unchecked;
use crate::iter::{ use crate::iter::{
DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccess, DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccess,
}; };
@ -14,7 +14,9 @@
#[must_use = "iterators are lazy and do nothing unless consumed"] #[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub struct Fuse<I> { pub struct Fuse<I> {
// 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<I>, iter: Option<I>,
} }
impl<I> Fuse<I> { impl<I> Fuse<I> {
@ -42,19 +44,19 @@ macro_rules! fuse {
}; };
} }
// NOTE: for `I: FusedIterator`, we assume that the iterator is always `Some`. /// Specialized macro that doesn't check if the expression is `None`.
// Implementing this as a directly-expanded macro helps codegen performance. /// (We trust that a `FusedIterator` will fuse itself.)
macro_rules! unchecked { macro_rules! spec {
($self:ident) => { ($self:ident . iter . $($call:tt)+) => {
match $self { match $self.iter {
Fuse { iter: Some(iter) } => iter, Some(ref mut iter) => iter.$($call)+,
// SAFETY: the specialized iterator never sets `None` None => None,
Fuse { iter: None } => unsafe { intrinsics::unreachable() },
} }
}; };
} }
// 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")] #[stable(feature = "rust1", since = "1.0.0")]
impl<I> Iterator for Fuse<I> impl<I> Iterator for Fuse<I>
where where
@ -74,17 +76,26 @@ fn nth(&mut self, n: usize) -> Option<I::Item> {
#[inline] #[inline]
fn last(self) -> Option<Self::Item> { fn last(self) -> Option<Self::Item> {
FuseImpl::last(self) match self.iter {
Some(iter) => iter.last(),
None => None,
}
} }
#[inline] #[inline]
fn count(self) -> usize { fn count(self) -> usize {
FuseImpl::count(self) match self.iter {
Some(iter) => iter.count(),
None => 0,
}
} }
#[inline] #[inline]
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) {
FuseImpl::size_hint(self) match self.iter {
Some(ref iter) => iter.size_hint(),
None => (0, Some(0)),
}
} }
#[inline] #[inline]
@ -98,11 +109,14 @@ fn try_fold<Acc, Fold, R>(&mut self, acc: Acc, fold: Fold) -> R
} }
#[inline] #[inline]
fn fold<Acc, Fold>(self, acc: Acc, fold: Fold) -> Acc fn fold<Acc, Fold>(self, mut acc: Acc, fold: Fold) -> Acc
where where
Fold: FnMut(Acc, Self::Item) -> Acc, Fold: FnMut(Acc, Self::Item) -> Acc,
{ {
FuseImpl::fold(self, acc, fold) if let Some(iter) = self.iter {
acc = iter.fold(acc, fold);
}
acc
} }
#[inline] #[inline]
@ -155,11 +169,14 @@ fn try_rfold<Acc, Fold, R>(&mut self, acc: Acc, fold: Fold) -> R
} }
#[inline] #[inline]
fn rfold<Acc, Fold>(self, acc: Acc, fold: Fold) -> Acc fn rfold<Acc, Fold>(self, mut acc: Acc, fold: Fold) -> Acc
where where
Fold: FnMut(Acc, Self::Item) -> Acc, Fold: FnMut(Acc, Self::Item) -> Acc,
{ {
FuseImpl::rfold(self, acc, fold) if let Some(iter) = self.iter {
acc = iter.rfold(acc, fold);
}
acc
} }
#[inline] #[inline]
@ -177,11 +194,17 @@ impl<I> ExactSizeIterator for Fuse<I>
I: ExactSizeIterator, I: ExactSizeIterator,
{ {
fn len(&self) -> usize { fn len(&self) -> usize {
FuseImpl::len(self) match self.iter {
Some(ref iter) => iter.len(),
None => 0,
}
} }
fn is_empty(&self) -> bool { fn is_empty(&self) -> bool {
FuseImpl::is_empty(self) match self.iter {
Some(ref iter) => iter.is_empty(),
None => true,
}
} }
} }
@ -205,7 +228,10 @@ unsafe impl<I> TrustedRandomAccess for Fuse<I>
const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT; 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)] #[doc(hidden)]
trait FuseImpl<I> { trait FuseImpl<I> {
type Item; type Item;
@ -213,17 +239,11 @@ trait FuseImpl<I> {
// Functions specific to any normal Iterators // Functions specific to any normal Iterators
fn next(&mut self) -> Option<Self::Item>; fn next(&mut self) -> Option<Self::Item>;
fn nth(&mut self, n: usize) -> Option<Self::Item>; fn nth(&mut self, n: usize) -> Option<Self::Item>;
fn last(self) -> Option<Self::Item>;
fn count(self) -> usize;
fn size_hint(&self) -> (usize, Option<usize>);
fn try_fold<Acc, Fold, R>(&mut self, acc: Acc, fold: Fold) -> R fn try_fold<Acc, Fold, R>(&mut self, acc: Acc, fold: Fold) -> R
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Output = Acc>; R: Try<Output = Acc>;
fn fold<Acc, Fold>(self, acc: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc;
fn find<P>(&mut self, predicate: P) -> Option<Self::Item> fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
where where
P: FnMut(&Self::Item) -> bool; P: FnMut(&Self::Item) -> bool;
@ -241,25 +261,13 @@ fn try_rfold<Acc, Fold, R>(&mut self, acc: Acc, fold: Fold) -> R
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Output = Acc>, R: Try<Output = Acc>,
I: DoubleEndedIterator; I: DoubleEndedIterator;
fn rfold<Acc, Fold>(self, acc: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
I: DoubleEndedIterator;
fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item> fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
where where
P: FnMut(&Self::Item) -> bool, P: FnMut(&Self::Item) -> bool,
I: DoubleEndedIterator; 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)] #[doc(hidden)]
impl<I> FuseImpl<I> for Fuse<I> impl<I> FuseImpl<I> for Fuse<I>
where where
@ -277,30 +285,6 @@ impl<I> FuseImpl<I> for Fuse<I>
fuse!(self.iter.nth(n)) fuse!(self.iter.nth(n))
} }
#[inline]
default fn last(self) -> Option<I::Item> {
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<usize>) {
match self.iter {
Some(ref iter) => iter.size_hint(),
None => (0, Some(0)),
}
}
#[inline] #[inline]
default fn try_fold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R default fn try_fold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R
where where
@ -315,17 +299,6 @@ impl<I> FuseImpl<I> for Fuse<I>
try { acc } try { acc }
} }
#[inline]
default fn fold<Acc, 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] #[inline]
default fn find<P>(&mut self, predicate: P) -> Option<Self::Item> default fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
where where
@ -365,18 +338,6 @@ impl<I> FuseImpl<I> for Fuse<I>
try { acc } try { acc }
} }
#[inline]
default fn rfold<Acc, Fold>(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] #[inline]
default fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item> default fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
where where
@ -385,30 +346,10 @@ impl<I> FuseImpl<I> for Fuse<I>
{ {
fuse!(self.iter.rfind(predicate)) 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)] #[doc(hidden)]
impl<I> FuseImpl<I> for Fuse<I> impl<I> FuseImpl<I> for Fuse<I>
where where
@ -416,45 +357,25 @@ impl<I> FuseImpl<I> for Fuse<I>
{ {
#[inline] #[inline]
fn next(&mut self) -> Option<<I as Iterator>::Item> { fn next(&mut self) -> Option<<I as Iterator>::Item> {
unchecked!(self).next() spec!(self.iter.next())
} }
#[inline] #[inline]
fn nth(&mut self, n: usize) -> Option<I::Item> { fn nth(&mut self, n: usize) -> Option<I::Item> {
unchecked!(self).nth(n) spec!(self.iter.nth(n))
} }
#[inline] #[inline]
fn last(self) -> Option<I::Item> { fn try_fold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R
unchecked!(self).last()
}
#[inline]
fn count(self) -> usize {
unchecked!(self).count()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
unchecked!(self).size_hint()
}
#[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Output = Acc>, R: Try<Output = Acc>,
{ {
unchecked!(self).try_fold(init, fold) if let Some(ref mut iter) = self.iter {
} acc = iter.try_fold(acc, fold)?;
}
#[inline] try { acc }
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
unchecked!(self).fold(init, fold)
} }
#[inline] #[inline]
@ -462,7 +383,7 @@ fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
where where
P: FnMut(&Self::Item) -> bool, P: FnMut(&Self::Item) -> bool,
{ {
unchecked!(self).find(predicate) spec!(self.iter.find(predicate))
} }
#[inline] #[inline]
@ -470,7 +391,7 @@ fn next_back(&mut self) -> Option<<I as Iterator>::Item>
where where
I: DoubleEndedIterator, I: DoubleEndedIterator,
{ {
unchecked!(self).next_back() spec!(self.iter.next_back())
} }
#[inline] #[inline]
@ -478,27 +399,21 @@ fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item>
where where
I: DoubleEndedIterator, I: DoubleEndedIterator,
{ {
unchecked!(self).nth_back(n) spec!(self.iter.nth_back(n))
} }
#[inline] #[inline]
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R fn try_rfold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Output = Acc>, R: Try<Output = Acc>,
I: DoubleEndedIterator, I: DoubleEndedIterator,
{ {
unchecked!(self).try_rfold(init, fold) if let Some(ref mut iter) = self.iter {
} acc = iter.try_rfold(acc, fold)?;
}
#[inline] try { acc }
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
I: DoubleEndedIterator,
{
unchecked!(self).rfold(init, fold)
} }
#[inline] #[inline]
@ -507,43 +422,6 @@ fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
P: FnMut(&Self::Item) -> bool, P: FnMut(&Self::Item) -> bool,
I: DoubleEndedIterator, I: DoubleEndedIterator,
{ {
unchecked!(self).rfind(predicate) spec!(self.iter.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()
} }
} }
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<S: Iterator, I: FusedIterator> SourceIter for Fuse<I>
where
I: SourceIter<Source = S>,
{
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<I: InPlaceIterable> InPlaceIterable for Fuse<I> {}