| @@ -18,7 +18,9 @@ use crate::{ | |||
| map::Map, | |||
| map_init::MapInit, | |||
| map_with::MapWith, | |||
| product::Product, | |||
| reduce::Reduce, | |||
| sum::Sum, | |||
| try_fold::{TryFold, TryFoldWith}, | |||
| try_for_each::{TryForEach, TryForEachInit, TryForEachWith}, | |||
| try_reduce::TryReduce, | |||
| @@ -925,6 +927,70 @@ pub trait ParallelIterator<'a>: Sized + Send { | |||
| TryFoldWith::new(self, init, operation) | |||
| } | |||
| /// Sums up the items in the iterator. | |||
| /// | |||
| /// Note that the order in items will be reduced is not specified, | |||
| /// so if the `+` operator is not truly [associative] \(as is the | |||
| /// case for floating point numbers), then the results are not | |||
| /// fully deterministic. | |||
| /// | |||
| /// [associative]: https://en.wikipedia.org/wiki/Associative_property | |||
| /// | |||
| /// Basically equivalent to `self.reduce(|| 0, |a, b| a + b)`, | |||
| /// except that the type of `0` and the `+` operation may vary | |||
| /// depending on the type of value being produced. | |||
| /// | |||
| /// # Examples | |||
| /// | |||
| /// ``` | |||
| /// use rayon::prelude::*; | |||
| /// | |||
| /// let a = [1, 5, 7]; | |||
| /// | |||
| /// let sum: i32 = a.par_iter().sum(); | |||
| /// | |||
| /// assert_eq!(sum, 13); | |||
| /// ``` | |||
| fn sum<S>(self) -> Sum<Self, S> | |||
| where | |||
| S: std::iter::Sum<Self::Item> + std::iter::Sum<S> + Send, | |||
| { | |||
| Sum::new(self) | |||
| } | |||
| /// Multiplies all the items in the iterator. | |||
| /// | |||
| /// Note that the order in items will be reduced is not specified, | |||
| /// so if the `*` operator is not truly [associative] \(as is the | |||
| /// case for floating point numbers), then the results are not | |||
| /// fully deterministic. | |||
| /// | |||
| /// [associative]: https://en.wikipedia.org/wiki/Associative_property | |||
| /// | |||
| /// Basically equivalent to `self.reduce(|| 1, |a, b| a * b)`, | |||
| /// except that the type of `1` and the `*` operation may vary | |||
| /// depending on the type of value being produced. | |||
| /// | |||
| /// # Examples | |||
| /// | |||
| /// ``` | |||
| /// use rayon::prelude::*; | |||
| /// | |||
| /// fn factorial(n: u32) -> u32 { | |||
| /// (1..n+1).into_par_iter().product() | |||
| /// } | |||
| /// | |||
| /// assert_eq!(factorial(0), 1); | |||
| /// assert_eq!(factorial(1), 1); | |||
| /// assert_eq!(factorial(5), 120); | |||
| /// ``` | |||
| fn product<P>(self) -> Product<Self, P> | |||
| where | |||
| P: std::iter::Product<Self::Item> + std::iter::Product<P> + Send, | |||
| { | |||
| Product::new(self) | |||
| } | |||
| /// Creates a fresh collection containing all the elements produced | |||
| /// by this parallel iterator. | |||
| /// | |||
| @@ -11,7 +11,9 @@ pub mod map; | |||
| pub mod map_init; | |||
| pub mod map_with; | |||
| pub mod noop; | |||
| pub mod product; | |||
| pub mod reduce; | |||
| pub mod sum; | |||
| pub mod try_fold; | |||
| pub mod try_for_each; | |||
| pub mod try_reduce; | |||
| @@ -51,7 +53,6 @@ mod tests { | |||
| move || j.fetch_add(1, Ordering::Relaxed), | |||
| |init, item| -> Result<(), ()> { | |||
| println!("{:?} - {:?}", init, item); | |||
| Ok(()) | |||
| }, | |||
| ) | |||
| @@ -0,0 +1,121 @@ | |||
| use std::iter::{empty, once}; | |||
| use std::marker::PhantomData; | |||
| use crate::{core::Driver, Consumer, Executor, Folder, ParallelIterator, Reducer}; | |||
| /* Product */ | |||
| pub struct Product<X, P> { | |||
| iterator: X, | |||
| marker: PhantomData<P>, | |||
| } | |||
| impl<X, P> Product<X, P> { | |||
| pub fn new(iterator: X) -> Self { | |||
| Self { | |||
| iterator, | |||
| marker: PhantomData, | |||
| } | |||
| } | |||
| } | |||
| impl<'a, X, P> Driver<'a, P> for Product<X, P> | |||
| where | |||
| X: ParallelIterator<'a>, | |||
| P: std::iter::Product<X::Item> + std::iter::Product + Send + 'a, | |||
| { | |||
| fn exec_with<E>(self, executor: E) -> E::Result | |||
| where | |||
| E: Executor<'a, P>, | |||
| { | |||
| let iterator = self.iterator; | |||
| let consumer = ProductConsumer(PhantomData); | |||
| iterator.drive(executor, consumer) | |||
| } | |||
| } | |||
| /* ProductConsumer */ | |||
| pub struct ProductConsumer<P>(PhantomData<P>); | |||
| impl<P, I> Consumer<I> for ProductConsumer<P> | |||
| where | |||
| P: std::iter::Product<I> + std::iter::Product + Send, | |||
| { | |||
| type Folder = ProductFolder<P>; | |||
| type Reducer = ProductReducer<P>; | |||
| type Result = P; | |||
| fn split(self) -> (Self, Self, Self::Reducer) { | |||
| let left = self; | |||
| let right = ProductConsumer(PhantomData); | |||
| (left, right, ProductReducer(PhantomData)) | |||
| } | |||
| fn split_at(self, _index: usize) -> (Self, Self, Self::Reducer) { | |||
| let left = self; | |||
| let right = ProductConsumer(PhantomData); | |||
| (left, right, ProductReducer(PhantomData)) | |||
| } | |||
| fn into_folder(self) -> Self::Folder { | |||
| ProductFolder { | |||
| product: empty::<I>().product(), | |||
| } | |||
| } | |||
| } | |||
| /* ProductFolder */ | |||
| pub struct ProductFolder<P> { | |||
| product: P, | |||
| } | |||
| impl<P, I> Folder<I> for ProductFolder<P> | |||
| where | |||
| P: std::iter::Product<I> + std::iter::Product + Send, | |||
| { | |||
| type Result = P; | |||
| fn consume(mut self, item: I) -> Self { | |||
| self.product = mul(self.product, once(item).product()); | |||
| self | |||
| } | |||
| fn consume_iter<X>(mut self, iter: X) -> Self | |||
| where | |||
| X: IntoIterator<Item = I>, | |||
| { | |||
| self.product = mul(self.product, iter.into_iter().product()); | |||
| self | |||
| } | |||
| fn complete(self) -> Self::Result { | |||
| self.product | |||
| } | |||
| } | |||
| /* ProductReducer */ | |||
| pub struct ProductReducer<P>(PhantomData<P>); | |||
| impl<P> Reducer<P> for ProductReducer<P> | |||
| where | |||
| P: std::iter::Product + Send, | |||
| { | |||
| fn reduce(self, left: P, right: P) -> P { | |||
| mul(left, right) | |||
| } | |||
| } | |||
| fn mul<T>(left: T, right: T) -> T | |||
| where | |||
| T: std::iter::Product, | |||
| { | |||
| once(left).chain(once(right)).product() | |||
| } | |||
| @@ -0,0 +1,121 @@ | |||
| use std::iter::{empty, once}; | |||
| use std::marker::PhantomData; | |||
| use crate::{core::Driver, Consumer, Executor, Folder, ParallelIterator, Reducer}; | |||
| /* Sum */ | |||
| pub struct Sum<X, S> { | |||
| iterator: X, | |||
| marker: PhantomData<S>, | |||
| } | |||
| impl<X, S> Sum<X, S> { | |||
| pub fn new(iterator: X) -> Self { | |||
| Self { | |||
| iterator, | |||
| marker: PhantomData, | |||
| } | |||
| } | |||
| } | |||
| impl<'a, X, S> Driver<'a, S> for Sum<X, S> | |||
| where | |||
| X: ParallelIterator<'a>, | |||
| S: std::iter::Sum<X::Item> + std::iter::Sum + Send + 'a, | |||
| { | |||
| fn exec_with<E>(self, executor: E) -> E::Result | |||
| where | |||
| E: Executor<'a, S>, | |||
| { | |||
| let iterator = self.iterator; | |||
| let consumer = SumConsumer(PhantomData); | |||
| iterator.drive(executor, consumer) | |||
| } | |||
| } | |||
| /* SumConsumer */ | |||
| pub struct SumConsumer<S>(PhantomData<S>); | |||
| impl<S, I> Consumer<I> for SumConsumer<S> | |||
| where | |||
| S: std::iter::Sum<I> + std::iter::Sum + Send, | |||
| { | |||
| type Folder = SumFolder<S>; | |||
| type Reducer = SumReducer<S>; | |||
| type Result = S; | |||
| fn split(self) -> (Self, Self, Self::Reducer) { | |||
| let left = self; | |||
| let right = SumConsumer(PhantomData); | |||
| (left, right, SumReducer(PhantomData)) | |||
| } | |||
| fn split_at(self, _index: usize) -> (Self, Self, Self::Reducer) { | |||
| let left = self; | |||
| let right = SumConsumer(PhantomData); | |||
| (left, right, SumReducer(PhantomData)) | |||
| } | |||
| fn into_folder(self) -> Self::Folder { | |||
| SumFolder { | |||
| sum: empty::<I>().sum(), | |||
| } | |||
| } | |||
| } | |||
| /* SumFolder */ | |||
| pub struct SumFolder<S> { | |||
| sum: S, | |||
| } | |||
| impl<S, I> Folder<I> for SumFolder<S> | |||
| where | |||
| S: std::iter::Sum<I> + std::iter::Sum + Send, | |||
| { | |||
| type Result = S; | |||
| fn consume(mut self, item: I) -> Self { | |||
| self.sum = add(self.sum, once(item).sum()); | |||
| self | |||
| } | |||
| fn consume_iter<X>(mut self, iter: X) -> Self | |||
| where | |||
| X: IntoIterator<Item = I>, | |||
| { | |||
| self.sum = add(self.sum, iter.into_iter().sum()); | |||
| self | |||
| } | |||
| fn complete(self) -> Self::Result { | |||
| self.sum | |||
| } | |||
| } | |||
| /* SumReducer */ | |||
| pub struct SumReducer<S>(PhantomData<S>); | |||
| impl<S> Reducer<S> for SumReducer<S> | |||
| where | |||
| S: std::iter::Sum + Send, | |||
| { | |||
| fn reduce(self, left: S, right: S) -> S { | |||
| add(left, right) | |||
| } | |||
| } | |||
| fn add<T>(left: T, right: T) -> T | |||
| where | |||
| T: std::iter::Sum, | |||
| { | |||
| once(left).chain(once(right)).sum() | |||
| } | |||