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 core::cmp::Ordering;
10use orx_concurrent_iter::ConcurrentIter;
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;
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 Map: Fn(&mut U::Item, Self::Item) -> Out + Sync + Clone;
78
79 /// Creates an iterator which uses a closure `filter` to determine if an element should be yielded.
80 ///
81 /// Unlike [crate::ParIter::filter], the closure allows access to mutable reference of the used variable.
82 ///
83 /// Please see [`crate::ParIter::using`] transformation for details and examples.
84 ///
85 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
86 fn filter<Filter>(self, filter: Filter) -> impl ParIterUsing<U, R, Item = Self::Item>
87 where
88 Filter: Fn(&mut U::Item, &Self::Item) -> bool + Sync + Clone;
89
90 /// Creates an iterator that works like map, but flattens nested structure.
91 ///
92 /// Unlike [crate::ParIter::flat_map], the closure allows access to mutable reference of the used variable.
93 ///
94 /// Please see [`crate::ParIter::using`] transformation for details and examples.
95 ///
96 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
97 fn flat_map<IOut, FlatMap>(
98 self,
99 flat_map: FlatMap,
100 ) -> impl ParIterUsing<U, R, Item = IOut::Item>
101 where
102 IOut: IntoIterator,
103 FlatMap: Fn(&mut U::Item, Self::Item) -> IOut + Sync + Clone;
104
105 /// Creates an iterator that both filters and maps.
106 ///
107 /// The returned iterator yields only the values for which the supplied closure `filter_map` returns `Some(value)`.
108 ///
109 /// `filter_map` can be used to make chains of `filter` and `map` more concise.
110 /// The example below shows how a `map().filter().map()` can be shortened to a single call to `filter_map`.
111 ///
112 /// Unlike [crate::ParIter::filter_map], the closure allows access to mutable reference of the used variable.
113 ///
114 /// Please see [`crate::ParIter::using`] transformation for details and examples.
115 ///
116 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
117 fn filter_map<Out, FilterMap>(
118 self,
119 filter_map: FilterMap,
120 ) -> impl ParIterUsing<U, R, Item = Out>
121 where
122 FilterMap: Fn(&mut U::Item, Self::Item) -> Option<Out> + Sync + Clone;
123
124 /// Does something with each element of an iterator, passing the value on.
125 ///
126 /// Unlike [crate::ParIter::inspect], the closure allows access to mutable reference of the used variable.
127 ///
128 /// Please see [`crate::ParIter::using`] transformation for details and examples.
129 ///
130 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
131 fn inspect<Operation>(self, operation: Operation) -> impl ParIterUsing<U, R, Item = Self::Item>
132 where
133 Operation: Fn(&mut U::Item, &Self::Item) + Sync + Clone,
134 {
135 let map = move |u: &mut U::Item, x: Self::Item| {
136 operation(u, &x);
137 x
138 };
139 self.map(map)
140 }
141
142 // special item transformations
143
144 /// Creates an iterator which copies all of its elements.
145 ///
146 /// Unlike [crate::ParIter::copied], the closure allows access to mutable reference of the used variable.
147 ///
148 /// Please see [`crate::ParIter::using`] transformation for details and examples.
149 ///
150 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
151 fn copied<'a, T>(self) -> impl ParIterUsing<U, R, Item = T>
152 where
153 T: 'a + Copy,
154 Self: ParIterUsing<U, R, Item = &'a T>,
155 {
156 self.map(u_map_copy)
157 }
158
159 /// Creates an iterator which clones all of its elements.
160 ///
161 /// Unlike [crate::ParIter::cloned], the closure allows access to mutable reference of the used variable.
162 ///
163 /// Please see [`crate::ParIter::using`] transformation for details and examples.
164 ///
165 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
166 fn cloned<'a, T>(self) -> impl ParIterUsing<U, R, Item = T>
167 where
168 T: 'a + Clone,
169 Self: ParIterUsing<U, R, Item = &'a T>,
170 {
171 self.map(u_map_clone)
172 }
173
174 /// Creates an iterator that flattens nested structure.
175 ///
176 /// Unlike [crate::ParIter::flatten], the closure allows access to mutable reference of the used variable.
177 ///
178 /// Please see [`crate::ParIter::using`] transformation for details and examples.
179 ///
180 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
181 fn flatten(self) -> impl ParIterUsing<U, R, Item = <Self::Item as IntoIterator>::Item>
182 where
183 Self::Item: IntoIterator,
184 {
185 let map = |_: &mut U::Item, e: Self::Item| e.into_iter();
186 self.flat_map(map)
187 }
188
189 // collect
190
191 /// Collects all the items from an iterator into a collection.
192 ///
193 /// Unlike [crate::ParIter::collect_into], the closure allows access to mutable reference of the used variable.
194 ///
195 /// Please see [`crate::ParIter::using`] transformation for details and examples.
196 ///
197 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
198 fn collect_into<C>(self, output: C) -> C
199 where
200 C: ParCollectInto<Self::Item>;
201
202 /// Transforms an iterator into a collection.
203 ///
204 /// Unlike [crate::ParIter::collect], the closure allows access to mutable reference of the used variable.
205 ///
206 /// Please see [`crate::ParIter::using`] transformation for details and examples.
207 ///
208 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
209 fn collect<C>(self) -> C
210 where
211 C: ParCollectInto<Self::Item>,
212 {
213 let output = C::empty(self.con_iter().try_get_len());
214 self.collect_into(output)
215 }
216
217 // reduce
218
219 /// Reduces the elements to a single one, by repeatedly applying a reducing operation.
220 ///
221 /// See the details here: [crate::ParIter::reduce].
222 fn reduce<Reduce>(self, reduce: Reduce) -> Option<Self::Item>
223 where
224 Self::Item: Send,
225 Reduce: Fn(&mut U::Item, Self::Item, Self::Item) -> Self::Item + Sync;
226
227 /// Tests if every element of the iterator matches a predicate.
228 ///
229 /// Unlike [crate::ParIter::all], the closure allows access to mutable reference of the used variable.
230 ///
231 /// Please see [`crate::ParIter::using`] transformation for details and examples.
232 ///
233 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
234 fn all<Predicate>(self, predicate: Predicate) -> bool
235 where
236 Self::Item: Send,
237 Predicate: Fn(&mut U::Item, &Self::Item) -> bool + Sync + Clone,
238 {
239 let violates = |u: &mut U::Item, x: &Self::Item| !predicate(u, x);
240 self.find(violates).is_none()
241 }
242
243 /// Tests if any element of the iterator matches a predicate.
244 ///
245 /// Unlike [crate::ParIter::any], the closure allows access to mutable reference of the used variable.
246 ///
247 /// Please see [`crate::ParIter::using`] transformation for details and examples.
248 ///
249 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
250 fn any<Predicate>(self, predicate: Predicate) -> bool
251 where
252 Self::Item: Send,
253 Predicate: Fn(&mut U::Item, &Self::Item) -> bool + Sync + Clone,
254 {
255 self.find(predicate).is_some()
256 }
257
258 /// Consumes the iterator, counting the number of iterations and returning it.
259 ///
260 /// See the details here: [crate::ParIter::count].
261 fn count(self) -> usize {
262 self.map(u_map_count).reduce(u_reduce_sum).unwrap_or(0)
263 }
264
265 /// Calls a closure on each element of an iterator.
266 ///
267 /// Unlike [crate::ParIter::for_each], the closure allows access to mutable reference of the used variable.
268 ///
269 /// Please see [`crate::ParIter::using`] transformation for details and examples.
270 ///
271 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
272 fn for_each<Operation>(self, operation: Operation)
273 where
274 Operation: Fn(&mut U::Item, Self::Item) + Sync,
275 {
276 let map = |u: &mut U::Item, x| operation(u, x);
277 let _ = self.map(map).reduce(u_reduce_unit);
278 }
279
280 /// Returns the maximum element of an iterator.
281 ///
282 /// See the details here: [crate::ParIter::max].
283 fn max(self) -> Option<Self::Item>
284 where
285 Self::Item: Ord + Send,
286 {
287 self.reduce(|_, a, b| Ord::max(a, b))
288 }
289
290 /// Returns the element that gives the maximum value with respect to the specified `compare` function.
291 ///
292 /// See the details here: [crate::ParIter::max_by].
293 fn max_by<Compare>(self, compare: Compare) -> Option<Self::Item>
294 where
295 Self::Item: Send,
296 Compare: Fn(&Self::Item, &Self::Item) -> Ordering + Sync,
297 {
298 let reduce = |_: &mut U::Item, x, y| match compare(&x, &y) {
299 Ordering::Greater | Ordering::Equal => x,
300 Ordering::Less => y,
301 };
302 self.reduce(reduce)
303 }
304
305 /// Returns the element that gives the maximum value from the specified function.
306 ///
307 /// See the details here: [crate::ParIter::max_by_key].
308 fn max_by_key<Key, GetKey>(self, key: GetKey) -> Option<Self::Item>
309 where
310 Self::Item: Send,
311 Key: Ord,
312 GetKey: Fn(&Self::Item) -> Key + Sync,
313 {
314 let reduce = |_: &mut U::Item, x, y| match key(&x).cmp(&key(&y)) {
315 Ordering::Greater | Ordering::Equal => x,
316 Ordering::Less => y,
317 };
318 self.reduce(reduce)
319 }
320
321 /// Returns the minimum element of an iterator.
322 ///
323 /// See the details here: [crate::ParIter::min].
324 fn min(self) -> Option<Self::Item>
325 where
326 Self::Item: Ord + Send,
327 {
328 self.reduce(|_, a, b| Ord::min(a, b))
329 }
330
331 /// Returns the element that gives the minimum value with respect to the specified `compare` function.
332 ///
333 /// See the details here: [crate::ParIter::min_by].
334 fn min_by<Compare>(self, compare: Compare) -> Option<Self::Item>
335 where
336 Self::Item: Send,
337 Compare: Fn(&Self::Item, &Self::Item) -> Ordering + Sync,
338 {
339 let reduce = |_: &mut U::Item, x, y| match compare(&x, &y) {
340 Ordering::Less | Ordering::Equal => x,
341 Ordering::Greater => y,
342 };
343 self.reduce(reduce)
344 }
345
346 /// Returns the element that gives the minimum value from the specified function.
347 ///
348 /// See the details here: [crate::ParIter::min_by_key].
349 fn min_by_key<Key, GetKey>(self, get_key: GetKey) -> Option<Self::Item>
350 where
351 Self::Item: Send,
352 Key: Ord,
353 GetKey: Fn(&Self::Item) -> Key + Sync,
354 {
355 let reduce = |_: &mut U::Item, x, y| match get_key(&x).cmp(&get_key(&y)) {
356 Ordering::Less | Ordering::Equal => x,
357 Ordering::Greater => y,
358 };
359 self.reduce(reduce)
360 }
361
362 /// Sums the elements of an iterator.
363 ///
364 /// See the details here: [crate::ParIter::sum].
365 fn sum<Out>(self) -> Out
366 where
367 Self::Item: Sum<Out>,
368 Out: Send,
369 {
370 self.map(Self::Item::u_map)
371 .reduce(Self::Item::u_reduce)
372 .unwrap_or(Self::Item::zero())
373 }
374
375 // early exit
376
377 /// Returns the first (or any) element of the iterator; returns None if it is empty.
378 ///
379 /// * first element is returned if default iteration order `IterationOrder::Ordered` is used,
380 /// * any element is returned if `IterationOrder::Arbitrary` is set.
381 ///
382 /// See the details here: [crate::ParIter::first].
383 fn first(self) -> Option<Self::Item>
384 where
385 Self::Item: Send;
386
387 /// Searches for an element of an iterator that satisfies a `predicate`.
388 ///
389 /// Unlike [crate::ParIter::find], the closure allows access to mutable reference of the used variable.
390 ///
391 /// Please see [`crate::ParIter::using`] transformation for details and examples.
392 ///
393 /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).
394 fn find<Predicate>(self, predicate: Predicate) -> Option<Self::Item>
395 where
396 Self::Item: Send,
397 Predicate: Fn(&mut U::Item, &Self::Item) -> bool + Sync,
398 {
399 self.filter(&predicate).first()
400 }
401}