| 1 | use super::plumbing::*; | 
| 2 | use super::*; | 
|---|
| 3 |  | 
|---|
| 4 | use std::fmt::{self, Debug}; | 
|---|
| 5 |  | 
|---|
| 6 | /// The `split` function takes arbitrary data and a closure that knows how to | 
|---|
| 7 | /// split it, and turns this into a `ParallelIterator`. | 
|---|
| 8 | /// | 
|---|
| 9 | /// # Examples | 
|---|
| 10 | /// | 
|---|
| 11 | /// As a simple example, Rayon can recursively split ranges of indices | 
|---|
| 12 | /// | 
|---|
| 13 | /// ``` | 
|---|
| 14 | /// use rayon::iter; | 
|---|
| 15 | /// use rayon::prelude::*; | 
|---|
| 16 | /// use std::ops::Range; | 
|---|
| 17 | /// | 
|---|
| 18 | /// | 
|---|
| 19 | /// // We define a range of indices as follows | 
|---|
| 20 | /// type Range1D = Range<usize>; | 
|---|
| 21 | /// | 
|---|
| 22 | /// // Splitting it in two can be done like this | 
|---|
| 23 | /// fn split_range1(r: Range1D) -> (Range1D, Option<Range1D>) { | 
|---|
| 24 | ///     // We are mathematically unable to split the range if there is only | 
|---|
| 25 | ///     // one point inside of it, but we could stop splitting before that. | 
|---|
| 26 | ///     if r.end - r.start <= 1 { return (r, None); } | 
|---|
| 27 | /// | 
|---|
| 28 | ///     // Here, our range is considered large enough to be splittable | 
|---|
| 29 | ///     let midpoint = r.start + (r.end - r.start) / 2; | 
|---|
| 30 | ///     (r.start..midpoint, Some(midpoint..r.end)) | 
|---|
| 31 | /// } | 
|---|
| 32 | /// | 
|---|
| 33 | /// // By using iter::split, Rayon will split the range until it has enough work | 
|---|
| 34 | /// // to feed the CPU cores, then give us the resulting sub-ranges | 
|---|
| 35 | /// iter::split(0..4096, split_range1).for_each(|sub_range| { | 
|---|
| 36 | ///     // As our initial range had a power-of-two size, the final sub-ranges | 
|---|
| 37 | ///     // should have power-of-two sizes too | 
|---|
| 38 | ///     assert!((sub_range.end - sub_range.start).is_power_of_two()); | 
|---|
| 39 | /// }); | 
|---|
| 40 | /// ``` | 
|---|
| 41 | /// | 
|---|
| 42 | /// This recursive splitting can be extended to two or three dimensions, | 
|---|
| 43 | /// to reproduce a classic "block-wise" parallelization scheme of graphics and | 
|---|
| 44 | /// numerical simulations: | 
|---|
| 45 | /// | 
|---|
| 46 | /// ``` | 
|---|
| 47 | /// # use rayon::iter; | 
|---|
| 48 | /// # use rayon::prelude::*; | 
|---|
| 49 | /// # use std::ops::Range; | 
|---|
| 50 | /// # type Range1D = Range<usize>; | 
|---|
| 51 | /// # fn split_range1(r: Range1D) -> (Range1D, Option<Range1D>) { | 
|---|
| 52 | /// #     if r.end - r.start <= 1 { return (r, None); } | 
|---|
| 53 | /// #     let midpoint = r.start + (r.end - r.start) / 2; | 
|---|
| 54 | /// #     (r.start..midpoint, Some(midpoint..r.end)) | 
|---|
| 55 | /// # } | 
|---|
| 56 | /// # | 
|---|
| 57 | /// // A two-dimensional range of indices can be built out of two 1D ones | 
|---|
| 58 | /// struct Range2D { | 
|---|
| 59 | ///     // Range of horizontal indices | 
|---|
| 60 | ///     pub rx: Range1D, | 
|---|
| 61 | /// | 
|---|
| 62 | ///     // Range of vertical indices | 
|---|
| 63 | ///     pub ry: Range1D, | 
|---|
| 64 | /// } | 
|---|
| 65 | /// | 
|---|
| 66 | /// // We want to recursively split them by the largest dimension until we have | 
|---|
| 67 | /// // enough sub-ranges to feed our mighty multi-core CPU. This function | 
|---|
| 68 | /// // carries out one such split. | 
|---|
| 69 | /// fn split_range2(r2: Range2D) -> (Range2D, Option<Range2D>) { | 
|---|
| 70 | ///     // Decide on which axis (horizontal/vertical) the range should be split | 
|---|
| 71 | ///     let width = r2.rx.end - r2.rx.start; | 
|---|
| 72 | ///     let height = r2.ry.end - r2.ry.start; | 
|---|
| 73 | ///     if width >= height { | 
|---|
| 74 | ///         // This is a wide range, split it on the horizontal axis | 
|---|
| 75 | ///         let (split_rx, ry) = (split_range1(r2.rx), r2.ry); | 
|---|
| 76 | ///         let out1 = Range2D { | 
|---|
| 77 | ///             rx: split_rx.0, | 
|---|
| 78 | ///             ry: ry.clone(), | 
|---|
| 79 | ///         }; | 
|---|
| 80 | ///         let out2 = split_rx.1.map(|rx| Range2D { rx, ry }); | 
|---|
| 81 | ///         (out1, out2) | 
|---|
| 82 | ///     } else { | 
|---|
| 83 | ///         // This is a tall range, split it on the vertical axis | 
|---|
| 84 | ///         let (rx, split_ry) = (r2.rx, split_range1(r2.ry)); | 
|---|
| 85 | ///         let out1 = Range2D { | 
|---|
| 86 | ///             rx: rx.clone(), | 
|---|
| 87 | ///             ry: split_ry.0, | 
|---|
| 88 | ///         }; | 
|---|
| 89 | ///         let out2 = split_ry.1.map(|ry| Range2D { rx, ry, }); | 
|---|
| 90 | ///         (out1, out2) | 
|---|
| 91 | ///     } | 
|---|
| 92 | /// } | 
|---|
| 93 | /// | 
|---|
| 94 | /// // Again, rayon can handle the recursive splitting for us | 
|---|
| 95 | /// let range = Range2D { rx: 0..800, ry: 0..600 }; | 
|---|
| 96 | /// iter::split(range, split_range2).for_each(|sub_range| { | 
|---|
| 97 | ///     // If the sub-ranges were indeed split by the largest dimension, then | 
|---|
| 98 | ///     // if no dimension was twice larger than the other initially, this | 
|---|
| 99 | ///     // property will remain true in the final sub-ranges. | 
|---|
| 100 | ///     let width = sub_range.rx.end - sub_range.rx.start; | 
|---|
| 101 | ///     let height = sub_range.ry.end - sub_range.ry.start; | 
|---|
| 102 | ///     assert!((width / 2 <= height) && (height / 2 <= width)); | 
|---|
| 103 | /// }); | 
|---|
| 104 | /// ``` | 
|---|
| 105 | /// | 
|---|
| 106 | pub fn split<D, S>(data: D, splitter: S) -> Split<D, S> | 
|---|
| 107 | where | 
|---|
| 108 | D: Send, | 
|---|
| 109 | S: Fn(D) -> (D, Option<D>) + Sync, | 
|---|
| 110 | { | 
|---|
| 111 | Split { data, splitter } | 
|---|
| 112 | } | 
|---|
| 113 |  | 
|---|
| 114 | /// `Split` is a parallel iterator using arbitrary data and a splitting function. | 
|---|
| 115 | /// This struct is created by the [`split()`] function. | 
|---|
| 116 | /// | 
|---|
| 117 | /// [`split()`]: fn.split.html | 
|---|
| 118 | #[ derive(Clone)] | 
|---|
| 119 | pub struct Split<D, S> { | 
|---|
| 120 | data: D, | 
|---|
| 121 | splitter: S, | 
|---|
| 122 | } | 
|---|
| 123 |  | 
|---|
| 124 | impl<D: Debug, S> Debug for Split<D, S> { | 
|---|
| 125 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|---|
| 126 | f.debug_struct( "Split").field(name: "data", &self.data).finish() | 
|---|
| 127 | } | 
|---|
| 128 | } | 
|---|
| 129 |  | 
|---|
| 130 | impl<D, S> ParallelIterator for Split<D, S> | 
|---|
| 131 | where | 
|---|
| 132 | D: Send, | 
|---|
| 133 | S: Fn(D) -> (D, Option<D>) + Sync + Send, | 
|---|
| 134 | { | 
|---|
| 135 | type Item = D; | 
|---|
| 136 |  | 
|---|
| 137 | fn drive_unindexed<C>(self, consumer: C) -> C::Result | 
|---|
| 138 | where | 
|---|
| 139 | C: UnindexedConsumer<Self::Item>, | 
|---|
| 140 | { | 
|---|
| 141 | let producer: SplitProducer<'_, D, S> = SplitProducer { | 
|---|
| 142 | data: self.data, | 
|---|
| 143 | splitter: &self.splitter, | 
|---|
| 144 | }; | 
|---|
| 145 | bridge_unindexed(producer, consumer) | 
|---|
| 146 | } | 
|---|
| 147 | } | 
|---|
| 148 |  | 
|---|
| 149 | struct SplitProducer<'a, D, S> { | 
|---|
| 150 | data: D, | 
|---|
| 151 | splitter: &'a S, | 
|---|
| 152 | } | 
|---|
| 153 |  | 
|---|
| 154 | impl<'a, D, S> UnindexedProducer for SplitProducer<'a, D, S> | 
|---|
| 155 | where | 
|---|
| 156 | D: Send, | 
|---|
| 157 | S: Fn(D) -> (D, Option<D>) + Sync, | 
|---|
| 158 | { | 
|---|
| 159 | type Item = D; | 
|---|
| 160 |  | 
|---|
| 161 | fn split(mut self) -> (Self, Option<Self>) { | 
|---|
| 162 | let splitter: &'a S = self.splitter; | 
|---|
| 163 | let (left: D, right: Option) = splitter(self.data); | 
|---|
| 164 | self.data = left; | 
|---|
| 165 | (self, right.map(|data: D| SplitProducer { data, splitter })) | 
|---|
| 166 | } | 
|---|
| 167 |  | 
|---|
| 168 | fn fold_with<F>(self, folder: F) -> F | 
|---|
| 169 | where | 
|---|
| 170 | F: Folder<Self::Item>, | 
|---|
| 171 | { | 
|---|
| 172 | folder.consume(self.data) | 
|---|
| 173 | } | 
|---|
| 174 | } | 
|---|
| 175 |  | 
|---|