From 9b429fd1219bfd15ec3fd9ce3cb073cdae6ed03c Mon Sep 17 00:00:00 2001 From: Nathan West Date: Mon, 6 Jan 2020 17:06:19 -0500 Subject: [PATCH 1/4] Add fold_self - Added `Iterator::fold_first`, which is like `fold`, but uses the first element in the iterator as the initial accumulator - Includes doc and doctest - Rebase commit; see #65222 for details Co-Authored-By: Tim Vermeulen --- src/libcore/iter/traits/iterator.rs | 56 ++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index 39bd270da8680..c066d535f24e5 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -2005,6 +2005,44 @@ 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: + /// + /// ``` + /// fn find_max(iter: I) -> Option + /// where I: Iterator, + /// I::Item: Ord, + /// { + /// iter.fold_first(|a, b| { + /// a.partial_cmp(b).map(move |cmp| match cmp { + /// Ordering::Greater | Ordering::Equal => a, + /// Ordering::Less => b, + /// }) + /// }) + /// } + /// let a = [10, 20, 5, -23, 0]; + /// let b = []; + /// + /// 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(mut self, f: F) -> Option + 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 +2535,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 +2599,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 +3252,6 @@ pub trait Iterator { } } -/// Fold an iterator without having to provide an initial value. -#[inline] -fn fold1(mut it: I, f: F) -> Option -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 Iterator for &mut I { type Item = I::Item; From a9a2a319afbeb7e2a54f343a9360bd9bc4863b4f Mon Sep 17 00:00:00 2001 From: dylan_DPC Date: Thu, 26 Mar 2020 23:18:37 +0100 Subject: [PATCH 2/4] fix docs --- src/libcore/iter/traits/iterator.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index c066d535f24e5..853059f98a609 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -2015,6 +2015,9 @@ pub trait Iterator { /// Find the maximum value: /// /// ``` + /// #![feature(iterator_fold_self)] + /// use std::cmp::Ordering; + /// /// fn find_max(iter: I) -> Option /// where I: Iterator, /// I::Item: Ord, @@ -2027,9 +2030,9 @@ pub trait Iterator { /// }) /// } /// let a = [10, 20, 5, -23, 0]; - /// let b = []; + /// let b: [u32; 0] = []; /// - /// assert_eq!(find_max(a.iter()), Some(20)); + /// assert_eq!(find_max(a.iter()), Some(&20)); /// assert_eq!(find_max(b.iter()), None); /// ``` #[inline] From 7e7c2f19a3ab215fd4ef4ba983d52aeacf35d3c4 Mon Sep 17 00:00:00 2001 From: dylan_DPC Date: Fri, 27 Mar 2020 02:45:56 +0100 Subject: [PATCH 3/4] simplify test --- src/libcore/iter/traits/iterator.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index 853059f98a609..62492f639e45b 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -2023,10 +2023,7 @@ pub trait Iterator { /// I::Item: Ord, /// { /// iter.fold_first(|a, b| { - /// a.partial_cmp(b).map(move |cmp| match cmp { - /// Ordering::Greater | Ordering::Equal => a, - /// Ordering::Less => b, - /// }) + /// if a >= b { a } else { b } /// }) /// } /// let a = [10, 20, 5, -23, 0]; From 268408f495f5fe225269842837ec1e49b498c881 Mon Sep 17 00:00:00 2001 From: dylan_DPC Date: Fri, 27 Mar 2020 03:21:15 +0100 Subject: [PATCH 4/4] remove unused import --- src/libcore/iter/traits/iterator.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index 62492f639e45b..daa880e7cd53b 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -2016,7 +2016,6 @@ pub trait Iterator { /// /// ``` /// #![feature(iterator_fold_self)] - /// use std::cmp::Ordering; /// /// fn find_max(iter: I) -> Option /// where I: Iterator,