1use rayon::iter::plumbing::bridge;
2use rayon::iter::plumbing::bridge_unindexed;
3use rayon::iter::plumbing::Folder;
4use rayon::iter::plumbing::Producer;
5use rayon::iter::plumbing::ProducerCallback;
6use rayon::iter::plumbing::UnindexedProducer;
7use rayon::iter::plumbing::{Consumer, UnindexedConsumer};
8use rayon::iter::IndexedParallelIterator;
9use rayon::iter::ParallelIterator;
10use rayon::prelude::IntoParallelIterator;
11
12use crate::iter::AxisChunksIter;
13use crate::iter::AxisChunksIterMut;
14use crate::iter::AxisIter;
15use crate::iter::AxisIterMut;
16use crate::split_at::SplitPreference;
17use crate::Dimension;
18use crate::{ArrayView, ArrayViewMut};
19
20#[derive(Copy, Clone, Debug)]
22pub struct Parallel<I>
23{
24 iter: I,
25 min_len: usize,
26}
27
28const DEFAULT_MIN_LEN: usize = 1;
29
30#[derive(Copy, Clone, Debug)]
32struct ParallelProducer<I>(I, usize);
33
34macro_rules! par_iter_wrapper {
35 ($iter_name:ident, [$($thread_bounds:tt)*]) => {
37 impl<'a, A, D> IntoParallelIterator for $iter_name<'a, A, D>
39 where D: Dimension,
40 A: $($thread_bounds)*,
41 {
42 type Item = <Self as Iterator>::Item;
43 type Iter = Parallel<Self>;
44 fn into_par_iter(self) -> Self::Iter {
45 Parallel {
46 iter: self,
47 min_len: DEFAULT_MIN_LEN,
48 }
49 }
50 }
51
52 impl<'a, A, D> ParallelIterator for Parallel<$iter_name<'a, A, D>>
53 where D: Dimension,
54 A: $($thread_bounds)*,
55 {
56 type Item = <$iter_name<'a, A, D> as Iterator>::Item;
57 fn drive_unindexed<C>(self, consumer: C) -> C::Result
58 where C: UnindexedConsumer<Self::Item>
59 {
60 bridge(self, consumer)
61 }
62
63 fn opt_len(&self) -> Option<usize> {
64 Some(self.iter.len())
65 }
66 }
67
68 impl<'a, A, D> IndexedParallelIterator for Parallel<$iter_name<'a, A, D>>
69 where D: Dimension,
70 A: $($thread_bounds)*,
71 {
72 fn with_producer<Cb>(self, callback: Cb) -> Cb::Output
73 where Cb: ProducerCallback<Self::Item>
74 {
75 callback.callback(ParallelProducer(self.iter, self.min_len))
76 }
77
78 fn len(&self) -> usize {
79 ExactSizeIterator::len(&self.iter)
80 }
81
82 fn drive<C>(self, consumer: C) -> C::Result
83 where C: Consumer<Self::Item>
84 {
85 bridge(self, consumer)
86 }
87 }
88
89 impl<'a, A, D> IntoIterator for ParallelProducer<$iter_name<'a, A, D>>
90 where D: Dimension,
91 {
92 type IntoIter = $iter_name<'a, A, D>;
93 type Item = <Self::IntoIter as Iterator>::Item;
94
95 fn into_iter(self) -> Self::IntoIter {
96 self.0
97 }
98 }
99
100 impl<'a, A, D> Producer for ParallelProducer<$iter_name<'a, A, D>>
102 where D: Dimension,
103 A: $($thread_bounds)*,
104 {
105 type IntoIter = $iter_name<'a, A, D>;
106 type Item = <Self::IntoIter as Iterator>::Item;
107
108 fn into_iter(self) -> Self::IntoIter {
109 self.0
110 }
111
112 fn split_at(self, i: usize) -> (Self, Self) {
113 let (a, b) = self.0.split_at(i);
114 (ParallelProducer(a, self.1), ParallelProducer(b, self.1))
115 }
116 }
117
118 };
119}
120
121par_iter_wrapper!(AxisIter, [Sync]);
122par_iter_wrapper!(AxisIterMut, [Send + Sync]);
123par_iter_wrapper!(AxisChunksIter, [Sync]);
124par_iter_wrapper!(AxisChunksIterMut, [Send + Sync]);
125
126macro_rules! par_iter_view_wrapper {
127 ($view_name:ident, [$($thread_bounds:tt)*]) => {
129 impl<'a, A, D> IntoParallelIterator for $view_name<'a, A, D>
131 where D: Dimension,
132 A: $($thread_bounds)*,
133 {
134 type Item = <Self as IntoIterator>::Item;
135 type Iter = Parallel<Self>;
136 fn into_par_iter(self) -> Self::Iter {
137 Parallel {
138 iter: self,
139 min_len: DEFAULT_MIN_LEN,
140 }
141 }
142 }
143
144 impl<'a, A, D> ParallelIterator for Parallel<$view_name<'a, A, D>>
145 where D: Dimension,
146 A: $($thread_bounds)*,
147 {
148 type Item = <$view_name<'a, A, D> as IntoIterator>::Item;
149 fn drive_unindexed<C>(self, consumer: C) -> C::Result
150 where C: UnindexedConsumer<Self::Item>
151 {
152 bridge_unindexed(ParallelProducer(self.iter, self.min_len), consumer)
153 }
154
155 fn opt_len(&self) -> Option<usize> {
156 None
157 }
158 }
159
160 impl<'a, A, D> Parallel<$view_name<'a, A, D>>
161 where D: Dimension,
162 A: $($thread_bounds)*,
163 {
164 pub fn with_min_len(self, min_len: usize) -> Self {
170 assert_ne!(min_len, 0, "Minimum number of elements must at least be one to avoid splitting off empty tasks.");
171
172 Self {
173 min_len,
174 ..self
175 }
176 }
177 }
178
179 impl<'a, A, D> UnindexedProducer for ParallelProducer<$view_name<'a, A, D>>
180 where D: Dimension,
181 A: $($thread_bounds)*,
182 {
183 type Item = <$view_name<'a, A, D> as IntoIterator>::Item;
184 fn split(self) -> (Self, Option<Self>) {
185 if self.0.len() <= self.1 {
186 return (self, None)
187 }
188 let array = self.0;
189 let max_axis = array.max_stride_axis();
190 let mid = array.len_of(max_axis) / 2;
191 let (a, b) = array.split_at(max_axis, mid);
192 (ParallelProducer(a, self.1), Some(ParallelProducer(b, self.1)))
193 }
194
195 fn fold_with<F>(self, folder: F) -> F
196 where F: Folder<Self::Item>,
197 {
198 Zip::from(self.0).fold_while(folder, |mut folder, elt| {
199 folder = folder.consume(elt);
200 if folder.full() {
201 FoldWhile::Done(folder)
202 } else {
203 FoldWhile::Continue(folder)
204 }
205 }).into_inner()
206 }
207 }
208
209 impl<'a, A, D> IntoIterator for ParallelProducer<$view_name<'a, A, D>>
210 where D: Dimension,
211 A: $($thread_bounds)*,
212 {
213 type Item = <$view_name<'a, A, D> as IntoIterator>::Item;
214 type IntoIter = <$view_name<'a, A, D> as IntoIterator>::IntoIter;
215 fn into_iter(self) -> Self::IntoIter {
216 self.0.into_iter()
217 }
218 }
219
220 };
221}
222
223par_iter_view_wrapper!(ArrayView, [Sync]);
224par_iter_view_wrapper!(ArrayViewMut, [Sync + Send]);
225
226use crate::{FoldWhile, NdProducer, Zip};
227
228macro_rules! zip_impl {
229 ($([$($p:ident)*],)+) => {
230 $(
231 #[allow(non_snake_case)]
233 impl<D, $($p),*> IntoParallelIterator for Zip<($($p,)*), D>
234 where $($p::Item : Send , )*
235 $($p : Send , )*
236 D: Dimension,
237 $($p: NdProducer<Dim=D> ,)*
238 {
239 type Item = ($($p::Item ,)*);
240 type Iter = Parallel<Self>;
241 fn into_par_iter(self) -> Self::Iter {
242 Parallel {
243 iter: self,
244 min_len: DEFAULT_MIN_LEN,
245 }
246 }
247 }
248
249 #[allow(non_snake_case)]
250 impl<D, $($p),*> ParallelIterator for Parallel<Zip<($($p,)*), D>>
251 where $($p::Item : Send , )*
252 $($p : Send , )*
253 D: Dimension,
254 $($p: NdProducer<Dim=D> ,)*
255 {
256 type Item = ($($p::Item ,)*);
257
258 fn drive_unindexed<Cons>(self, consumer: Cons) -> Cons::Result
259 where Cons: UnindexedConsumer<Self::Item>
260 {
261 bridge_unindexed(ParallelProducer(self.iter, self.min_len), consumer)
262 }
263
264 fn opt_len(&self) -> Option<usize> {
265 None
266 }
267 }
268
269 #[allow(non_snake_case)]
270 impl<D, $($p),*> UnindexedProducer for ParallelProducer<Zip<($($p,)*), D>>
271 where $($p : Send , )*
272 $($p::Item : Send , )*
273 D: Dimension,
274 $($p: NdProducer<Dim=D> ,)*
275 {
276 type Item = ($($p::Item ,)*);
277
278 fn split(self) -> (Self, Option<Self>) {
279 if self.0.size() <= self.1 {
280 return (self, None)
281 }
282 let (a, b) = self.0.split();
283 (ParallelProducer(a, self.1), Some(ParallelProducer(b, self.1)))
284 }
285
286 fn fold_with<Fold>(self, folder: Fold) -> Fold
287 where Fold: Folder<Self::Item>,
288 {
289 self.0.fold_while(folder, |mut folder, $($p),*| {
290 folder = folder.consume(($($p ,)*));
291 if folder.full() {
292 FoldWhile::Done(folder)
293 } else {
294 FoldWhile::Continue(folder)
295 }
296 }).into_inner()
297 }
298 }
299 )+
300 };
301}
302
303zip_impl! {
304 [P1],
305 [P1 P2],
306 [P1 P2 P3],
307 [P1 P2 P3 P4],
308 [P1 P2 P3 P4 P5],
309 [P1 P2 P3 P4 P5 P6],
310}
311
312impl<D, Parts> Parallel<Zip<Parts, D>>
313where D: Dimension
314{
315 pub fn with_min_len(self, min_len: usize) -> Self
321 {
322 assert_ne!(min_len, 0, "Minimum number of elements must at least be one to avoid splitting off empty tasks.");
323
324 Self { min_len, ..self }
325 }
326}
327
328pub(crate) struct ParallelSplits<P>
331{
332 pub(crate) iter: P,
333 pub(crate) max_splits: usize,
334}
335
336impl<P> ParallelIterator for ParallelSplits<P>
337where P: SplitPreference + Send
338{
339 type Item = P;
340
341 fn drive_unindexed<C>(self, consumer: C) -> C::Result
342 where C: UnindexedConsumer<Self::Item>
343 {
344 bridge_unindexed(self, consumer)
345 }
346
347 fn opt_len(&self) -> Option<usize>
348 {
349 None
350 }
351}
352
353impl<P> UnindexedProducer for ParallelSplits<P>
354where P: SplitPreference + Send
355{
356 type Item = P;
357
358 fn split(self) -> (Self, Option<Self>)
359 {
360 if self.max_splits == 0 || !self.iter.can_split() {
361 return (self, None);
362 }
363 let (a, b) = self.iter.split();
364 (
365 ParallelSplits {
366 iter: a,
367 max_splits: self.max_splits - 1,
368 },
369 Some(ParallelSplits {
370 iter: b,
371 max_splits: self.max_splits - 1,
372 }),
373 )
374 }
375
376 fn fold_with<Fold>(self, folder: Fold) -> Fold
377 where Fold: Folder<Self::Item>
378 {
379 folder.consume(self.iter)
380 }
381}