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