summaryrefslogtreecommitdiffstats
path: root/library/core/src/iter
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--library/core/src/iter/adapters/array_chunks.rs170
-rw-r--r--library/core/src/iter/adapters/by_ref_sized.rs42
-rw-r--r--library/core/src/iter/adapters/copied.rs74
-rw-r--r--library/core/src/iter/adapters/flatten.rs375
-rw-r--r--library/core/src/iter/adapters/map_while.rs14
-rw-r--r--library/core/src/iter/adapters/mod.rs14
-rw-r--r--library/core/src/iter/adapters/scan.rs14
-rw-r--r--library/core/src/iter/adapters/skip.rs39
-rw-r--r--library/core/src/iter/adapters/take.rs14
-rw-r--r--library/core/src/iter/adapters/take_while.rs14
-rw-r--r--library/core/src/iter/mod.rs25
-rw-r--r--library/core/src/iter/range.rs28
-rw-r--r--library/core/src/iter/traits/collect.rs3
-rw-r--r--library/core/src/iter/traits/iterator.rs215
14 files changed, 703 insertions, 338 deletions
diff --git a/library/core/src/iter/adapters/array_chunks.rs b/library/core/src/iter/adapters/array_chunks.rs
new file mode 100644
index 000000000..d4fb88610
--- /dev/null
+++ b/library/core/src/iter/adapters/array_chunks.rs
@@ -0,0 +1,170 @@
+use crate::array;
+use crate::iter::{ByRefSized, FusedIterator, Iterator};
+use crate::ops::{ControlFlow, Try};
+
+/// An iterator over `N` elements of the iterator at a time.
+///
+/// The chunks do not overlap. If `N` does not divide the length of the
+/// iterator, then the last up to `N-1` elements will be omitted.
+///
+/// This `struct` is created by the [`array_chunks`][Iterator::array_chunks]
+/// method on [`Iterator`]. See its documentation for more.
+#[derive(Debug, Clone)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+pub struct ArrayChunks<I: Iterator, const N: usize> {
+ iter: I,
+ remainder: Option<array::IntoIter<I::Item, N>>,
+}
+
+impl<I, const N: usize> ArrayChunks<I, N>
+where
+ I: Iterator,
+{
+ #[track_caller]
+ pub(in crate::iter) fn new(iter: I) -> Self {
+ assert!(N != 0, "chunk size must be non-zero");
+ Self { iter, remainder: None }
+ }
+
+ /// Returns an iterator over the remaining elements of the original iterator
+ /// that are not going to be returned by this iterator. The returned
+ /// iterator will yield at most `N-1` elements.
+ #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+ #[inline]
+ pub fn into_remainder(self) -> Option<array::IntoIter<I::Item, N>> {
+ self.remainder
+ }
+}
+
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+impl<I, const N: usize> Iterator for ArrayChunks<I, N>
+where
+ I: Iterator,
+{
+ type Item = [I::Item; N];
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ self.try_for_each(ControlFlow::Break).break_value()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (lower, upper) = self.iter.size_hint();
+
+ (lower / N, upper.map(|n| n / N))
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.iter.count() / N
+ }
+
+ fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>,
+ {
+ let mut acc = init;
+ loop {
+ match self.iter.next_chunk() {
+ Ok(chunk) => acc = f(acc, chunk)?,
+ Err(remainder) => {
+ // Make sure to not override `self.remainder` with an empty array
+ // when `next` is called after `ArrayChunks` exhaustion.
+ self.remainder.get_or_insert(remainder);
+
+ break try { acc };
+ }
+ }
+ }
+ }
+
+ impl_fold_via_try_fold! { fold -> try_fold }
+}
+
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+impl<I, const N: usize> DoubleEndedIterator for ArrayChunks<I, N>
+where
+ I: DoubleEndedIterator + ExactSizeIterator,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.try_rfold((), |(), x| ControlFlow::Break(x)).break_value()
+ }
+
+ fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>,
+ {
+ // We are iterating from the back we need to first handle the remainder.
+ self.next_back_remainder();
+
+ let mut acc = init;
+ let mut iter = ByRefSized(&mut self.iter).rev();
+
+ // NB remainder is handled by `next_back_remainder`, so
+ // `next_chunk` can't return `Err` with non-empty remainder
+ // (assuming correct `I as ExactSizeIterator` impl).
+ while let Ok(mut chunk) = iter.next_chunk() {
+ // FIXME: do not do double reverse
+ // (we could instead add `next_chunk_back` for example)
+ chunk.reverse();
+ acc = f(acc, chunk)?
+ }
+
+ try { acc }
+ }
+
+ impl_fold_via_try_fold! { rfold -> try_rfold }
+}
+
+impl<I, const N: usize> ArrayChunks<I, N>
+where
+ I: DoubleEndedIterator + ExactSizeIterator,
+{
+ /// Updates `self.remainder` such that `self.iter.len` is divisible by `N`.
+ fn next_back_remainder(&mut self) {
+ // Make sure to not override `self.remainder` with an empty array
+ // when `next_back` is called after `ArrayChunks` exhaustion.
+ if self.remainder.is_some() {
+ return;
+ }
+
+ // We use the `ExactSizeIterator` implementation of the underlying
+ // iterator to know how many remaining elements there are.
+ let rem = self.iter.len() % N;
+
+ // Take the last `rem` elements out of `self.iter`.
+ let mut remainder =
+ // SAFETY: `unwrap_err` always succeeds because x % N < N for all x.
+ unsafe { self.iter.by_ref().rev().take(rem).next_chunk().unwrap_err_unchecked() };
+
+ // We used `.rev()` above, so we need to re-reverse the reminder
+ remainder.as_mut_slice().reverse();
+ self.remainder = Some(remainder);
+ }
+}
+
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+impl<I, const N: usize> FusedIterator for ArrayChunks<I, N> where I: FusedIterator {}
+
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+impl<I, const N: usize> ExactSizeIterator for ArrayChunks<I, N>
+where
+ I: ExactSizeIterator,
+{
+ #[inline]
+ fn len(&self) -> usize {
+ self.iter.len() / N
+ }
+
+ #[inline]
+ fn is_empty(&self) -> bool {
+ self.iter.len() < N
+ }
+}
diff --git a/library/core/src/iter/adapters/by_ref_sized.rs b/library/core/src/iter/adapters/by_ref_sized.rs
index cc1e8e8a2..1945e402f 100644
--- a/library/core/src/iter/adapters/by_ref_sized.rs
+++ b/library/core/src/iter/adapters/by_ref_sized.rs
@@ -1,4 +1,7 @@
-use crate::ops::Try;
+use crate::{
+ const_closure::ConstFnMutClosure,
+ ops::{NeverShortCircuit, Try},
+};
/// Like `Iterator::by_ref`, but requiring `Sized` so it can forward generics.
///
@@ -8,36 +11,41 @@ use crate::ops::Try;
#[derive(Debug)]
pub struct ByRefSized<'a, I>(pub &'a mut I);
+// The following implementations use UFCS-style, rather than trusting autoderef,
+// to avoid accidentally calling the `&mut Iterator` implementations.
+
#[unstable(feature = "std_internals", issue = "none")]
impl<I: Iterator> Iterator for ByRefSized<'_, I> {
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
- self.0.next()
+ I::next(self.0)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
- self.0.size_hint()
+ I::size_hint(self.0)
}
#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
- self.0.advance_by(n)
+ I::advance_by(self.0, n)
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
- self.0.nth(n)
+ I::nth(self.0, n)
}
#[inline]
- fn fold<B, F>(self, init: B, f: F) -> B
+ fn fold<B, F>(self, init: B, mut f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
- self.0.fold(init, f)
+ // `fold` needs ownership, so this can't forward directly.
+ I::try_fold(self.0, init, ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp))
+ .0
}
#[inline]
@@ -46,7 +54,7 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> {
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
- self.0.try_fold(init, f)
+ I::try_fold(self.0, init, f)
}
}
@@ -54,25 +62,31 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> {
impl<I: DoubleEndedIterator> DoubleEndedIterator for ByRefSized<'_, I> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
- self.0.next_back()
+ I::next_back(self.0)
}
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
- self.0.advance_back_by(n)
+ I::advance_back_by(self.0, n)
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
- self.0.nth_back(n)
+ I::nth_back(self.0, n)
}
#[inline]
- fn rfold<B, F>(self, init: B, f: F) -> B
+ fn rfold<B, F>(self, init: B, mut f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
- self.0.rfold(init, f)
+ // `rfold` needs ownership, so this can't forward directly.
+ I::try_rfold(
+ self.0,
+ init,
+ ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp),
+ )
+ .0
}
#[inline]
@@ -81,6 +95,6 @@ impl<I: DoubleEndedIterator> DoubleEndedIterator for ByRefSized<'_, I> {
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
- self.0.try_rfold(init, f)
+ I::try_rfold(self.0, init, f)
}
}
diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs
index f9bfd77d7..62d3afb81 100644
--- a/library/core/src/iter/adapters/copied.rs
+++ b/library/core/src/iter/adapters/copied.rs
@@ -2,7 +2,10 @@ use crate::iter::adapters::{
zip::try_get_unchecked, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
};
use crate::iter::{FusedIterator, TrustedLen};
+use crate::mem::MaybeUninit;
+use crate::mem::SizedTypeProperties;
use crate::ops::Try;
+use crate::{array, ptr};
/// An iterator that copies the elements of an underlying iterator.
///
@@ -44,6 +47,15 @@ where
self.it.next().copied()
}
+ fn next_chunk<const N: usize>(
+ &mut self,
+ ) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>>
+ where
+ Self: Sized,
+ {
+ <I as SpecNextChunk<'_, N, T>>::spec_next_chunk(&mut self.it)
+ }
+
fn size_hint(&self) -> (usize, Option<usize>) {
self.it.size_hint()
}
@@ -166,3 +178,65 @@ where
T: Copy,
{
}
+
+trait SpecNextChunk<'a, const N: usize, T: 'a>: Iterator<Item = &'a T>
+where
+ T: Copy,
+{
+ fn spec_next_chunk(&mut self) -> Result<[T; N], array::IntoIter<T, N>>;
+}
+
+impl<'a, const N: usize, I, T: 'a> SpecNextChunk<'a, N, T> for I
+where
+ I: Iterator<Item = &'a T>,
+ T: Copy,
+{
+ default fn spec_next_chunk(&mut self) -> Result<[T; N], array::IntoIter<T, N>> {
+ array::iter_next_chunk(&mut self.map(|e| *e))
+ }
+}
+
+impl<'a, const N: usize, T: 'a> SpecNextChunk<'a, N, T> for crate::slice::Iter<'a, T>
+where
+ T: Copy,
+{
+ fn spec_next_chunk(&mut self) -> Result<[T; N], array::IntoIter<T, N>> {
+ let mut raw_array = MaybeUninit::uninit_array();
+
+ let len = self.len();
+
+ if T::IS_ZST {
+ if len < N {
+ let _ = self.advance_by(len);
+ // SAFETY: ZSTs can be conjured ex nihilo; only the amount has to be correct
+ return Err(unsafe { array::IntoIter::new_unchecked(raw_array, 0..len) });
+ }
+
+ let _ = self.advance_by(N);
+ // SAFETY: ditto
+ return Ok(unsafe { MaybeUninit::array_assume_init(raw_array) });
+ }
+
+ if len < N {
+ // SAFETY: `len` indicates that this many elements are available and we just checked that
+ // it fits into the array.
+ unsafe {
+ ptr::copy_nonoverlapping(
+ self.as_ref().as_ptr(),
+ raw_array.as_mut_ptr() as *mut T,
+ len,
+ );
+ let _ = self.advance_by(len);
+ return Err(array::IntoIter::new_unchecked(raw_array, 0..len));
+ }
+ }
+
+ // SAFETY: `len` is larger than the array size. Copy a fixed amount here to fully initialize
+ // the array.
+ unsafe {
+ ptr::copy_nonoverlapping(self.as_ref().as_ptr(), raw_array.as_mut_ptr() as *mut T, N);
+ let _ = self.advance_by(N);
+ Ok(MaybeUninit::array_assume_init(raw_array))
+ }
+ }
+}
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index 15a120e35..307016c26 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -1,6 +1,6 @@
use crate::fmt;
use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map, TrustedLen};
-use crate::ops::Try;
+use crate::ops::{ControlFlow, Try};
/// An iterator that maps each element to an iterator, and yields the elements
/// of the produced iterators.
@@ -73,6 +73,21 @@ where
{
self.inner.fold(init, fold)
}
+
+ #[inline]
+ fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+ self.inner.advance_by(n)
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.inner.count()
+ }
+
+ #[inline]
+ fn last(self) -> Option<Self::Item> {
+ self.inner.last()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -103,6 +118,11 @@ where
{
self.inner.rfold(init, fold)
}
+
+ #[inline]
+ fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+ self.inner.advance_back_by(n)
+ }
}
#[stable(feature = "fused", since = "1.26.0")]
@@ -214,6 +234,21 @@ where
{
self.inner.fold(init, fold)
}
+
+ #[inline]
+ fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+ self.inner.advance_by(n)
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.inner.count()
+ }
+
+ #[inline]
+ fn last(self) -> Option<Self::Item> {
+ self.inner.last()
+ }
}
#[stable(feature = "iterator_flatten", since = "1.29.0")]
@@ -244,6 +279,11 @@ where
{
self.inner.rfold(init, fold)
}
+
+ #[inline]
+ fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+ self.inner.advance_back_by(n)
+ }
}
#[stable(feature = "iterator_flatten", since = "1.29.0")]
@@ -280,6 +320,144 @@ where
}
}
+impl<I, U> FlattenCompat<I, U>
+where
+ I: Iterator<Item: IntoIterator<IntoIter = U>>,
+{
+ /// Folds the inner iterators into an accumulator by applying an operation.
+ ///
+ /// Folds over the inner iterators, not over their elements. Is used by the `fold`, `count`,
+ /// and `last` methods.
+ #[inline]
+ fn iter_fold<Acc, Fold>(self, mut acc: Acc, mut fold: Fold) -> Acc
+ where
+ Fold: FnMut(Acc, U) -> Acc,
+ {
+ #[inline]
+ fn flatten<T: IntoIterator, Acc>(
+ fold: &mut impl FnMut(Acc, T::IntoIter) -> Acc,
+ ) -> impl FnMut(Acc, T) -> Acc + '_ {
+ move |acc, iter| fold(acc, iter.into_iter())
+ }
+
+ if let Some(iter) = self.frontiter {
+ acc = fold(acc, iter);
+ }
+
+ acc = self.iter.fold(acc, flatten(&mut fold));
+
+ if let Some(iter) = self.backiter {
+ acc = fold(acc, iter);
+ }
+
+ acc
+ }
+
+ /// Folds over the inner iterators as long as the given function returns successfully,
+ /// always storing the most recent inner iterator in `self.frontiter`.
+ ///
+ /// Folds over the inner iterators, not over their elements. Is used by the `try_fold` and
+ /// `advance_by` methods.
+ #[inline]
+ fn iter_try_fold<Acc, Fold, R>(&mut self, mut acc: Acc, mut fold: Fold) -> R
+ where
+ Fold: FnMut(Acc, &mut U) -> R,
+ R: Try<Output = Acc>,
+ {
+ #[inline]
+ fn flatten<'a, T: IntoIterator, Acc, R: Try<Output = Acc>>(
+ frontiter: &'a mut Option<T::IntoIter>,
+ fold: &'a mut impl FnMut(Acc, &mut T::IntoIter) -> R,
+ ) -> impl FnMut(Acc, T) -> R + 'a {
+ move |acc, iter| fold(acc, frontiter.insert(iter.into_iter()))
+ }
+
+ if let Some(iter) = &mut self.frontiter {
+ acc = fold(acc, iter)?;
+ }
+ self.frontiter = None;
+
+ acc = self.iter.try_fold(acc, flatten(&mut self.frontiter, &mut fold))?;
+ self.frontiter = None;
+
+ if let Some(iter) = &mut self.backiter {
+ acc = fold(acc, iter)?;
+ }
+ self.backiter = None;
+
+ try { acc }
+ }
+}
+
+impl<I, U> FlattenCompat<I, U>
+where
+ I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U>>,
+{
+ /// Folds the inner iterators into an accumulator by applying an operation, starting form the
+ /// back.
+ ///
+ /// Folds over the inner iterators, not over their elements. Is used by the `rfold` method.
+ #[inline]
+ fn iter_rfold<Acc, Fold>(self, mut acc: Acc, mut fold: Fold) -> Acc
+ where
+ Fold: FnMut(Acc, U) -> Acc,
+ {
+ #[inline]
+ fn flatten<T: IntoIterator, Acc>(
+ fold: &mut impl FnMut(Acc, T::IntoIter) -> Acc,
+ ) -> impl FnMut(Acc, T) -> Acc + '_ {
+ move |acc, iter| fold(acc, iter.into_iter())
+ }
+
+ if let Some(iter) = self.backiter {
+ acc = fold(acc, iter);
+ }
+
+ acc = self.iter.rfold(acc, flatten(&mut fold));
+
+ if let Some(iter) = self.frontiter {
+ acc = fold(acc, iter);
+ }
+
+ acc
+ }
+
+ /// Folds over the inner iterators in reverse order as long as the given function returns
+ /// successfully, always storing the most recent inner iterator in `self.backiter`.
+ ///
+ /// Folds over the inner iterators, not over their elements. Is used by the `try_rfold` and
+ /// `advance_back_by` methods.
+ #[inline]
+ fn iter_try_rfold<Acc, Fold, R>(&mut self, mut acc: Acc, mut fold: Fold) -> R
+ where
+ Fold: FnMut(Acc, &mut U) -> R,
+ R: Try<Output = Acc>,
+ {
+ #[inline]
+ fn flatten<'a, T: IntoIterator, Acc, R: Try>(
+ backiter: &'a mut Option<T::IntoIter>,
+ fold: &'a mut impl FnMut(Acc, &mut T::IntoIter) -> R,
+ ) -> impl FnMut(Acc, T) -> R + 'a {
+ move |acc, iter| fold(acc, backiter.insert(iter.into_iter()))
+ }
+
+ if let Some(iter) = &mut self.backiter {
+ acc = fold(acc, iter)?;
+ }
+ self.backiter = None;
+
+ acc = self.iter.try_rfold(acc, flatten(&mut self.backiter, &mut fold))?;
+ self.backiter = None;
+
+ if let Some(iter) = &mut self.frontiter {
+ acc = fold(acc, iter)?;
+ }
+ self.frontiter = None;
+
+ try { acc }
+ }
+}
+
impl<I, U> Iterator for FlattenCompat<I, U>
where
I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
@@ -323,99 +501,74 @@ where
}
#[inline]
- fn try_fold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R
+ fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Output = Acc>,
{
#[inline]
- fn flatten<'a, T: IntoIterator, Acc, R: Try<Output = Acc>>(
- frontiter: &'a mut Option<T::IntoIter>,
- fold: &'a mut impl FnMut(Acc, T::Item) -> R,
- ) -> impl FnMut(Acc, T) -> R + 'a {
- move |acc, x| {
- let mut mid = x.into_iter();
- let r = mid.try_fold(acc, &mut *fold);
- *frontiter = Some(mid);
- r
- }
- }
-
- if let Some(ref mut front) = self.frontiter {
- init = front.try_fold(init, &mut fold)?;
+ fn flatten<U: Iterator, Acc, R: Try<Output = Acc>>(
+ mut fold: impl FnMut(Acc, U::Item) -> R,
+ ) -> impl FnMut(Acc, &mut U) -> R {
+ move |acc, iter| iter.try_fold(acc, &mut fold)
}
- self.frontiter = None;
- init = self.iter.try_fold(init, flatten(&mut self.frontiter, &mut fold))?;
- self.frontiter = None;
-
- if let Some(ref mut back) = self.backiter {
- init = back.try_fold(init, &mut fold)?;
- }
- self.backiter = None;
-
- try { init }
+ self.iter_try_fold(init, flatten(fold))
}
#[inline]
- fn fold<Acc, Fold>(self, mut init: Acc, mut fold: Fold) -> Acc
+ fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
#[inline]
- fn flatten<T: IntoIterator, Acc>(
- fold: &mut impl FnMut(Acc, T::Item) -> Acc,
- ) -> impl FnMut(Acc, T) -> Acc + '_ {
- move |acc, x| x.into_iter().fold(acc, &mut *fold)
- }
-
- if let Some(front) = self.frontiter {
- init = front.fold(init, &mut fold);
- }
-
- init = self.iter.fold(init, flatten(&mut fold));
-
- if let Some(back) = self.backiter {
- init = back.fold(init, &mut fold);
+ fn flatten<U: Iterator, Acc>(
+ mut fold: impl FnMut(Acc, U::Item) -> Acc,
+ ) -> impl FnMut(Acc, U) -> Acc {
+ move |acc, iter| iter.fold(acc, &mut fold)
}
- init
+ self.iter_fold(init, flatten(fold))
}
#[inline]
#[rustc_inherit_overflow_checks]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
- let mut rem = n;
- loop {
- if let Some(ref mut front) = self.frontiter {
- match front.advance_by(rem) {
- ret @ Ok(_) => return ret,
- Err(advanced) => rem -= advanced,
- }
- }
- self.frontiter = match self.iter.next() {
- Some(iterable) => Some(iterable.into_iter()),
- _ => break,
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ fn advance<U: Iterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> {
+ match iter.advance_by(n) {
+ Ok(()) => ControlFlow::BREAK,
+ Err(advanced) => ControlFlow::Continue(n - advanced),
}
}
- self.frontiter = None;
-
- if let Some(ref mut back) = self.backiter {
- match back.advance_by(rem) {
- ret @ Ok(_) => return ret,
- Err(advanced) => rem -= advanced,
- }
+ match self.iter_try_fold(n, advance) {
+ ControlFlow::Continue(remaining) if remaining > 0 => Err(n - remaining),
+ _ => Ok(()),
}
+ }
- if rem > 0 {
- return Err(n - rem);
+ #[inline]
+ fn count(self) -> usize {
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ fn count<U: Iterator>(acc: usize, iter: U) -> usize {
+ acc + iter.count()
}
- self.backiter = None;
+ self.iter_fold(0, count)
+ }
+
+ #[inline]
+ fn last(self) -> Option<Self::Item> {
+ #[inline]
+ fn last<U: Iterator>(last: Option<U::Item>, iter: U) -> Option<U::Item> {
+ iter.last().or(last)
+ }
- Ok(())
+ self.iter_fold(None, last)
}
}
@@ -438,105 +591,53 @@ where
}
#[inline]
- fn try_rfold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R
+ fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Output = Acc>,
{
#[inline]
- fn flatten<'a, T: IntoIterator, Acc, R: Try<Output = Acc>>(
- backiter: &'a mut Option<T::IntoIter>,
- fold: &'a mut impl FnMut(Acc, T::Item) -> R,
- ) -> impl FnMut(Acc, T) -> R + 'a
- where
- T::IntoIter: DoubleEndedIterator,
- {
- move |acc, x| {
- let mut mid = x.into_iter();
- let r = mid.try_rfold(acc, &mut *fold);
- *backiter = Some(mid);
- r
- }
+ fn flatten<U: DoubleEndedIterator, Acc, R: Try<Output = Acc>>(
+ mut fold: impl FnMut(Acc, U::Item) -> R,
+ ) -> impl FnMut(Acc, &mut U) -> R {
+ move |acc, iter| iter.try_rfold(acc, &mut fold)
}
- if let Some(ref mut back) = self.backiter {
- init = back.try_rfold(init, &mut fold)?;
- }
- self.backiter = None;
-
- init = self.iter.try_rfold(init, flatten(&mut self.backiter, &mut fold))?;
- self.backiter = None;
-
- if let Some(ref mut front) = self.frontiter {
- init = front.try_rfold(init, &mut fold)?;
- }
- self.frontiter = None;
-
- try { init }
+ self.iter_try_rfold(init, flatten(fold))
}
#[inline]
- fn rfold<Acc, Fold>(self, mut init: Acc, mut fold: Fold) -> Acc
+ fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
#[inline]
- fn flatten<T: IntoIterator, Acc>(
- fold: &mut impl FnMut(Acc, T::Item) -> Acc,
- ) -> impl FnMut(Acc, T) -> Acc + '_
- where
- T::IntoIter: DoubleEndedIterator,
- {
- move |acc, x| x.into_iter().rfold(acc, &mut *fold)
- }
-
- if let Some(back) = self.backiter {
- init = back.rfold(init, &mut fold);
+ fn flatten<U: DoubleEndedIterator, Acc>(
+ mut fold: impl FnMut(Acc, U::Item) -> Acc,
+ ) -> impl FnMut(Acc, U) -> Acc {
+ move |acc, iter| iter.rfold(acc, &mut fold)
}
- init = self.iter.rfold(init, flatten(&mut fold));
-
- if let Some(front) = self.frontiter {
- init = front.rfold(init, &mut fold);
- }
-
- init
+ self.iter_rfold(init, flatten(fold))
}
#[inline]
#[rustc_inherit_overflow_checks]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
- let mut rem = n;
- loop {
- if let Some(ref mut back) = self.backiter {
- match back.advance_back_by(rem) {
- ret @ Ok(_) => return ret,
- Err(advanced) => rem -= advanced,
- }
- }
- match self.iter.next_back() {
- Some(iterable) => self.backiter = Some(iterable.into_iter()),
- _ => break,
- }
- }
-
- self.backiter = None;
-
- if let Some(ref mut front) = self.frontiter {
- match front.advance_back_by(rem) {
- ret @ Ok(_) => return ret,
- Err(advanced) => rem -= advanced,
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ fn advance<U: DoubleEndedIterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> {
+ match iter.advance_back_by(n) {
+ Ok(()) => ControlFlow::BREAK,
+ Err(advanced) => ControlFlow::Continue(n - advanced),
}
}
- if rem > 0 {
- return Err(n - rem);
+ match self.iter_try_rfold(n, advance) {
+ ControlFlow::Continue(remaining) if remaining > 0 => Err(n - remaining),
+ _ => Ok(()),
}
-
- self.frontiter = None;
-
- Ok(())
}
}
diff --git a/library/core/src/iter/adapters/map_while.rs b/library/core/src/iter/adapters/map_while.rs
index 1e8d6bf3e..fbdeca4d4 100644
--- a/library/core/src/iter/adapters/map_while.rs
+++ b/library/core/src/iter/adapters/map_while.rs
@@ -64,19 +64,7 @@ where
.into_try()
}
- #[inline]
- fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- #[inline]
- fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_fold(init, ok(fold)).unwrap()
- }
+ impl_fold_via_try_fold! { fold -> try_fold }
}
#[unstable(issue = "none", feature = "inplace_iteration")]
diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs
index 916a26e24..8cc2b7cec 100644
--- a/library/core/src/iter/adapters/mod.rs
+++ b/library/core/src/iter/adapters/mod.rs
@@ -1,6 +1,7 @@
use crate::iter::{InPlaceIterable, Iterator};
-use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, NeverShortCircuit, Residual, Try};
+use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
+mod array_chunks;
mod by_ref_sized;
mod chain;
mod cloned;
@@ -32,6 +33,9 @@ pub use self::{
scan::Scan, skip::Skip, skip_while::SkipWhile, take::Take, take_while::TakeWhile, zip::Zip,
};
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+pub use self::array_chunks::ArrayChunks;
+
#[unstable(feature = "std_internals", issue = "none")]
pub use self::by_ref_sized::ByRefSized;
@@ -199,13 +203,7 @@ where
.into_try()
}
- fn fold<B, F>(mut self, init: B, fold: F) -> B
- where
- Self: Sized,
- F: FnMut(B, Self::Item) -> B,
- {
- self.try_fold(init, NeverShortCircuit::wrap_mut_2(fold)).0
- }
+ impl_fold_via_try_fold! { fold -> try_fold }
}
#[unstable(issue = "none", feature = "inplace_iteration")]
diff --git a/library/core/src/iter/adapters/scan.rs b/library/core/src/iter/adapters/scan.rs
index 80bfd2231..62470512c 100644
--- a/library/core/src/iter/adapters/scan.rs
+++ b/library/core/src/iter/adapters/scan.rs
@@ -74,19 +74,7 @@ where
self.iter.try_fold(init, scan(state, f, fold)).into_try()
}
- #[inline]
- fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- #[inline]
- fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_fold(init, ok(fold)).unwrap()
- }
+ impl_fold_via_try_fold! { fold -> try_fold }
}
#[unstable(issue = "none", feature = "inplace_iteration")]
diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs
index 2c283100f..c6334880d 100644
--- a/library/core/src/iter/adapters/skip.rs
+++ b/library/core/src/iter/adapters/skip.rs
@@ -33,21 +33,32 @@ where
#[inline]
fn next(&mut self) -> Option<I::Item> {
if unlikely(self.n > 0) {
- self.iter.nth(crate::mem::take(&mut self.n) - 1)?;
+ self.iter.nth(crate::mem::take(&mut self.n))
+ } else {
+ self.iter.next()
}
- self.iter.next()
}
#[inline]
fn nth(&mut self, n: usize) -> Option<I::Item> {
- // Can't just add n + self.n due to overflow.
if self.n > 0 {
- let to_skip = self.n;
- self.n = 0;
- // nth(n) skips n+1
- self.iter.nth(to_skip - 1)?;
+ let skip: usize = crate::mem::take(&mut self.n);
+ // Checked add to handle overflow case.
+ let n = match skip.checked_add(n) {
+ Some(nth) => nth,
+ None => {
+ // In case of overflow, load skip value, before loading `n`.
+ // Because the amount of elements to iterate is beyond `usize::MAX`, this
+ // is split into two `nth` calls where the `skip` `nth` call is discarded.
+ self.iter.nth(skip - 1)?;
+ n
+ }
+ };
+ // Load nth element including skip.
+ self.iter.nth(n)
+ } else {
+ self.iter.nth(n)
}
- self.iter.nth(n)
}
#[inline]
@@ -195,17 +206,7 @@ where
if n == 0 { try { init } } else { self.iter.try_rfold(init, check(n, fold)).into_try() }
}
- fn rfold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
- where
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- #[inline]
- fn ok<Acc, T>(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, T) -> Result<Acc, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_rfold(init, ok(fold)).unwrap()
- }
+ impl_fold_via_try_fold! { rfold -> try_rfold }
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs
index 2962e0104..58a0b9d7b 100644
--- a/library/core/src/iter/adapters/take.rs
+++ b/library/core/src/iter/adapters/take.rs
@@ -98,19 +98,7 @@ where
}
}
- #[inline]
- fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- #[inline]
- fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_fold(init, ok(fold)).unwrap()
- }
+ impl_fold_via_try_fold! { fold -> try_fold }
#[inline]
#[rustc_inherit_overflow_checks]
diff --git a/library/core/src/iter/adapters/take_while.rs b/library/core/src/iter/adapters/take_while.rs
index ded216da9..ec66dc3ae 100644
--- a/library/core/src/iter/adapters/take_while.rs
+++ b/library/core/src/iter/adapters/take_while.rs
@@ -94,19 +94,7 @@ where
}
}
- #[inline]
- fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- #[inline]
- fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_fold(init, ok(fold)).unwrap()
- }
+ impl_fold_via_try_fold! { fold -> try_fold }
}
#[stable(feature = "fused", since = "1.26.0")]
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs
index d5c6aed5b..ef0f39782 100644
--- a/library/core/src/iter/mod.rs
+++ b/library/core/src/iter/mod.rs
@@ -352,6 +352,29 @@
#![stable(feature = "rust1", since = "1.0.0")]
+// This needs to be up here in order to be usable in the child modules
+macro_rules! impl_fold_via_try_fold {
+ (fold -> try_fold) => {
+ impl_fold_via_try_fold! { @internal fold -> try_fold }
+ };
+ (rfold -> try_rfold) => {
+ impl_fold_via_try_fold! { @internal rfold -> try_rfold }
+ };
+ (@internal $fold:ident -> $try_fold:ident) => {
+ #[inline]
+ fn $fold<AAA, FFF>(mut self, init: AAA, mut fold: FFF) -> AAA
+ where
+ FFF: FnMut(AAA, Self::Item) -> AAA,
+ {
+ use crate::const_closure::ConstFnMutClosure;
+ use crate::ops::NeverShortCircuit;
+
+ let fold = ConstFnMutClosure::new(&mut fold, NeverShortCircuit::wrap_mut_2_imp);
+ self.$try_fold(init, fold).0
+ }
+ };
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::traits::Iterator;
@@ -398,6 +421,8 @@ pub use self::traits::{
#[stable(feature = "iter_zip", since = "1.59.0")]
pub use self::adapters::zip;
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+pub use self::adapters::ArrayChunks;
#[unstable(feature = "std_internals", issue = "none")]
pub use self::adapters::ByRefSized;
#[stable(feature = "iter_cloned", since = "1.1.0")]
diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs
index f7aeee8c9..ac7b389b1 100644
--- a/library/core/src/iter/range.rs
+++ b/library/core/src/iter/range.rs
@@ -1150,19 +1150,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
self.spec_try_fold(init, f)
}
- #[inline]
- fn fold<B, F>(mut self, init: B, f: F) -> B
- where
- Self: Sized,
- F: FnMut(B, Self::Item) -> B,
- {
- #[inline]
- fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_fold(init, ok(f)).unwrap()
- }
+ impl_fold_via_try_fold! { fold -> try_fold }
#[inline]
fn last(mut self) -> Option<A> {
@@ -1230,19 +1218,7 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
self.spec_try_rfold(init, f)
}
- #[inline]
- fn rfold<B, F>(mut self, init: B, f: F) -> B
- where
- Self: Sized,
- F: FnMut(B, Self::Item) -> B,
- {
- #[inline]
- fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_rfold(init, ok(f)).unwrap()
- }
+ impl_fold_via_try_fold! { rfold -> try_rfold }
}
// Safety: See above implementation for `ops::Range<A>`
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 12ca508be..e099700e3 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -228,6 +228,7 @@ pub trait FromIterator<A>: Sized {
#[rustc_diagnostic_item = "IntoIterator"]
#[rustc_skip_array_during_method_dispatch]
#[stable(feature = "rust1", since = "1.0.0")]
+#[const_trait]
pub trait IntoIterator {
/// The type of the elements being iterated over.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -263,7 +264,7 @@ pub trait IntoIterator {
#[rustc_const_unstable(feature = "const_intoiterator_identity", issue = "90603")]
#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: ~const Iterator> const IntoIterator for I {
+impl<I: Iterator> const IntoIterator for I {
type Item = I::Item;
type IntoIter = I;
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 275412b57..789a87968 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -5,7 +5,7 @@ use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
use super::super::try_process;
use super::super::ByRefSized;
use super::super::TrustedRandomAccessNoCoerce;
-use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
+use super::super::{ArrayChunks, Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
use super::super::{FlatMap, Flatten};
use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip};
use super::super::{
@@ -692,7 +692,7 @@ pub trait Iterator {
/// assert_eq!(it.next(), Some(NotClone(99))); // The separator.
/// assert_eq!(it.next(), Some(NotClone(1))); // The next element from `v`.
/// assert_eq!(it.next(), Some(NotClone(99))); // The separator.
- /// assert_eq!(it.next(), Some(NotClone(2))); // The last element from from `v`.
+ /// assert_eq!(it.next(), Some(NotClone(2))); // The last element from `v`.
/// assert_eq!(it.next(), None); // The iterator is finished.
/// ```
///
@@ -2431,22 +2431,13 @@ pub trait Iterator {
///
/// # Example
///
- /// Find the maximum value:
- ///
/// ```
- /// fn find_max<I>(iter: I) -> Option<I::Item>
- /// where I: Iterator,
- /// I::Item: Ord,
- /// {
- /// iter.reduce(|accum, item| {
- /// if accum >= item { accum } else { item }
- /// })
- /// }
- /// let a = [10, 20, 5, -23, 0];
- /// let b: [u32; 0] = [];
+ /// let reduced: i32 = (1..10).reduce(|acc, e| acc + e).unwrap();
+ /// assert_eq!(reduced, 45);
///
- /// assert_eq!(find_max(a.iter()), Some(&20));
- /// assert_eq!(find_max(b.iter()), None);
+ /// // Which is equivalent to doing it with `fold`:
+ /// let folded: i32 = (1..10).fold(0, |acc, e| acc + e);
+ /// assert_eq!(reduced, folded);
/// ```
#[inline]
#[stable(feature = "iterator_fold_self", since = "1.51.0")]
@@ -2906,14 +2897,14 @@ pub trait Iterator {
/// Stopping at the first `true`:
///
/// ```
- /// let a = [1, 2, 3];
+ /// let a = [-1, 2, 3, 4];
///
/// let mut iter = a.iter();
///
- /// assert_eq!(iter.rposition(|&x| x == 2), Some(1));
+ /// assert_eq!(iter.rposition(|&x| x >= 2), Some(3));
///
/// // we can still use `iter`, as there are more elements.
- /// assert_eq!(iter.next(), Some(&1));
+ /// assert_eq!(iter.next(), Some(&-1));
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -3316,6 +3307,49 @@ pub trait Iterator {
Cycle::new(self)
}
+ /// Returns an iterator over `N` elements of the iterator at a time.
+ ///
+ /// The chunks do not overlap. If `N` does not divide the length of the
+ /// iterator, then the last up to `N-1` elements will be omitted and can be
+ /// retrieved from the [`.into_remainder()`][ArrayChunks::into_remainder]
+ /// function of the iterator.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `N` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(iter_array_chunks)]
+ ///
+ /// let mut iter = "lorem".chars().array_chunks();
+ /// assert_eq!(iter.next(), Some(['l', 'o']));
+ /// assert_eq!(iter.next(), Some(['r', 'e']));
+ /// assert_eq!(iter.next(), None);
+ /// assert_eq!(iter.into_remainder().unwrap().as_slice(), &['m']);
+ /// ```
+ ///
+ /// ```
+ /// #![feature(iter_array_chunks)]
+ ///
+ /// let data = [1, 1, 2, -2, 6, 0, 3, 1];
+ /// // ^-----^ ^------^
+ /// for [x, y, z] in data.iter().array_chunks() {
+ /// assert_eq!(x + y + z, 4);
+ /// }
+ /// ```
+ #[track_caller]
+ #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+ fn array_chunks<const N: usize>(self) -> ArrayChunks<Self, N>
+ where
+ Self: Sized,
+ {
+ ArrayChunks::new(self)
+ }
+
/// Sums the elements of an iterator.
///
/// Takes each element, adds them together, and returns the result.
@@ -3418,36 +3452,27 @@ pub trait Iterator {
/// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (2 * x).cmp(&y)), Ordering::Greater);
/// ```
#[unstable(feature = "iter_order_by", issue = "64295")]
- fn cmp_by<I, F>(mut self, other: I, mut cmp: F) -> Ordering
+ fn cmp_by<I, F>(self, other: I, cmp: F) -> Ordering
where
Self: Sized,
I: IntoIterator,
F: FnMut(Self::Item, I::Item) -> Ordering,
{
- let mut other = other.into_iter();
-
- loop {
- let x = match self.next() {
- None => {
- if other.next().is_none() {
- return Ordering::Equal;
- } else {
- return Ordering::Less;
- }
- }
- Some(val) => val,
- };
-
- let y = match other.next() {
- None => return Ordering::Greater,
- Some(val) => val,
- };
-
- match cmp(x, y) {
- Ordering::Equal => (),
- non_eq => return non_eq,
+ #[inline]
+ fn compare<X, Y, F>(mut cmp: F) -> impl FnMut(X, Y) -> ControlFlow<Ordering>
+ where
+ F: FnMut(X, Y) -> Ordering,
+ {
+ move |x, y| match cmp(x, y) {
+ Ordering::Equal => ControlFlow::CONTINUE,
+ non_eq => ControlFlow::Break(non_eq),
}
}
+
+ match iter_compare(self, other.into_iter(), compare(cmp)) {
+ ControlFlow::Continue(ord) => ord,
+ ControlFlow::Break(ord) => ord,
+ }
}
/// [Lexicographically](Ord#lexicographical-comparison) compares the elements of this [`Iterator`] with those
@@ -3503,36 +3528,27 @@ pub trait Iterator {
/// );
/// ```
#[unstable(feature = "iter_order_by", issue = "64295")]
- fn partial_cmp_by<I, F>(mut self, other: I, mut partial_cmp: F) -> Option<Ordering>
+ fn partial_cmp_by<I, F>(self, other: I, partial_cmp: F) -> Option<Ordering>
where
Self: Sized,
I: IntoIterator,
F: FnMut(Self::Item, I::Item) -> Option<Ordering>,
{
- let mut other = other.into_iter();
-
- loop {
- let x = match self.next() {
- None => {
- if other.next().is_none() {
- return Some(Ordering::Equal);
- } else {
- return Some(Ordering::Less);
- }
- }
- Some(val) => val,
- };
-
- let y = match other.next() {
- None => return Some(Ordering::Greater),
- Some(val) => val,
- };
-
- match partial_cmp(x, y) {
- Some(Ordering::Equal) => (),
- non_eq => return non_eq,
+ #[inline]
+ fn compare<X, Y, F>(mut partial_cmp: F) -> impl FnMut(X, Y) -> ControlFlow<Option<Ordering>>
+ where
+ F: FnMut(X, Y) -> Option<Ordering>,
+ {
+ move |x, y| match partial_cmp(x, y) {
+ Some(Ordering::Equal) => ControlFlow::CONTINUE,
+ non_eq => ControlFlow::Break(non_eq),
}
}
+
+ match iter_compare(self, other.into_iter(), compare(partial_cmp)) {
+ ControlFlow::Continue(ord) => Some(ord),
+ ControlFlow::Break(ord) => ord,
+ }
}
/// Determines if the elements of this [`Iterator`] are equal to those of
@@ -3570,29 +3586,26 @@ pub trait Iterator {
/// assert!(xs.iter().eq_by(&ys, |&x, &y| x * x == y));
/// ```
#[unstable(feature = "iter_order_by", issue = "64295")]
- fn eq_by<I, F>(mut self, other: I, mut eq: F) -> bool
+ fn eq_by<I, F>(self, other: I, eq: F) -> bool
where
Self: Sized,
I: IntoIterator,
F: FnMut(Self::Item, I::Item) -> bool,
{
- let mut other = other.into_iter();
-
- loop {
- let x = match self.next() {
- None => return other.next().is_none(),
- Some(val) => val,
- };
-
- let y = match other.next() {
- None => return false,
- Some(val) => val,
- };
-
- if !eq(x, y) {
- return false;
+ #[inline]
+ fn compare<X, Y, F>(mut eq: F) -> impl FnMut(X, Y) -> ControlFlow<()>
+ where
+ F: FnMut(X, Y) -> bool,
+ {
+ move |x, y| {
+ if eq(x, y) { ControlFlow::CONTINUE } else { ControlFlow::BREAK }
}
}
+
+ match iter_compare(self, other.into_iter(), compare(eq)) {
+ ControlFlow::Continue(ord) => ord == Ordering::Equal,
+ ControlFlow::Break(()) => false,
+ }
}
/// Determines if the elements of this [`Iterator`] are unequal to those of
@@ -3817,6 +3830,46 @@ pub trait Iterator {
}
}
+/// Compares two iterators element-wise using the given function.
+///
+/// If `ControlFlow::CONTINUE` is returned from the function, the comparison moves on to the next
+/// elements of both iterators. Returning `ControlFlow::Break(x)` short-circuits the iteration and
+/// returns `ControlFlow::Break(x)`. If one of the iterators runs out of elements,
+/// `ControlFlow::Continue(ord)` is returned where `ord` is the result of comparing the lengths of
+/// the iterators.
+///
+/// Isolates the logic shared by ['cmp_by'](Iterator::cmp_by),
+/// ['partial_cmp_by'](Iterator::partial_cmp_by), and ['eq_by'](Iterator::eq_by).
+#[inline]
+fn iter_compare<A, B, F, T>(mut a: A, mut b: B, f: F) -> ControlFlow<T, Ordering>
+where
+ A: Iterator,
+ B: Iterator,
+ F: FnMut(A::Item, B::Item) -> ControlFlow<T>,
+{
+ #[inline]
+ fn compare<'a, B, X, T>(
+ b: &'a mut B,
+ mut f: impl FnMut(X, B::Item) -> ControlFlow<T> + 'a,
+ ) -> impl FnMut(X) -> ControlFlow<ControlFlow<T, Ordering>> + 'a
+ where
+ B: Iterator,
+ {
+ move |x| match b.next() {
+ None => ControlFlow::Break(ControlFlow::Continue(Ordering::Greater)),
+ Some(y) => f(x, y).map_break(ControlFlow::Break),
+ }
+ }
+
+ match a.try_for_each(compare(&mut b, f)) {
+ ControlFlow::Continue(()) => ControlFlow::Continue(match b.next() {
+ None => Ordering::Equal,
+ Some(_) => Ordering::Less,
+ }),
+ ControlFlow::Break(x) => x,
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator + ?Sized> Iterator for &mut I {
type Item = I::Item;