| @@ -18,7 +18,9 @@ use crate::{ | |||||
| map::Map, | map::Map, | ||||
| map_init::MapInit, | map_init::MapInit, | ||||
| map_with::MapWith, | map_with::MapWith, | ||||
| product::Product, | |||||
| reduce::Reduce, | reduce::Reduce, | ||||
| sum::Sum, | |||||
| try_fold::{TryFold, TryFoldWith}, | try_fold::{TryFold, TryFoldWith}, | ||||
| try_for_each::{TryForEach, TryForEachInit, TryForEachWith}, | try_for_each::{TryForEach, TryForEachInit, TryForEachWith}, | ||||
| try_reduce::TryReduce, | try_reduce::TryReduce, | ||||
| @@ -925,6 +927,70 @@ pub trait ParallelIterator<'a>: Sized + Send { | |||||
| TryFoldWith::new(self, init, operation) | 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 | /// Creates a fresh collection containing all the elements produced | ||||
| /// by this parallel iterator. | /// by this parallel iterator. | ||||
| /// | /// | ||||
| @@ -11,7 +11,9 @@ pub mod map; | |||||
| pub mod map_init; | pub mod map_init; | ||||
| pub mod map_with; | pub mod map_with; | ||||
| pub mod noop; | pub mod noop; | ||||
| pub mod product; | |||||
| pub mod reduce; | pub mod reduce; | ||||
| pub mod sum; | |||||
| pub mod try_fold; | pub mod try_fold; | ||||
| pub mod try_for_each; | pub mod try_for_each; | ||||
| pub mod try_reduce; | pub mod try_reduce; | ||||
| @@ -51,7 +53,6 @@ mod tests { | |||||
| move || j.fetch_add(1, Ordering::Relaxed), | move || j.fetch_add(1, Ordering::Relaxed), | ||||
| |init, item| -> Result<(), ()> { | |init, item| -> Result<(), ()> { | ||||
| println!("{:?} - {:?}", init, item); | println!("{:?} - {:?}", init, item); | ||||
| Ok(()) | 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() | |||||
| } | |||||