Skip to content

Commit 87d5107

Browse files
committed
Add Iterator::{sum_nonempty, product_nonempty}
These return Option<T>. Some(result) if the iter is nonempty, None otherwise. Allows differentiation between empty iterators and iterators that reduce to neutral elements.
1 parent 0fc4501 commit 87d5107

File tree

3 files changed

+81
-0
lines changed

3 files changed

+81
-0
lines changed

src/libcore/iter/iterator.rs

+62
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use super::{Flatten, FlatMap, flatten_compat};
1717
use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, Rev};
1818
use super::{Zip, Sum, Product};
1919
use super::{ChainState, FromIterator, ZipImpl};
20+
use super::sources::once;
2021

2122
fn _assert_is_object_safe(_: &Iterator<Item=()>) {}
2223

@@ -2265,6 +2266,37 @@ pub trait Iterator {
22652266
Sum::sum(self)
22662267
}
22672268

2269+
/// Iterates over the entire iterator, adding all the elements
2270+
///
2271+
/// An empty iterator returns `None`, otherwise `Some(sum)`.
2272+
///
2273+
/// # Panics
2274+
///
2275+
/// When calling `sum_nonempty()` and a primitive integer type is being returned, this
2276+
/// method will panic if the computation overflows and debug assertions are
2277+
/// enabled.
2278+
///
2279+
/// # Examples
2280+
///
2281+
/// ```
2282+
/// #![feature(nonempty_iter_arith)]
2283+
/// let empty_sum = (1..1).sum_nonempty::<i32>();
2284+
/// assert_eq!(empty_sum, None);
2285+
///
2286+
/// let nonempty_sum = (1..=10).sum_nonempty::<i32>();
2287+
/// assert_eq!(nonempty_sum, Some(55));
2288+
/// ```
2289+
#[unstable(feature = "nonempty_iter_arith",
2290+
reason = "recently added unstable API",
2291+
issue = "0")]
2292+
fn sum_nonempty<S>(mut self) -> Option<S>
2293+
where Self: Sized,
2294+
S: Sum<Self::Item>,
2295+
{
2296+
self.next()
2297+
.map(|first| once(first).chain(self).sum())
2298+
}
2299+
22682300
/// Iterates over the entire iterator, multiplying all the elements
22692301
///
22702302
/// An empty iterator returns the one value of the type.
@@ -2293,6 +2325,36 @@ pub trait Iterator {
22932325
Product::product(self)
22942326
}
22952327

2328+
/// Iterates over the entire iterator, multiplying all the elements
2329+
///
2330+
/// An empty iterator returns `None`, otherwise `Some(product)`.
2331+
///
2332+
/// # Panics
2333+
///
2334+
/// When calling `product_nonempty()` and a primitive integer type is being returned,
2335+
/// method will panic if the computation overflows and debug assertions are
2336+
/// enabled.
2337+
///
2338+
/// # Examples
2339+
/// ```
2340+
/// #![feature(nonempty_iter_arith)]
2341+
/// let empty_product = (1..1).product_nonempty::<i32>();
2342+
/// assert_eq!(empty_product, None);
2343+
///
2344+
/// let nonempty_product = (1..=10).product_nonempty::<i32>();
2345+
/// assert_eq!(nonempty_product, Some(3628800));
2346+
/// ```
2347+
#[unstable(feature = "nonempty_iter_arith",
2348+
reason = "recently added unstable API",
2349+
issue = "0")]
2350+
fn product_nonempty<P>(mut self) -> Option<P>
2351+
where Self: Sized,
2352+
P: Product<Self::Item>,
2353+
{
2354+
self.next()
2355+
.map(|first| once(first).chain(self).product())
2356+
}
2357+
22962358
/// Lexicographically compares the elements of this `Iterator` with those
22972359
/// of another.
22982360
#[stable(feature = "iter_order", since = "1.5.0")]

src/libcore/tests/iter.rs

+18
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,15 @@ fn test_iterator_sum() {
10351035
assert_eq!(v[..0].iter().cloned().sum::<i32>(), 0);
10361036
}
10371037

1038+
#[test]
1039+
fn test_iterator_sum_nonempty() {
1040+
let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
1041+
assert_eq!(v[..0].iter().cloned().sum_nonempty::<i32>(), None);
1042+
assert_eq!(v[1..2].iter().cloned().sum_nonempty::<i32>(), Some(1));
1043+
assert_eq!(v[1..3].iter().cloned().sum_nonempty::<i32>(), Some(3));
1044+
assert_eq!(v.iter().cloned().sum_nonempty::<i32>(), Some(55));
1045+
}
1046+
10381047
#[test]
10391048
fn test_iterator_sum_result() {
10401049
let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)];
@@ -1051,6 +1060,15 @@ fn test_iterator_product() {
10511060
assert_eq!(v[..0].iter().cloned().product::<i32>(), 1);
10521061
}
10531062

1063+
#[test]
1064+
fn test_iterator_product_nonempty() {
1065+
let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
1066+
assert_eq!(v[..0].iter().cloned().product_nonempty::<i32>(), None);
1067+
assert_eq!(v[..1].iter().cloned().product_nonempty::<i32>(), Some(0));
1068+
assert_eq!(v[1..3].iter().cloned().product_nonempty::<i32>(), Some(2));
1069+
assert_eq!(v[1..5].iter().cloned().product_nonempty::<i32>(), Some(24));
1070+
}
1071+
10541072
#[test]
10551073
fn test_iterator_product_result() {
10561074
let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)];

src/libcore/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#![feature(flt2dec)]
2424
#![feature(fmt_internals)]
2525
#![feature(hashmap_internals)]
26+
#![feature(nonempty_iter_arith)]
2627
#![feature(pattern)]
2728
#![feature(range_is_empty)]
2829
#![feature(raw)]

0 commit comments

Comments
 (0)