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}