Make the specialized Fuse still deal with None
This commit is contained in:
parent
868c702d0c
commit
6f5e933adb
@ -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> {}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user