Skip to content

Commit

Permalink
Auto merge of #68820 - WaffleLapkin:remove_finished_from_map_while, r…
Browse files Browse the repository at this point in the history
…=LukasKalbertodt

Remove `finished` flag from `MapWhile`

This PR removes  `finished` flag from `MapWhile` as been proposed in #66577 (comment).

This also resolves open questions of the tracking issue (#68537):
- `MapWhile` can't implement both
  + `DoubleEndedIterator` (discussed in #66577 (comment) and following comments)
  + `FusedIterator` (this pr removes `finished` flag, so `MapWhile` isn't fused anymore)
- Debug output (this pr removes `finished` flag, so there is no question in including it in debug output)

r? @Mark-Simulacrum
  • Loading branch information
bors committed Mar 22, 2020
2 parents 94d43d6 + e964d71 commit 5ae85f4
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 57 deletions.
68 changes: 21 additions & 47 deletions src/libcore/iter/adapters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1768,6 +1768,14 @@ where
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I, P> FusedIterator for TakeWhile<I, P>
where
I: FusedIterator,
P: FnMut(&I::Item) -> bool,
{
}

/// An iterator that only accepts elements while `predicate` returns `Some(_)`.
///
/// This `struct` is created by the [`map_while`] method on [`Iterator`]. See its
Expand All @@ -1780,20 +1788,19 @@ where
#[derive(Clone)]
pub struct MapWhile<I, P> {
iter: I,
finished: bool,
predicate: P,
}

impl<I, P> MapWhile<I, P> {
pub(super) fn new(iter: I, predicate: P) -> MapWhile<I, P> {
MapWhile { iter, finished: false, predicate }
MapWhile { iter, predicate }
}
}

#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
impl<I: fmt::Debug, P> fmt::Debug for MapWhile<I, P> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MapWhile").field("iter", &self.iter).field("flag", &self.finished).finish()
f.debug_struct("MapWhile").field("iter", &self.iter).finish()
}
}

Expand All @@ -1806,65 +1813,32 @@ where

#[inline]
fn next(&mut self) -> Option<B> {
if self.finished {
None
} else {
let x = self.iter.next()?;
let ret = (self.predicate)(x);
self.finished = ret.is_none();
ret
}
let x = self.iter.next()?;
(self.predicate)(x)
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
if self.finished {
(0, Some(0))
} else {
let (_, upper) = self.iter.size_hint();
(0, upper) // can't know a lower bound, due to the predicate
}
let (_, upper) = self.iter.size_hint();
(0, upper) // can't know a lower bound, due to the predicate
}

#[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
fn check<'a, B, T, Acc, R: Try<Ok = Acc>>(
flag: &'a mut bool,
p: &'a mut impl FnMut(T) -> Option<B>,
mut fold: impl FnMut(Acc, B) -> R + 'a,
) -> impl FnMut(Acc, T) -> LoopState<Acc, R> + 'a {
move |acc, x| match p(x) {
Some(item) => LoopState::from_try(fold(acc, item)),
None => {
*flag = true;
LoopState::Break(Try::from_ok(acc))
}
}
}

if self.finished {
Try::from_ok(init)
} else {
let flag = &mut self.finished;
let p = &mut self.predicate;
self.iter.try_fold(init, check(flag, p, fold)).into_try()
}
let Self { iter, predicate } = self;
iter.try_fold(init, |acc, x| match predicate(x) {
Some(item) => LoopState::from_try(fold(acc, item)),
None => LoopState::Break(Try::from_ok(acc)),
})
.into_try()
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I, P> FusedIterator for TakeWhile<I, P>
where
I: FusedIterator,
P: FnMut(&I::Item) -> bool,
{
}

/// An iterator that skips over `n` elements of `iter`.
///
/// This `struct` is created by the [`skip`] method on [`Iterator`]. See its
Expand Down
21 changes: 11 additions & 10 deletions src/libcore/iter/traits/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1037,9 +1037,6 @@ pub trait Iterator {
/// closure on each element of the iterator, and yield elements
/// while it returns [`Some(_)`][`Some`].
///
/// After [`None`] is returned, `map_while()`'s job is over, and the
/// rest of the elements are ignored.
///
/// # Examples
///
/// Basic usage:
Expand Down Expand Up @@ -1079,15 +1076,14 @@ pub trait Iterator {
/// #![feature(iter_map_while)]
/// use std::convert::TryFrom;
///
/// let a = [0, -1, 1, -2];
///
/// let mut iter = a.iter().map_while(|x| u32::try_from(*x).ok());
/// let a = [0, 1, 2, -3, 4, 5, -6];
///
/// assert_eq!(iter.next(), Some(0u32));
/// let iter = a.iter().map_while(|x| u32::try_from(*x).ok());
/// let vec = iter.collect::<Vec<_>>();
///
/// // We have more elements that are fit in u32, but since we already
/// // got a None, map_while() isn't used any more
/// assert_eq!(iter.next(), None);
/// // We have more elements which could fit in u32 (4, 5), but `map_while` returned `None` for `-3`
/// // (as the `predicate` returned `None`) and `collect` stops at the first `None` entcountered.
/// assert_eq!(vec, vec![0, 1, 2]);
/// ```
///
/// Because `map_while()` needs to look at the value in order to see if it
Expand Down Expand Up @@ -1115,8 +1111,13 @@ pub trait Iterator {
/// The `-3` is no longer there, because it was consumed in order to see if
/// the iteration should stop, but wasn't placed back into the iterator.
///
/// Note that unlike [`take_while`] this iterator is **not** fused.
/// It is also not specified what this iterator returns after the first` None` is returned.
/// If you need fused iterator, use [`fuse`].
///
/// [`Some`]: ../../std/option/enum.Option.html#variant.Some
/// [`None`]: ../../std/option/enum.Option.html#variant.None
/// [`fuse`]: #method.fuse
#[inline]
#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
fn map_while<B, P>(self, predicate: P) -> MapWhile<Self, P>
Expand Down

0 comments on commit 5ae85f4

Please sign in to comment.