1 use super::plumbing::*;
2 use super::*;
3 
4 /// `MultiZip` is an iterator that zips up a tuple of parallel iterators to
5 /// produce tuples of their items.
6 ///
7 /// It is created by calling `into_par_iter()` on a tuple of types that
8 /// implement `IntoParallelIterator`, or `par_iter()`/`par_iter_mut()` with
9 /// types that are iterable by reference.
10 ///
11 /// The implementation currently support tuples up to length 12.
12 ///
13 /// # Examples
14 ///
15 /// ```
16 /// use rayon::prelude::*;
17 ///
18 /// // This will iterate `r` by mutable reference, like `par_iter_mut()`, while
19 /// // ranges are all iterated by value like `into_par_iter()`.
20 /// // Note that the zipped iterator is only as long as the shortest input.
21 /// let mut r = vec![0; 3];
22 /// (&mut r, 1..10, 10..100, 100..1000).into_par_iter()
23 ///     .for_each(|(r, x, y, z)| *r = x * y + z);
24 ///
25 /// assert_eq!(&r, &[1 * 10 + 100, 2 * 11 + 101, 3 * 12 + 102]);
26 /// ```
27 ///
28 /// For a group that should all be iterated by reference, you can use a tuple reference.
29 ///
30 /// ```
31 /// use rayon::prelude::*;
32 ///
33 /// let xs: Vec<_> = (1..10).collect();
34 /// let ys: Vec<_> = (10..100).collect();
35 /// let zs: Vec<_> = (100..1000).collect();
36 ///
37 /// // Reference each input separately with `IntoParallelIterator`:
38 /// let r1: Vec<_> = (&xs, &ys, &zs).into_par_iter()
39 ///     .map(|(x, y, z)| x * y + z)
40 ///     .collect();
41 ///
42 /// // Reference them all together with `IntoParallelRefIterator`:
43 /// let r2: Vec<_> = (xs, ys, zs).par_iter()
44 ///     .map(|(x, y, z)| x * y + z)
45 ///     .collect();
46 ///
47 /// assert_eq!(r1, r2);
48 /// ```
49 ///
50 /// Mutable references to a tuple will work similarly.
51 ///
52 /// ```
53 /// use rayon::prelude::*;
54 ///
55 /// let mut xs: Vec<_> = (1..4).collect();
56 /// let mut ys: Vec<_> = (-4..-1).collect();
57 /// let mut zs = vec![0; 3];
58 ///
59 /// // Mutably reference each input separately with `IntoParallelIterator`:
60 /// (&mut xs, &mut ys, &mut zs).into_par_iter().for_each(|(x, y, z)| {
61 ///     *z += *x + *y;
62 ///     std::mem::swap(x, y);
63 /// });
64 ///
65 /// assert_eq!(xs, (vec![-4, -3, -2]));
66 /// assert_eq!(ys, (vec![1, 2, 3]));
67 /// assert_eq!(zs, (vec![-3, -1, 1]));
68 ///
69 /// // Mutably reference them all together with `IntoParallelRefMutIterator`:
70 /// let mut tuple = (xs, ys, zs);
71 /// tuple.par_iter_mut().for_each(|(x, y, z)| {
72 ///     *z += *x + *y;
73 ///     std::mem::swap(x, y);
74 /// });
75 ///
76 /// assert_eq!(tuple, (vec![1, 2, 3], vec![-4, -3, -2], vec![-6, -2, 2]));
77 /// ```
78 #[derive(Debug, Clone)]
79 pub struct MultiZip<T> {
80     tuple: T,
81 }
82 
83 // These macros greedily consume 4 or 2 items first to achieve log2 nesting depth.
84 // For example, 5 => 4,1 => (2,2),1.
85 //
86 // The tuples go up to 12, so we might want to greedily consume 8 too, but
87 // the depth works out the same if we let that expand on the right:
88 //      9 => 4,5 => (2,2),(4,1) => (2,2),((2,2),1)
89 //     12 => 4,8 => (2,2),(4,4) => (2,2),((2,2),(2,2))
90 //
91 // But if we ever increase to 13, we would want to split 8,5 rather than 4,9.
92 
93 macro_rules! reduce {
94     ($a:expr, $b:expr, $c:expr, $d:expr, $( $x:expr ),+ => $fn:path) => {
95         reduce!(reduce!($a, $b, $c, $d => $fn),
96                 reduce!($( $x ),+ => $fn)
97                 => $fn)
98     };
99     ($a:expr, $b:expr, $( $x:expr ),+ => $fn:path) => {
100         reduce!(reduce!($a, $b => $fn),
101                 reduce!($( $x ),+ => $fn)
102                 => $fn)
103     };
104     ($a:expr, $b:expr => $fn:path) => { $fn($a, $b) };
105     ($a:expr => $fn:path) => { $a };
106 }
107 
108 macro_rules! nest {
109     ($A:tt, $B:tt, $C:tt, $D:tt, $( $X:tt ),+) => {
110         (nest!($A, $B, $C, $D), nest!($( $X ),+))
111     };
112     ($A:tt, $B:tt, $( $X:tt ),+) => {
113         (($A, $B), nest!($( $X ),+))
114     };
115     ($A:tt, $B:tt) => { ($A, $B) };
116     ($A:tt) => { $A };
117 }
118 
119 macro_rules! flatten {
120     ($( $T:ident ),+) => {{
121         #[allow(non_snake_case)]
122         fn flatten<$( $T ),+>(nest!($( $T ),+) : nest!($( $T ),+)) -> ($( $T, )+) {
123             ($( $T, )+)
124         }
125         flatten
126     }};
127 }
128 
129 macro_rules! multizip_impls {
130     ($(
131         $Tuple:ident {
132             $(($idx:tt) -> $T:ident)+
133         }
134     )+) => {
135         $(
136             impl<$( $T, )+> IntoParallelIterator for ($( $T, )+)
137             where
138                 $(
139                     $T: IntoParallelIterator,
140                     $T::Iter: IndexedParallelIterator,
141                 )+
142             {
143                 type Item = ($( $T::Item, )+);
144                 type Iter = MultiZip<($( $T::Iter, )+)>;
145 
146                 fn into_par_iter(self) -> Self::Iter {
147                     MultiZip {
148                         tuple: ( $( self.$idx.into_par_iter(), )+ ),
149                     }
150                 }
151             }
152 
153             impl<'a, $( $T, )+> IntoParallelIterator for &'a ($( $T, )+)
154             where
155                 $(
156                     $T: IntoParallelRefIterator<'a>,
157                     $T::Iter: IndexedParallelIterator,
158                 )+
159             {
160                 type Item = ($( $T::Item, )+);
161                 type Iter = MultiZip<($( $T::Iter, )+)>;
162 
163                 fn into_par_iter(self) -> Self::Iter {
164                     MultiZip {
165                         tuple: ( $( self.$idx.par_iter(), )+ ),
166                     }
167                 }
168             }
169 
170             impl<'a, $( $T, )+> IntoParallelIterator for &'a mut ($( $T, )+)
171             where
172                 $(
173                     $T: IntoParallelRefMutIterator<'a>,
174                     $T::Iter: IndexedParallelIterator,
175                 )+
176             {
177                 type Item = ($( $T::Item, )+);
178                 type Iter = MultiZip<($( $T::Iter, )+)>;
179 
180                 fn into_par_iter(self) -> Self::Iter {
181                     MultiZip {
182                         tuple: ( $( self.$idx.par_iter_mut(), )+ ),
183                     }
184                 }
185             }
186 
187             impl<$( $T, )+> ParallelIterator for MultiZip<($( $T, )+)>
188             where
189                 $( $T: IndexedParallelIterator, )+
190             {
191                 type Item = ($( $T::Item, )+);
192 
193                 fn drive_unindexed<CONSUMER>(self, consumer: CONSUMER) -> CONSUMER::Result
194                 where
195                     CONSUMER: UnindexedConsumer<Self::Item>,
196                 {
197                     self.drive(consumer)
198                 }
199 
200                 fn opt_len(&self) -> Option<usize> {
201                     Some(self.len())
202                 }
203             }
204 
205             impl<$( $T, )+> IndexedParallelIterator for MultiZip<($( $T, )+)>
206             where
207                 $( $T: IndexedParallelIterator, )+
208             {
209                 fn drive<CONSUMER>(self, consumer: CONSUMER) -> CONSUMER::Result
210                 where
211                     CONSUMER: Consumer<Self::Item>,
212                 {
213                     reduce!($( self.tuple.$idx ),+ => IndexedParallelIterator::zip)
214                         .map(flatten!($( $T ),+))
215                         .drive(consumer)
216                 }
217 
218                 fn len(&self) -> usize {
219                     reduce!($( self.tuple.$idx.len() ),+ => Ord::min)
220                 }
221 
222                 fn with_producer<CB>(self, callback: CB) -> CB::Output
223                 where
224                     CB: ProducerCallback<Self::Item>,
225                 {
226                     reduce!($( self.tuple.$idx ),+ => IndexedParallelIterator::zip)
227                         .map(flatten!($( $T ),+))
228                         .with_producer(callback)
229                 }
230             }
231         )+
232     }
233 }
234 
235 multizip_impls! {
236     Tuple1 {
237         (0) -> A
238     }
239     Tuple2 {
240         (0) -> A
241         (1) -> B
242     }
243     Tuple3 {
244         (0) -> A
245         (1) -> B
246         (2) -> C
247     }
248     Tuple4 {
249         (0) -> A
250         (1) -> B
251         (2) -> C
252         (3) -> D
253     }
254     Tuple5 {
255         (0) -> A
256         (1) -> B
257         (2) -> C
258         (3) -> D
259         (4) -> E
260     }
261     Tuple6 {
262         (0) -> A
263         (1) -> B
264         (2) -> C
265         (3) -> D
266         (4) -> E
267         (5) -> F
268     }
269     Tuple7 {
270         (0) -> A
271         (1) -> B
272         (2) -> C
273         (3) -> D
274         (4) -> E
275         (5) -> F
276         (6) -> G
277     }
278     Tuple8 {
279         (0) -> A
280         (1) -> B
281         (2) -> C
282         (3) -> D
283         (4) -> E
284         (5) -> F
285         (6) -> G
286         (7) -> H
287     }
288     Tuple9 {
289         (0) -> A
290         (1) -> B
291         (2) -> C
292         (3) -> D
293         (4) -> E
294         (5) -> F
295         (6) -> G
296         (7) -> H
297         (8) -> I
298     }
299     Tuple10 {
300         (0) -> A
301         (1) -> B
302         (2) -> C
303         (3) -> D
304         (4) -> E
305         (5) -> F
306         (6) -> G
307         (7) -> H
308         (8) -> I
309         (9) -> J
310     }
311     Tuple11 {
312         (0) -> A
313         (1) -> B
314         (2) -> C
315         (3) -> D
316         (4) -> E
317         (5) -> F
318         (6) -> G
319         (7) -> H
320         (8) -> I
321         (9) -> J
322         (10) -> K
323     }
324     Tuple12 {
325         (0) -> A
326         (1) -> B
327         (2) -> C
328         (3) -> D
329         (4) -> E
330         (5) -> F
331         (6) -> G
332         (7) -> H
333         (8) -> I
334         (9) -> J
335         (10) -> K
336         (11) -> L
337     }
338 }
339