From d46867ca8448cf99233fa37c323366d38a5441f5 Mon Sep 17 00:00:00 2001 From: Bergmann89 Date: Thu, 5 Nov 2020 22:41:40 +0100 Subject: [PATCH] Implemented range iterator for all other numeric types --- asparit/src/core/iterator.rs | 4 +- asparit/src/inner/map.rs | 4 +- asparit/src/inner/map_init.rs | 4 +- asparit/src/inner/map_with.rs | 4 +- asparit/src/std/range.rs | 223 ++++++++++++++++++++++++++-------- 5 files changed, 181 insertions(+), 58 deletions(-) diff --git a/asparit/src/core/iterator.rs b/asparit/src/core/iterator.rs index 9a772b0..1dd2d8d 100644 --- a/asparit/src/core/iterator.rs +++ b/asparit/src/core/iterator.rs @@ -509,9 +509,9 @@ pub trait IndexedParallelIterator<'a>: ParallelIterator<'a> { fn drive_indexed(self, executor: E, consumer: C) -> E::Result where E: Executor<'a, D>, - C: IndexedConsumer, + C: IndexedConsumer + 'a, D: Send, - R: Reducer; + R: Reducer + Send; /// Internal method used to define the behavior of this parallel /// iterator. You should not need to call this directly. diff --git a/asparit/src/inner/map.rs b/asparit/src/inner/map.rs index 3f12892..73f3361 100644 --- a/asparit/src/inner/map.rs +++ b/asparit/src/inner/map.rs @@ -60,9 +60,9 @@ where fn drive_indexed(self, executor: E, consumer: C) -> E::Result where E: Executor<'a, D>, - C: IndexedConsumer, + C: IndexedConsumer + 'a, D: Send, - R: Reducer, + R: Reducer + Send, { let consumer = MapConsumer::new(consumer, self.operation); diff --git a/asparit/src/inner/map_init.rs b/asparit/src/inner/map_init.rs index f307c4d..59b16ec 100644 --- a/asparit/src/inner/map_init.rs +++ b/asparit/src/inner/map_init.rs @@ -70,9 +70,9 @@ where fn drive_indexed(self, executor: E, consumer: C) -> E::Result where E: Executor<'a, D>, - C: IndexedConsumer, + C: IndexedConsumer + 'a, D: Send, - R: Reducer, + R: Reducer + Send, { let consumer = MapInitConsumer::new(consumer, self.init, self.operation); diff --git a/asparit/src/inner/map_with.rs b/asparit/src/inner/map_with.rs index 5445c8f..864131c 100644 --- a/asparit/src/inner/map_with.rs +++ b/asparit/src/inner/map_with.rs @@ -68,9 +68,9 @@ where fn drive_indexed(self, executor: E, consumer: C) -> E::Result where E: Executor<'a, D>, - C: IndexedConsumer, + C: IndexedConsumer + 'a, D: Send, - R: Reducer, + R: Reducer + Send, { let consumer = MapWithConsumer::new(consumer, self.item, self.operation); diff --git a/asparit/src/std/range.rs b/asparit/src/std/range.rs index 696f9d4..8696b48 100644 --- a/asparit/src/std/range.rs +++ b/asparit/src/std/range.rs @@ -1,79 +1,202 @@ use std::ops::Range; use crate::{ - Consumer, Executor, ExecutorCallback, Folder, IntoParallelIterator, ParallelIterator, Producer, + Consumer, Executor, ExecutorCallback, IndexedConsumer, IndexedParallelIterator, + IndexedProducer, IndexedProducerCallback, IntoParallelIterator, ParallelIterator, Producer, ProducerCallback, Reducer, }; -pub struct Iter { - range: Range, +/// Parallel iterator over a range, implemented for all integer types. +/// +/// **Note:** The `zip` operation requires `IndexedParallelIterator` +/// which is not implemented for `u64`, `i64`, `u128`, or `i128`. +/// +/// ``` +/// use rayon::prelude::*; +/// +/// let p = (0..25usize) +/// .into_par_iter() +/// .zip(0..25usize) +/// .filter(|&(x, y)| x % 5 == 0 || y % 5 == 0) +/// .map(|(x, y)| x * y) +/// .sum::(); +/// +/// let s = (0..25usize) +/// .zip(0..25) +/// .filter(|&(x, y)| x % 5 == 0 || y % 5 == 0) +/// .map(|(x, y)| x * y) +/// .sum(); +/// +/// assert_eq!(p, s); +/// ``` +#[derive(Debug, Clone)] +pub struct Iter { + range: Range, } -struct IterProducer { - range: Range, +struct IterProducer { + range: Range, } -impl<'a> IntoParallelIterator<'a> for Range { - type Iter = Iter; - type Item = usize; +trait RangeLen { + fn length(&self) -> L; +} + +impl<'a, T> IntoParallelIterator<'a> for Range +where + Iter: ParallelIterator<'a>, +{ + type Item = as ParallelIterator<'a>>::Item; + type Iter = Iter; fn into_par_iter(self) -> Self::Iter { Iter { range: self } } } -impl<'a> ParallelIterator<'a> for Iter { - type Item = usize; - - fn drive(self, executor: E, consumer: C) -> E::Result - where - E: Executor<'a, D>, - C: Consumer + 'a, - D: Send, - R: Reducer + Send, - { - self.with_producer(ExecutorCallback::new(executor, consumer)) - } +impl IntoIterator for IterProducer +where + Range: Iterator, +{ + type Item = as Iterator>::Item; + type IntoIter = Range; - fn len_hint_opt(&self) -> Option { - Some(self.range.end - self.range.start) + fn into_iter(self) -> Self::IntoIter { + self.range } +} - fn with_producer(self, callback: CB) -> CB::Output - where - CB: ProducerCallback<'a, Self::Item>, - { - callback.callback(IterProducer { range: self.range }) - } +macro_rules! range_len_impl { + ( $t:ty, $len_t:ty ) => { + impl RangeLen<$len_t> for Range<$t> { + fn length(&self) -> $len_t { + if self.start < self.end { + self.end.wrapping_sub(self.start) as $len_t + } else { + 0 + } + } + } + }; } -impl Producer for IterProducer { - type Item = usize; - type IntoIter = Range; +macro_rules! unindexed_parallel_iterator_impl { + ( $t:ty, $len_t:ty ) => { + range_len_impl!($t, $len_t); + + impl<'a> ParallelIterator<'a> for Iter<$t> { + type Item = $t; + + fn drive(self, executor: E, consumer: C) -> E::Result + where + E: Executor<'a, D>, + C: Consumer + 'a, + D: Send, + R: Reducer + Send, + { + self.with_producer(ExecutorCallback::new(executor, consumer)) + } + + fn with_producer(self, callback: CB) -> CB::Output + where + CB: ProducerCallback<'a, Self::Item>, + { + callback.callback(IterProducer { range: self.range }) + } + + fn len_hint_opt(&self) -> Option { + Some(self.range.length() as usize) + } + } - fn into_iter(self) -> Self::IntoIter { - self.range - } + impl Producer for IterProducer<$t> { + type Item = $t; + type IntoIter = Range<$t>; + + fn into_iter(self) -> Self::IntoIter { + self.range + } - fn split(mut self) -> (Self, Option) { - let index = self.range.len() / 2; + fn split(mut self) -> (Self, Option) { + let index = self.range.length() / 2; - if index > 0 { - let mid = self.range.start.wrapping_add(index); - let right = mid..self.range.end; + if index > 0 { + let mid = self.range.start.wrapping_add(index as $t); + let right = mid..self.range.end; - self.range.end = mid; + self.range.end = mid; - (self, Some(IterProducer { range: right })) - } else { - (self, None) + (self, Some(IterProducer { range: right })) + } else { + (self, None) + } + } } - } + }; +} - fn fold_with(self, folder: F) -> F - where - F: Folder, - { - folder.consume_iter(self.range) - } +macro_rules! indexed_parallel_iterator_impl { + ( $t:ty, $len_t:ty ) => { + unindexed_parallel_iterator_impl!($t, $len_t); + + impl<'a> IndexedParallelIterator<'a> for Iter<$t> { + fn drive_indexed(self, executor: E, consumer: C) -> E::Result + where + E: Executor<'a, D>, + C: IndexedConsumer + 'a, + D: Send, + R: Reducer + Send, + { + self.with_producer_indexed(ExecutorCallback::new(executor, consumer)) + } + + fn with_producer_indexed(self, callback: CB) -> CB::Output + where + CB: IndexedProducerCallback<'a, Self::Item>, + { + callback.callback(IterProducer { range: self.range }) + } + + fn len_hint(&self) -> usize { + self.range.length() as usize + } + } + + impl IndexedProducer for IterProducer<$t> { + type Item = $t; + type IntoIter = Range<$t>; + + fn into_iter(self) -> Self::IntoIter { + self.range + } + + fn len(&self) -> usize { + self.range.length() as usize + } + + fn split_at(self, index: usize) -> (Self, Self) { + assert!(index <= self.range.length() as usize); + + let mid = self.range.start.wrapping_add(index as $t); + let left = self.range.start..mid; + let right = mid..self.range.end; + + (IterProducer { range: left }, IterProducer { range: right }) + } + } + }; } + +indexed_parallel_iterator_impl!(u8, u8); +indexed_parallel_iterator_impl!(i8, u8); +indexed_parallel_iterator_impl!(u16, u16); +indexed_parallel_iterator_impl!(i16, u16); +indexed_parallel_iterator_impl!(u32, u32); +indexed_parallel_iterator_impl!(i32, u32); +indexed_parallel_iterator_impl!(usize, usize); +indexed_parallel_iterator_impl!(isize, usize); + +unindexed_parallel_iterator_impl!(u64, u64); +unindexed_parallel_iterator_impl!(i64, u64); +unindexed_parallel_iterator_impl!(u128, u128); +unindexed_parallel_iterator_impl!(i128, u128);