Coverage Report

Created: 2026-01-13 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rayon-1.11.0/src/iter/splitter.rs
Line
Count
Source
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
0
pub fn split<D, S>(data: D, splitter: S) -> Split<D, S>
107
0
where
108
0
    D: Send,
109
0
    S: Fn(D) -> (D, Option<D>) + Sync,
110
{
111
0
    Split { data, splitter }
112
0
}
113
114
/// `Split` is a parallel iterator using arbitrary data and a splitting function.
115
/// This struct is created by the [`split()`] function.
116
#[derive(Clone)]
117
pub struct Split<D, S> {
118
    data: D,
119
    splitter: S,
120
}
121
122
impl<D: Debug, S> Debug for Split<D, S> {
123
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124
0
        f.debug_struct("Split").field("data", &self.data).finish()
125
0
    }
126
}
127
128
impl<D, S> ParallelIterator for Split<D, S>
129
where
130
    D: Send,
131
    S: Fn(D) -> (D, Option<D>) + Sync + Send,
132
{
133
    type Item = D;
134
135
0
    fn drive_unindexed<C>(self, consumer: C) -> C::Result
136
0
    where
137
0
        C: UnindexedConsumer<Self::Item>,
138
    {
139
0
        let producer = SplitProducer {
140
0
            data: self.data,
141
0
            splitter: &self.splitter,
142
0
        };
143
0
        bridge_unindexed(producer, consumer)
144
0
    }
145
}
146
147
struct SplitProducer<'a, D, S> {
148
    data: D,
149
    splitter: &'a S,
150
}
151
152
impl<'a, D, S> UnindexedProducer for SplitProducer<'a, D, S>
153
where
154
    D: Send,
155
    S: Fn(D) -> (D, Option<D>) + Sync,
156
{
157
    type Item = D;
158
159
0
    fn split(mut self) -> (Self, Option<Self>) {
160
0
        let splitter = self.splitter;
161
0
        let (left, right) = splitter(self.data);
162
0
        self.data = left;
163
0
        (self, right.map(|data| SplitProducer { data, splitter }))
164
0
    }
165
166
0
    fn fold_with<F>(self, folder: F) -> F
167
0
    where
168
0
        F: Folder<Self::Item>,
169
    {
170
0
        folder.consume(self.data)
171
0
    }
172
}