about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2020-03-27 15:09:48 +0100
committerGitHub <noreply@github.com>2020-03-27 15:09:48 +0100
commit87fdf35572089028dff6bf4eb620c2f99764c1e0 (patch)
tree4cf31fd8ec3af094dbe8fa2ab968f26f56928da1 /src
parent697d6b3f3fa1f163acb5ae0911d7df7f02a54444 (diff)
parent268408f495f5fe225269842837ec1e49b498c881 (diff)
downloadrust-87fdf35572089028dff6bf4eb620c2f99764c1e0.tar.gz
rust-87fdf35572089028dff6bf4eb620c2f99764c1e0.zip
Rollup merge of #65222 - Lucretiel:fold_self, r=kodrAus
Proposal: `fold_self` and `try_fold_self` for Iterators

This pull request proposes & implements two new methods on Iterators: `fold_self` and `try_fold_self`. These are variants of `fold` and `try_fold` that use the first element in the iterator as the initial accumulator.

Let me know if a public feature like this requires an RFC, or if this pull request is sufficient as place for discussion.
Diffstat (limited to 'src')
-rw-r--r--src/libcore/iter/traits/iterator.rs55
1 files changed, 39 insertions, 16 deletions
diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs
index 39bd270da86..daa880e7cd5 100644
--- a/src/libcore/iter/traits/iterator.rs
+++ b/src/libcore/iter/traits/iterator.rs
@@ -2005,6 +2005,43 @@ pub trait Iterator {
         self.try_fold(init, ok(f)).unwrap()
     }
 
+    /// The same as [`fold()`](#method.fold), but uses the first element in the
+    /// iterator as the initial value, folding every subsequent element into it.
+    /// If the iterator is empty, return `None`; otherwise, return the result
+    /// of the fold.
+    ///
+    /// # Example
+    ///
+    /// Find the maximum value:
+    ///
+    /// ```
+    /// #![feature(iterator_fold_self)]
+    ///
+    /// fn find_max<I>(iter: I) -> Option<I::Item>
+    ///     where I: Iterator,
+    ///           I::Item: Ord,
+    /// {
+    ///     iter.fold_first(|a, b| {
+    ///         if a >= b { a } else { b }
+    ///     })
+    /// }
+    /// let a = [10, 20, 5, -23, 0];
+    /// let b: [u32; 0] = [];
+    ///
+    /// assert_eq!(find_max(a.iter()), Some(&20));
+    /// assert_eq!(find_max(b.iter()), None);
+    /// ```
+    #[inline]
+    #[unstable(feature = "iterator_fold_self", issue = "68125")]
+    fn fold_first<F>(mut self, f: F) -> Option<Self::Item>
+    where
+        Self: Sized,
+        F: FnMut(Self::Item, Self::Item) -> Self::Item,
+    {
+        let first = self.next()?;
+        Some(self.fold(first, f))
+    }
+
     /// Tests if every element of the iterator matches a predicate.
     ///
     /// `all()` takes a closure that returns `true` or `false`. It applies
@@ -2497,7 +2534,7 @@ pub trait Iterator {
             move |x, y| cmp::max_by(x, y, &mut compare)
         }
 
-        fold1(self, fold(compare))
+        self.fold_first(fold(compare))
     }
 
     /// Returns the element that gives the minimum value from the
@@ -2561,7 +2598,7 @@ pub trait Iterator {
             move |x, y| cmp::min_by(x, y, &mut compare)
         }
 
-        fold1(self, fold(compare))
+        self.fold_first(fold(compare))
     }
 
     /// Reverses an iterator's direction.
@@ -3214,20 +3251,6 @@ pub trait Iterator {
     }
 }
 
-/// Fold an iterator without having to provide an initial value.
-#[inline]
-fn fold1<I, F>(mut it: I, f: F) -> Option<I::Item>
-where
-    I: Iterator,
-    F: FnMut(I::Item, I::Item) -> I::Item,
-{
-    // start with the first element as our selection. This avoids
-    // having to use `Option`s inside the loop, translating to a
-    // sizeable performance gain (6x in one case).
-    let first = it.next()?;
-    Some(it.fold(first, f))
-}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I: Iterator + ?Sized> Iterator for &mut I {
     type Item = I::Item;