winter_utils/
iterators.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree.
5
6//! Components needed for parallel iterators.
7//!
8//! When `concurrent` feature is enabled, this module re-exports `rayon::prelude`. Otherwise,
9//! this is an empty module.
10
11#[cfg(feature = "concurrent")]
12pub use rayon::{current_num_threads as rayon_num_threads, prelude::*};
13
14/// Returns either a regular or a parallel iterator depending on whether `concurrent` feature
15/// is enabled.
16///
17/// When `concurrent` feature is enabled, creates a parallel iterator; otherwise, creates a
18/// regular iterator. Optionally, `min_length` can be used to specify the minimum length of
19/// iterator to be processed in each thread.
20///
21/// Adapted from: <https://github.com/arkworks-rs/utils/blob/master/src/lib.rs>
22#[macro_export]
23macro_rules! iter {
24    ($e:expr) => {{
25        #[cfg(feature = "concurrent")]
26        let result = $e.par_iter();
27
28        #[cfg(not(feature = "concurrent"))]
29        let result = $e.iter();
30
31        result
32    }};
33    ($e:expr, $min_len:expr) => {{
34        #[cfg(feature = "concurrent")]
35        let result = $e.par_iter().with_min_len($min_len);
36
37        #[cfg(not(feature = "concurrent"))]
38        let result = $e.iter();
39
40        result
41    }};
42}
43
44/// Returns either a regular or a parallel mutable iterator depending on whether `concurrent`
45/// feature is enabled.
46///
47/// When `concurrent` feature is enabled, creates a mutable parallel iterator; otherwise,
48/// creates a regular mutable iterator. Optionally, `min_length` can be used to specify the
49/// minimum length of iterator to be processed in each thread.
50///
51/// Adapted from: <https://github.com/arkworks-rs/utils/blob/master/src/lib.rs>
52#[macro_export]
53macro_rules! iter_mut {
54    ($e:expr) => {{
55        #[cfg(feature = "concurrent")]
56        let result = $e.par_iter_mut();
57
58        #[cfg(not(feature = "concurrent"))]
59        let result = $e.iter_mut();
60
61        result
62    }};
63    ($e:expr, $min_len:expr) => {{
64        #[cfg(feature = "concurrent")]
65        let result = $e.par_iter_mut().with_min_len($min_len);
66
67        #[cfg(not(feature = "concurrent"))]
68        let result = $e.iter_mut();
69
70        result
71    }};
72}
73
74/// Applies a procedure to the provided slice either in a single thread or multiple threads
75/// based on whether `concurrent` feature is enabled.
76///
77/// When `concurrent` feature is enabled, breaks the slice into batches and processes each
78/// batch in a separate thread; otherwise, the entire slice is processed as a single batch
79/// in one thread. Optionally, `min_batch_size` can be used to specify the minimum size of
80/// the resulting batches.
81#[macro_export]
82macro_rules! batch_iter_mut {
83    ($e: expr, $c: expr) => {
84        #[cfg(feature = "concurrent")]
85        {
86            let batch_size = $e.len() / rayon_num_threads().next_power_of_two();
87            if batch_size < 1 {
88                $c($e, 0);
89            }
90            else {
91                $e.par_chunks_mut(batch_size).enumerate().for_each(|(i, batch)| {
92                    $c(batch, i * batch_size);
93                });
94            }
95        }
96
97        #[cfg(not(feature = "concurrent"))]
98        $c($e, 0);
99    };
100    ($e: expr, $min_batch_size: expr, $c: expr) => {
101        #[cfg(feature = "concurrent")]
102        {
103            let batch_size = $e.len() / rayon_num_threads().next_power_of_two();
104            if batch_size < $min_batch_size {
105                $c($e, 0);
106            }
107            else {
108                $e.par_chunks_mut(batch_size).enumerate().for_each(|(i, batch)| {
109                    $c(batch, i * batch_size);
110                });
111            }
112        }
113
114        #[cfg(not(feature = "concurrent"))]
115        $c($e, 0);
116    };
117}