| @@ -23,6 +23,8 @@ where | |||
| C: Consumer<P::Item, Result = T1, Reducer = R> + 'a, | |||
| R: Reducer<T1> + Send + 'a; | |||
| fn ready(self, value: T1) -> Self::Result; | |||
| fn split(self) -> (Self, Self); | |||
| fn join<R>(left: Self::Result, right: Self::Result, reducer: R) -> Self::Result | |||
| @@ -10,6 +10,7 @@ use crate::{ | |||
| chain::Chain, | |||
| chunks::Chunks, | |||
| cloned::Cloned, | |||
| cmp::{Cmp, Compare, Equal, PartialCmp}, | |||
| collect::Collect, | |||
| copied::Copied, | |||
| count::Count, | |||
| @@ -1916,6 +1917,130 @@ pub trait IndexedParallelIterator<'a>: ParallelIterator<'a> { | |||
| 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. | |||
| /// | |||
| /// # Examples | |||
| @@ -38,6 +38,10 @@ where | |||
| } | |||
| } | |||
| fn ready(self, value: T1) -> Self::Result { | |||
| value | |||
| } | |||
| fn split(self) -> (Self, Self) { | |||
| (Self, Self) | |||
| } | |||
| @@ -62,6 +62,10 @@ where | |||
| exec_indexed(splitter, producer, consumer) | |||
| } | |||
| fn ready(self, value: T1) -> Self::Result { | |||
| async move { value }.boxed() | |||
| } | |||
| fn split(self) -> (Self, Self) { | |||
| let mut left = 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); | |||
| E::map(ret, |x| x.is_some()) | |||
| E::map(ret, |x| x.is_none()) | |||
| } | |||
| } | |||
| @@ -265,8 +265,8 @@ where | |||
| loop { | |||
| let boundary = match self.find_match { | |||
| 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::First => self.lower_bound, | |||
| FindMatch::Last => self.upper_bound, | |||
| @@ -1,6 +1,7 @@ | |||
| pub mod chain; | |||
| pub mod chunks; | |||
| pub mod cloned; | |||
| pub mod cmp; | |||
| pub mod collect; | |||
| pub mod copied; | |||
| pub mod count; | |||
| @@ -40,15 +41,14 @@ mod tests { | |||
| #[tokio::test(flavor = "multi_thread")] | |||
| 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() | |||
| .with_splits(1) | |||
| .chunks(4) | |||
| .for_each(|x| { | |||
| dbg!(x); | |||
| }) | |||
| .lt(vec![0usize, 1, 2, 3, 4, 5]) | |||
| .exec() | |||
| .await; | |||
| dbg!(x); | |||
| } | |||
| #[tokio::test] | |||