orx_parallel/using/u_par_iter.rs
1use crate::{
2 ChunkSize, DefaultRunner, IterationOrder, NumThreads, ParCollectInto, ParallelRunner, Params,
3 Sum,
4 using::{
5 Using,
6 computations::{u_map_clone, u_map_copy, u_map_count, u_reduce_sum, u_reduce_unit},
7 },
8};
9use orx_concurrent_iter::ConcurrentIter;
10use std::cmp::Ordering;
11
12/// Parallel iterator which allows mutable access to a variable of type `U` within its iterator methods.
13///
14/// Note that one variable will be created per thread used by the parallel computation.
15pub trait ParIterUsing<U, R = DefaultRunner>: Sized + Send + Sync
16where
17 R: ParallelRunner,
18 U: Using,
19{
20 /// Element type of the parallel iterator.
21 type Item: Send + Sync;
22
23 /// Returns a reference to the input concurrent iterator.
24 fn con_iter(&self) -> &impl ConcurrentIter;
25
26 /// Parameters of the parallel iterator.
27 ///
28 /// See [crate::ParIter::params] for details.
29 fn params(&self) -> Params;
30
31 // params transformations
32
33 /// Sets the number of threads to be used in the parallel execution.
34 /// Integers can be used as the argument with the following mapping:
35 ///
36 /// * `0` -> `NumThreads::Auto`
37 /// * `1` -> `NumThreads::sequential()`
38 /// * `n > 0` -> `NumThreads::Max(n)`
39 ///
40 /// /// Parameters of the parallel iterator.
41 ///
42 /// See [crate::ParIter::num_threads] for details.
43 fn num_threads(self, num_threads: impl Into<NumThreads>) -> Self;
44
45 /// Sets the number of elements to be pulled from the concurrent iterator during the
46 /// parallel execution. When integers are used as argument, the following mapping applies:
47 ///
48 /// * `0` -> `ChunkSize::Auto`
49 /// * `n > 0` -> `ChunkSize::Exact(n)`
50 ///
51 /// Please use the default enum constructor for creating `ChunkSize::Min` variant.
52 ///
53 /// See [crate::ParIter::chunk_size] for details.
54 fn chunk_size(self, chunk_size: impl Into<ChunkSize>) -> Self;
55
56 /// Sets the iteration order of the parallel computation.
57 ///
58 /// See [crate::ParIter::iteration_order] for details.
59 fn iteration_order(self, collect: IterationOrder) -> Self;
60
61 /// Rather than the [`DefaultRunner`], uses the parallel runner `Q` which implements [`ParallelRunner`].
62 ///
63 /// See [crate::ParIter::with_runner] for details.
64 fn with_runner<Q: ParallelRunner>(self) -> impl ParIterUsing<U, Q, Item = Self::Item>;
65
66 // computation transformations
67
68 /// Takes a closure `map` and creates a parallel iterator which calls that closure on each element.
69 ///
70 /// Unlike [crate::ParIter::map], the closure allows access to mutable reference of the used variable.
71 ///
72 /// Please see [`crate::ParIter::using`] transformation for details and examples.
73 ///
74 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
75 fn map<Out, Map>(self, map: Map) -> impl ParIterUsing<U, R, Item = Out>
76 where
77 Out: Send + Sync,
78 Map: Fn(&mut U::Item, Self::Item) -> Out + Send + Sync + Clone;
79
80 /// Creates an iterator which uses a closure `filter` to determine if an element should be yielded.
81 ///
82 /// Unlike [crate::ParIter::filter], the closure allows access to mutable reference of the used variable.
83 ///
84 /// Please see [`crate::ParIter::using`] transformation for details and examples.
85 ///
86 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
87 fn filter<Filter>(self, filter: Filter) -> impl ParIterUsing<U, R, Item = Self::Item>
88 where
89 Filter: Fn(&mut U::Item, &Self::Item) -> bool + Send + Sync + Clone;
90
91 /// Creates an iterator that works like map, but flattens nested structure.
92 ///
93 /// Unlike [crate::ParIter::flat_map], the closure allows access to mutable reference of the used variable.
94 ///
95 /// Please see [`crate::ParIter::using`] transformation for details and examples.
96 ///
97 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
98 fn flat_map<IOut, FlatMap>(
99 self,
100 flat_map: FlatMap,
101 ) -> impl ParIterUsing<U, R, Item = IOut::Item>
102 where
103 IOut: IntoIterator + Send + Sync,
104 IOut::IntoIter: Send + Sync,
105 IOut::Item: Send + Sync,
106 FlatMap: Fn(&mut U::Item, Self::Item) -> IOut + Send + Sync + Clone;
107
108 /// Creates an iterator that both filters and maps.
109 ///
110 /// The returned iterator yields only the values for which the supplied closure `filter_map` returns `Some(value)`.
111 ///
112 /// `filter_map` can be used to make chains of `filter` and `map` more concise.
113 /// The example below shows how a `map().filter().map()` can be shortened to a single call to `filter_map`.
114 ///
115 /// Unlike [crate::ParIter::filter_map], the closure allows access to mutable reference of the used variable.
116 ///
117 /// Please see [`crate::ParIter::using`] transformation for details and examples.
118 ///
119 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
120 fn filter_map<Out, FilterMap>(
121 self,
122 filter_map: FilterMap,
123 ) -> impl ParIterUsing<U, R, Item = Out>
124 where
125 Out: Send + Sync,
126 FilterMap: Fn(&mut U::Item, Self::Item) -> Option<Out> + Send + Sync + Clone;
127
128 /// Does something with each element of an iterator, passing the value on.
129 ///
130 /// Unlike [crate::ParIter::inspect], the closure allows access to mutable reference of the used variable.
131 ///
132 /// Please see [`crate::ParIter::using`] transformation for details and examples.
133 ///
134 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
135 fn inspect<Operation>(self, operation: Operation) -> impl ParIterUsing<U, R, Item = Self::Item>
136 where
137 Operation: Fn(&mut U::Item, &Self::Item) + Sync + Send + Clone,
138 {
139 let map = move |u: &mut U::Item, x: Self::Item| {
140 operation(u, &x);
141 x
142 };
143 self.map(map)
144 }
145
146 // special item transformations
147
148 /// Creates an iterator which copies all of its elements.
149 ///
150 /// Unlike [crate::ParIter::copied], the closure allows access to mutable reference of the used variable.
151 ///
152 /// Please see [`crate::ParIter::using`] transformation for details and examples.
153 ///
154 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
155 fn copied<'a, T>(self) -> impl ParIterUsing<U, R, Item = T>
156 where
157 T: 'a + Copy + Send + Sync,
158 Self: ParIterUsing<U, R, Item = &'a T>,
159 {
160 self.map(u_map_copy)
161 }
162
163 /// Creates an iterator which clones all of its elements.
164 ///
165 /// Unlike [crate::ParIter::cloned], the closure allows access to mutable reference of the used variable.
166 ///
167 /// Please see [`crate::ParIter::using`] transformation for details and examples.
168 ///
169 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
170 fn cloned<'a, T>(self) -> impl ParIterUsing<U, R, Item = T>
171 where
172 T: 'a + Clone + Send + Sync,
173 Self: ParIterUsing<U, R, Item = &'a T>,
174 {
175 self.map(u_map_clone)
176 }
177
178 /// Creates an iterator that flattens nested structure.
179 ///
180 /// Unlike [crate::ParIter::flatten], the closure allows access to mutable reference of the used variable.
181 ///
182 /// Please see [`crate::ParIter::using`] transformation for details and examples.
183 ///
184 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
185 fn flatten(self) -> impl ParIterUsing<U, R, Item = <Self::Item as IntoIterator>::Item>
186 where
187 Self::Item: IntoIterator,
188 <Self::Item as IntoIterator>::IntoIter: Send + Sync,
189 <Self::Item as IntoIterator>::Item: Send + Sync,
190 R: Send + Sync,
191 Self: Send + Sync,
192 {
193 let map = |_: &mut U::Item, e: Self::Item| e.into_iter();
194 self.flat_map(map)
195 }
196
197 // collect
198
199 /// Collects all the items from an iterator into a collection.
200 ///
201 /// Unlike [crate::ParIter::collect_into], the closure allows access to mutable reference of the used variable.
202 ///
203 /// Please see [`crate::ParIter::using`] transformation for details and examples.
204 ///
205 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
206 fn collect_into<C>(self, output: C) -> C
207 where
208 C: ParCollectInto<Self::Item>;
209
210 /// Transforms an iterator into a collection.
211 ///
212 /// Unlike [crate::ParIter::collect], the closure allows access to mutable reference of the used variable.
213 ///
214 /// Please see [`crate::ParIter::using`] transformation for details and examples.
215 ///
216 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
217 fn collect<C>(self) -> C
218 where
219 C: ParCollectInto<Self::Item>,
220 {
221 let output = C::empty(self.con_iter().try_get_len());
222 self.collect_into(output)
223 }
224
225 // reduce
226
227 /// Reduces the elements to a single one, by repeatedly applying a reducing operation.
228 ///
229 /// See the details here: [crate::ParIter::reduce].
230 fn reduce<Reduce>(self, reduce: Reduce) -> Option<Self::Item>
231 where
232 Reduce: Fn(&mut U::Item, Self::Item, Self::Item) -> Self::Item + Send + Sync;
233
234 /// Tests if every element of the iterator matches a predicate.
235 ///
236 /// Unlike [crate::ParIter::all], the closure allows access to mutable reference of the used variable.
237 ///
238 /// Please see [`crate::ParIter::using`] transformation for details and examples.
239 ///
240 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
241 fn all<Predicate>(self, predicate: Predicate) -> bool
242 where
243 Predicate: Fn(&mut U::Item, &Self::Item) -> bool + Send + Sync + Clone,
244 {
245 let violates = |u: &mut U::Item, x: &Self::Item| !predicate(u, x);
246 self.find(violates).is_none()
247 }
248
249 /// Tests if any element of the iterator matches a predicate.
250 ///
251 /// Unlike [crate::ParIter::any], the closure allows access to mutable reference of the used variable.
252 ///
253 /// Please see [`crate::ParIter::using`] transformation for details and examples.
254 ///
255 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
256 fn any<Predicate>(self, predicate: Predicate) -> bool
257 where
258 Predicate: Fn(&mut U::Item, &Self::Item) -> bool + Send + Sync + Clone,
259 {
260 self.find(predicate).is_some()
261 }
262
263 /// Consumes the iterator, counting the number of iterations and returning it.
264 ///
265 /// See the details here: [crate::ParIter::count].
266 fn count(self) -> usize {
267 self.map(u_map_count).reduce(u_reduce_sum).unwrap_or(0)
268 }
269
270 /// Calls a closure on each element of an iterator.
271 ///
272 /// Unlike [crate::ParIter::for_each], the closure allows access to mutable reference of the used variable.
273 ///
274 /// Please see [`crate::ParIter::using`] transformation for details and examples.
275 ///
276 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
277 fn for_each<Operation>(self, operation: Operation)
278 where
279 Operation: Fn(&mut U::Item, Self::Item) + Sync + Send,
280 {
281 let map = |u: &mut U::Item, x| operation(u, x);
282 let _ = self.map(map).reduce(u_reduce_unit);
283 }
284
285 /// Returns the maximum element of an iterator.
286 ///
287 /// See the details here: [crate::ParIter::max].
288 fn max(self) -> Option<Self::Item>
289 where
290 Self::Item: Ord,
291 {
292 self.reduce(|_, a, b| Ord::max(a, b))
293 }
294
295 /// Returns the element that gives the maximum value with respect to the specified `compare` function.
296 ///
297 /// See the details here: [crate::ParIter::max_by].
298 fn max_by<Compare>(self, compare: Compare) -> Option<Self::Item>
299 where
300 Compare: Fn(&Self::Item, &Self::Item) -> Ordering + Sync,
301 {
302 let reduce = |_: &mut U::Item, x, y| match compare(&x, &y) {
303 Ordering::Greater | Ordering::Equal => x,
304 Ordering::Less => y,
305 };
306 self.reduce(reduce)
307 }
308
309 /// Returns the element that gives the maximum value from the specified function.
310 ///
311 /// See the details here: [crate::ParIter::max_by_key].
312 fn max_by_key<Key, GetKey>(self, key: GetKey) -> Option<Self::Item>
313 where
314 Key: Ord,
315 GetKey: Fn(&Self::Item) -> Key + Sync,
316 {
317 let reduce = |_: &mut U::Item, x, y| match key(&x).cmp(&key(&y)) {
318 Ordering::Greater | Ordering::Equal => x,
319 Ordering::Less => y,
320 };
321 self.reduce(reduce)
322 }
323
324 /// Returns the minimum element of an iterator.
325 ///
326 /// See the details here: [crate::ParIter::min].
327 fn min(self) -> Option<Self::Item>
328 where
329 Self::Item: Ord,
330 {
331 self.reduce(|_, a, b| Ord::min(a, b))
332 }
333
334 /// Returns the element that gives the minimum value with respect to the specified `compare` function.
335 ///
336 /// See the details here: [crate::ParIter::min_by].
337 fn min_by<Compare>(self, compare: Compare) -> Option<Self::Item>
338 where
339 Compare: Fn(&Self::Item, &Self::Item) -> Ordering + Sync,
340 {
341 let reduce = |_: &mut U::Item, x, y| match compare(&x, &y) {
342 Ordering::Less | Ordering::Equal => x,
343 Ordering::Greater => y,
344 };
345 self.reduce(reduce)
346 }
347
348 /// Returns the element that gives the minimum value from the specified function.
349 ///
350 /// See the details here: [crate::ParIter::min_by_key].
351 fn min_by_key<Key, GetKey>(self, get_key: GetKey) -> Option<Self::Item>
352 where
353 Key: Ord,
354 GetKey: Fn(&Self::Item) -> Key + Sync,
355 {
356 let reduce = |_: &mut U::Item, x, y| match get_key(&x).cmp(&get_key(&y)) {
357 Ordering::Less | Ordering::Equal => x,
358 Ordering::Greater => y,
359 };
360 self.reduce(reduce)
361 }
362
363 /// Sums the elements of an iterator.
364 ///
365 /// See the details here: [crate::ParIter::sum].
366 fn sum<Out>(self) -> Out
367 where
368 Self::Item: Sum<Out>,
369 Out: Send + Sync,
370 {
371 self.map(Self::Item::u_map)
372 .reduce(Self::Item::u_reduce)
373 .unwrap_or(Self::Item::zero())
374 }
375
376 // early exit
377
378 /// Returns the first (or any) element of the iterator; returns None if it is empty.
379 ///
380 /// * first element is returned if default iteration order `IterationOrder::Ordered` is used,
381 /// * any element is returned if `IterationOrder::Arbitrary` is set.
382 ///
383 /// See the details here: [crate::ParIter::first].
384 fn first(self) -> Option<Self::Item>;
385
386 /// Searches for an element of an iterator that satisfies a `predicate`.
387 ///
388 /// Unlike [crate::ParIter::find], the closure allows access to mutable reference of the used variable.
389 ///
390 /// Please see [`crate::ParIter::using`] transformation for details and examples.
391 ///
392 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
393 fn find<Predicate>(self, predicate: Predicate) -> Option<Self::Item>
394 where
395 Predicate: Fn(&mut U::Item, &Self::Item) -> bool + Send + Sync + Clone,
396 {
397 self.filter(predicate).first()
398 }
399}