| @@ -23,6 +23,8 @@ where | |||||
| C: Consumer<P::Item, Result = T1, Reducer = R> + 'a, | C: Consumer<P::Item, Result = T1, Reducer = R> + 'a, | ||||
| R: Reducer<T1> + Send + 'a; | R: Reducer<T1> + Send + 'a; | ||||
| fn ready(self, value: T1) -> Self::Result; | |||||
| fn split(self) -> (Self, Self); | fn split(self) -> (Self, Self); | ||||
| fn join<R>(left: Self::Result, right: Self::Result, reducer: R) -> Self::Result | fn join<R>(left: Self::Result, right: Self::Result, reducer: R) -> Self::Result | ||||
| @@ -10,6 +10,7 @@ use crate::{ | |||||
| chain::Chain, | chain::Chain, | ||||
| chunks::Chunks, | chunks::Chunks, | ||||
| cloned::Cloned, | cloned::Cloned, | ||||
| cmp::{Cmp, Compare, Equal, PartialCmp}, | |||||
| collect::Collect, | collect::Collect, | ||||
| copied::Copied, | copied::Copied, | ||||
| count::Count, | count::Count, | ||||
| @@ -1916,6 +1917,130 @@ pub trait IndexedParallelIterator<'a>: ParallelIterator<'a> { | |||||
| Chunks::new(self, chunk_size) | Chunks::new(self, chunk_size) | ||||
| } | } | ||||
| /// Lexicographically compares the elements of this `ParallelIterator` with those of | |||||
| /// another. | |||||
| /// | |||||
| /// # Examples | |||||
| /// | |||||
| /// ``` | |||||
| /// use rayon::prelude::*; | |||||
| /// use std::cmp::Ordering::*; | |||||
| /// | |||||
| /// let x = vec![1, 2, 3]; | |||||
| /// assert_eq!(x.par_iter().cmp(&vec![1, 3, 0]), Less); | |||||
| /// assert_eq!(x.par_iter().cmp(&vec![1, 2, 3]), Equal); | |||||
| /// assert_eq!(x.par_iter().cmp(&vec![1, 2]), Greater); | |||||
| /// ``` | |||||
| fn cmp<X>(self, other: X) -> Cmp<Self, X::Iter> | |||||
| where | |||||
| X: IntoParallelIterator<'a, Item = Self::Item>, | |||||
| X::Iter: IndexedParallelIterator<'a>, | |||||
| Self::Item: Ord, | |||||
| { | |||||
| Cmp::new(self, other.into_par_iter()) | |||||
| } | |||||
| /// Lexicographically compares the elements of this `ParallelIterator` with those of | |||||
| /// another. | |||||
| /// | |||||
| /// # Examples | |||||
| /// | |||||
| /// ``` | |||||
| /// use rayon::prelude::*; | |||||
| /// use std::cmp::Ordering::*; | |||||
| /// use std::f64::NAN; | |||||
| /// | |||||
| /// let x = vec![1.0, 2.0, 3.0]; | |||||
| /// assert_eq!(x.par_iter().partial_cmp(&vec![1.0, 3.0, 0.0]), Some(Less)); | |||||
| /// assert_eq!(x.par_iter().partial_cmp(&vec![1.0, 2.0, 3.0]), Some(Equal)); | |||||
| /// assert_eq!(x.par_iter().partial_cmp(&vec![1.0, 2.0]), Some(Greater)); | |||||
| /// assert_eq!(x.par_iter().partial_cmp(&vec![1.0, NAN]), None); | |||||
| /// ``` | |||||
| fn partial_cmp<X>(self, other: X) -> PartialCmp<Self, X::Iter> | |||||
| where | |||||
| X: IntoParallelIterator<'a>, | |||||
| X::Iter: IndexedParallelIterator<'a>, | |||||
| Self::Item: PartialOrd<X::Item>, | |||||
| { | |||||
| PartialCmp::new(self, other.into_par_iter()) | |||||
| } | |||||
| /// Determines if the elements of this `ParallelIterator` | |||||
| /// are equal to those of another | |||||
| fn eq<X>(self, other: X) -> Equal<Self, X::Iter> | |||||
| where | |||||
| X: IntoParallelIterator<'a>, | |||||
| X::Iter: IndexedParallelIterator<'a>, | |||||
| Self::Item: PartialEq<X::Item>, | |||||
| { | |||||
| Equal::new(self, other.into_par_iter(), true) | |||||
| } | |||||
| /// Determines if the elements of this `ParallelIterator` | |||||
| /// are unequal to those of another | |||||
| fn ne<X>(self, other: X) -> Equal<Self, X::Iter> | |||||
| where | |||||
| X: IntoParallelIterator<'a>, | |||||
| X::Iter: IndexedParallelIterator<'a>, | |||||
| Self::Item: PartialEq<X::Item>, | |||||
| { | |||||
| Equal::new(self, other.into_par_iter(), false) | |||||
| } | |||||
| /// Determines if the elements of this `ParallelIterator` | |||||
| /// are lexicographically less than those of another. | |||||
| fn lt<X>(self, other: X) -> Compare<Self, X::Iter> | |||||
| where | |||||
| X: IntoParallelIterator<'a>, | |||||
| X::Iter: IndexedParallelIterator<'a>, | |||||
| Self::Item: PartialOrd<X::Item>, | |||||
| { | |||||
| Compare::new(self, other.into_par_iter(), Ordering::Less, None) | |||||
| } | |||||
| /// Determines if the elements of this `ParallelIterator` | |||||
| /// are less or equal to those of another. | |||||
| fn le<X>(self, other: X) -> Compare<Self, X::Iter> | |||||
| where | |||||
| X: IntoParallelIterator<'a>, | |||||
| X::Iter: IndexedParallelIterator<'a>, | |||||
| Self::Item: PartialOrd<X::Item>, | |||||
| { | |||||
| Compare::new( | |||||
| self, | |||||
| other.into_par_iter(), | |||||
| Ordering::Less, | |||||
| Some(Ordering::Equal), | |||||
| ) | |||||
| } | |||||
| /// Determines if the elements of this `ParallelIterator` | |||||
| /// are lexicographically greater than those of another. | |||||
| fn gt<X>(self, other: X) -> Compare<Self, X::Iter> | |||||
| where | |||||
| X: IntoParallelIterator<'a>, | |||||
| X::Iter: IndexedParallelIterator<'a>, | |||||
| Self::Item: PartialOrd<X::Item>, | |||||
| { | |||||
| Compare::new(self, other.into_par_iter(), Ordering::Greater, None) | |||||
| } | |||||
| /// Determines if the elements of this `ParallelIterator` | |||||
| /// are less or equal to those of another. | |||||
| fn ge<X>(self, other: X) -> Compare<Self, X::Iter> | |||||
| where | |||||
| X: IntoParallelIterator<'a>, | |||||
| X::Iter: IndexedParallelIterator<'a>, | |||||
| Self::Item: PartialOrd<X::Item>, | |||||
| { | |||||
| Compare::new( | |||||
| self, | |||||
| other.into_par_iter(), | |||||
| Ordering::Greater, | |||||
| Some(Ordering::Equal), | |||||
| ) | |||||
| } | |||||
| /// Creates an iterator that yields the first `n` elements. | /// Creates an iterator that yields the first `n` elements. | ||||
| /// | /// | ||||
| /// # Examples | /// # Examples | ||||
| @@ -38,6 +38,10 @@ where | |||||
| } | } | ||||
| } | } | ||||
| fn ready(self, value: T1) -> Self::Result { | |||||
| value | |||||
| } | |||||
| fn split(self) -> (Self, Self) { | fn split(self) -> (Self, Self) { | ||||
| (Self, Self) | (Self, Self) | ||||
| } | } | ||||
| @@ -62,6 +62,10 @@ where | |||||
| exec_indexed(splitter, producer, consumer) | exec_indexed(splitter, producer, consumer) | ||||
| } | } | ||||
| fn ready(self, value: T1) -> Self::Result { | |||||
| async move { value }.boxed() | |||||
| } | |||||
| fn split(self) -> (Self, Self) { | fn split(self) -> (Self, Self) { | ||||
| let mut left = self; | let mut left = self; | ||||
| let right = Self { | let right = Self { | ||||
| @@ -0,0 +1,187 @@ | |||||
| use std::cmp::{Ord, Ordering, PartialEq, PartialOrd}; | |||||
| use crate::{Driver, Executor, IndexedParallelIterator, ParallelIterator, WithIndexedProducer}; | |||||
| /* Cmp */ | |||||
| pub struct Cmp<XA, XB> { | |||||
| iterator_a: XA, | |||||
| iterator_b: XB, | |||||
| } | |||||
| impl<XA, XB> Cmp<XA, XB> { | |||||
| pub fn new(iterator_a: XA, iterator_b: XB) -> Self { | |||||
| Self { | |||||
| iterator_a, | |||||
| iterator_b, | |||||
| } | |||||
| } | |||||
| } | |||||
| impl<'a, XA, XB, I> Driver<'a, Ordering, Option<Ordering>> for Cmp<XA, XB> | |||||
| where | |||||
| XA: IndexedParallelIterator<'a, Item = I> + WithIndexedProducer<'a, Item = I>, | |||||
| XB: IndexedParallelIterator<'a, Item = I> + WithIndexedProducer<'a, Item = I>, | |||||
| I: Ord + Send + 'a, | |||||
| { | |||||
| fn exec_with<E>(self, executor: E) -> E::Result | |||||
| where | |||||
| E: Executor<'a, Ordering, Option<Ordering>>, | |||||
| { | |||||
| let Self { | |||||
| iterator_a, | |||||
| iterator_b, | |||||
| } = self; | |||||
| let len_a = iterator_a.len_hint(); | |||||
| let len_b = iterator_b.len_hint(); | |||||
| let ord_len = len_a.cmp(&len_b); | |||||
| let executor = executor.into_inner(); | |||||
| let inner = iterator_a | |||||
| .zip(iterator_b) | |||||
| .map(|(a, b)| Ord::cmp(&a, &b)) | |||||
| .find_first(|ord| ord != &Ordering::Equal) | |||||
| .exec_with(executor); | |||||
| E::map(inner, move |inner| inner.unwrap_or(ord_len)) | |||||
| } | |||||
| } | |||||
| /* PartialCmp */ | |||||
| pub struct PartialCmp<XA, XB> { | |||||
| iterator_a: XA, | |||||
| iterator_b: XB, | |||||
| } | |||||
| impl<XA, XB> PartialCmp<XA, XB> { | |||||
| pub fn new(iterator_a: XA, iterator_b: XB) -> Self { | |||||
| Self { | |||||
| iterator_a, | |||||
| iterator_b, | |||||
| } | |||||
| } | |||||
| } | |||||
| impl<'a, XA, XB, I> Driver<'a, Option<Ordering>, Option<Option<Ordering>>> for PartialCmp<XA, XB> | |||||
| where | |||||
| XA: IndexedParallelIterator<'a, Item = I> + WithIndexedProducer<'a, Item = I>, | |||||
| XB: IndexedParallelIterator<'a, Item = I> + WithIndexedProducer<'a, Item = I>, | |||||
| I: PartialOrd + Send + 'a, | |||||
| { | |||||
| fn exec_with<E>(self, executor: E) -> E::Result | |||||
| where | |||||
| E: Executor<'a, Option<Ordering>, Option<Option<Ordering>>>, | |||||
| { | |||||
| let Self { | |||||
| iterator_a, | |||||
| iterator_b, | |||||
| } = self; | |||||
| let len_a = iterator_a.len_hint(); | |||||
| let len_b = iterator_b.len_hint(); | |||||
| let ord_len = len_a.cmp(&len_b); | |||||
| let executor = executor.into_inner(); | |||||
| let inner = iterator_a | |||||
| .zip(iterator_b) | |||||
| .map(|(a, b)| PartialOrd::partial_cmp(&a, &b)) | |||||
| .find_first(|ord| ord != &Some(Ordering::Equal)) | |||||
| .exec_with(executor); | |||||
| E::map(inner, move |inner| inner.unwrap_or(Some(ord_len))) | |||||
| } | |||||
| } | |||||
| /* Equal */ | |||||
| pub struct Equal<XA, XB> { | |||||
| iterator_a: XA, | |||||
| iterator_b: XB, | |||||
| expected: bool, | |||||
| } | |||||
| impl<XA, XB> Equal<XA, XB> { | |||||
| pub fn new(iterator_a: XA, iterator_b: XB, expected: bool) -> Self { | |||||
| Self { | |||||
| iterator_a, | |||||
| iterator_b, | |||||
| expected, | |||||
| } | |||||
| } | |||||
| } | |||||
| impl<'a, XA, XB, I> Driver<'a, bool, Option<bool>> for Equal<XA, XB> | |||||
| where | |||||
| XA: IndexedParallelIterator<'a, Item = I> + WithIndexedProducer<'a, Item = I>, | |||||
| XB: IndexedParallelIterator<'a, Item = I> + WithIndexedProducer<'a, Item = I>, | |||||
| I: PartialEq + Send + 'a, | |||||
| { | |||||
| fn exec_with<E>(self, executor: E) -> E::Result | |||||
| where | |||||
| E: Executor<'a, bool, Option<bool>>, | |||||
| { | |||||
| let Self { | |||||
| iterator_a, | |||||
| iterator_b, | |||||
| expected, | |||||
| } = self; | |||||
| let len_a = iterator_a.len_hint(); | |||||
| let len_b = iterator_b.len_hint(); | |||||
| if (len_a == len_b) ^ expected { | |||||
| return executor.ready(false); | |||||
| } | |||||
| iterator_a | |||||
| .zip(iterator_b) | |||||
| .all(move |(x, y)| dbg!(PartialEq::eq(&x, &y)) == expected) | |||||
| .exec_with(executor) | |||||
| } | |||||
| } | |||||
| /* Compare */ | |||||
| pub struct Compare<XA, XB> { | |||||
| iterator_a: XA, | |||||
| iterator_b: XB, | |||||
| ord: Ordering, | |||||
| ord_opt: Option<Ordering>, | |||||
| } | |||||
| impl<XA, XB> Compare<XA, XB> { | |||||
| pub fn new(iterator_a: XA, iterator_b: XB, ord: Ordering, ord_opt: Option<Ordering>) -> Self { | |||||
| Self { | |||||
| iterator_a, | |||||
| iterator_b, | |||||
| ord, | |||||
| ord_opt, | |||||
| } | |||||
| } | |||||
| } | |||||
| impl<'a, XA, XB, I> Driver<'a, bool, Option<Ordering>, Option<Option<Ordering>>> for Compare<XA, XB> | |||||
| where | |||||
| XA: IndexedParallelIterator<'a, Item = I> + WithIndexedProducer<'a, Item = I>, | |||||
| XB: IndexedParallelIterator<'a, Item = I> + WithIndexedProducer<'a, Item = I>, | |||||
| I: PartialOrd + Send + 'a, | |||||
| { | |||||
| fn exec_with<E>(self, executor: E) -> E::Result | |||||
| where | |||||
| E: Executor<'a, bool, Option<Ordering>, Option<Option<Ordering>>>, | |||||
| { | |||||
| let Self { | |||||
| iterator_a, | |||||
| iterator_b, | |||||
| ord, | |||||
| ord_opt, | |||||
| } = self; | |||||
| let executor = executor.into_inner(); | |||||
| let inner = PartialCmp::new(iterator_a, iterator_b).exec_with(executor); | |||||
| E::map(inner, move |inner| inner == Some(ord) || inner == ord_opt) | |||||
| } | |||||
| } | |||||
| @@ -160,7 +160,7 @@ where | |||||
| ) | ) | ||||
| .exec_with(executor); | .exec_with(executor); | ||||
| E::map(ret, |x| x.is_some()) | |||||
| E::map(ret, |x| x.is_none()) | |||||
| } | } | ||||
| } | } | ||||
| @@ -265,8 +265,8 @@ where | |||||
| loop { | loop { | ||||
| let boundary = match self.find_match { | let boundary = match self.find_match { | ||||
| FindMatch::Any if found > 0 => return self, | FindMatch::Any if found > 0 => return self, | ||||
| FindMatch::First if found < self.lower_bound => return self, | |||||
| FindMatch::Last if found > self.upper_bound => return self, | |||||
| FindMatch::First if found != 0 && found < self.lower_bound => return self, | |||||
| FindMatch::Last if found != 0 && found > self.upper_bound => return self, | |||||
| FindMatch::Any => self.lower_bound, | FindMatch::Any => self.lower_bound, | ||||
| FindMatch::First => self.lower_bound, | FindMatch::First => self.lower_bound, | ||||
| FindMatch::Last => self.upper_bound, | FindMatch::Last => self.upper_bound, | ||||
| @@ -1,6 +1,7 @@ | |||||
| pub mod chain; | pub mod chain; | ||||
| pub mod chunks; | pub mod chunks; | ||||
| pub mod cloned; | pub mod cloned; | ||||
| pub mod cmp; | |||||
| pub mod collect; | pub mod collect; | ||||
| pub mod copied; | pub mod copied; | ||||
| pub mod count; | pub mod count; | ||||
| @@ -40,15 +41,14 @@ mod tests { | |||||
| #[tokio::test(flavor = "multi_thread")] | #[tokio::test(flavor = "multi_thread")] | ||||
| async fn test_for_each() { | async fn test_for_each() { | ||||
| vec![0usize, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |||||
| let x = vec![0usize, 1, 2, 3, 4] | |||||
| .into_par_iter() | .into_par_iter() | ||||
| .with_splits(1) | .with_splits(1) | ||||
| .chunks(4) | |||||
| .for_each(|x| { | |||||
| dbg!(x); | |||||
| }) | |||||
| .lt(vec![0usize, 1, 2, 3, 4, 5]) | |||||
| .exec() | .exec() | ||||
| .await; | .await; | ||||
| dbg!(x); | |||||
| } | } | ||||
| #[tokio::test] | #[tokio::test] | ||||