rayon_scan/lib.rs
1use self::scan::Scan;
2use rayon::prelude::ParallelIterator;
3
4mod scan;
5
6pub trait ScanParallelIterator: ParallelIterator {
7 /// Folds the items in the iterator using `scan_op`, and produces a
8 /// new iterator with all of the intermediate results.
9 ///
10 /// Specifically, the nth element of the scan iterator will be the
11 /// result of reducing the first n elements of the input with `scan_op`.
12 ///
13 /// # Examples
14 ///
15 /// ```
16 /// // Iterate over a sequence of numbers `x0, ..., xN`
17 /// // and use scan to compute the partial sums
18 /// use rayon::prelude::*;
19 /// use rayon_scan::ScanParallelIterator;
20 ///
21 /// let partial_sums = [1, 2, 3, 4, 5]
22 /// .into_par_iter() // iterating over i32
23 /// .scan(|a, b| *a + *b, // add (&i32, &i32) -> i32
24 /// 0) // identity
25 /// .collect::<Vec<i32>>();
26 /// assert_eq!(partial_sums, vec![1, 3, 6, 10, 15]);
27 /// ```
28 ///
29 /// **Note:** Unlike a sequential `scan` operation, the order in
30 /// which `scan_op` will be applied to produce the result is not fully
31 /// specified. So `scan_op` should be [associative] or else the results
32 /// will be non-deterministic. Also unlike sequential `scan`, there is
33 /// no internal state for this operation, so the operation has a
34 /// different signature.
35 ///
36 /// The argument `identity` should be an "identity" value for
37 /// `scan_op`, which may be inserted into the sequence as
38 /// needed to create opportunities for parallel execution. So, for
39 /// example, if you are doing a summation, then `identity` ought
40 /// to represent the zero for your type.
41 ///
42 /// [associative]: https://en.wikipedia.org/wiki/Associative_property
43 fn scan<F>(self, scan_op: F, identity: Self::Item) -> Scan<Self::Item, F>
44 where
45 F: Fn(&Self::Item, &Self::Item) -> Self::Item + Sync + Send,
46 <Self as ParallelIterator>::Item: Send + Sync,
47 {
48 scan::scan(self, scan_op, identity)
49 }
50}
51
52impl<T: ParallelIterator> ScanParallelIterator for T {}