orx_parallel/infallible_use/par.rs
1#![allow(clippy::type_complexity)]
2
3use crate::infallible::xap_variants::Id;
4use crate::infallible_use::fun::{UFnCloned, UFnCopied};
5use crate::infallible_use::par_core::ParUseCore;
6use crate::infallible_use::xap::FlattenOf;
7use crate::infallible_use::xap_variants::{IdUse, UDummyPair};
8use crate::infallible_use::{
9 FilMapOf, FilOf, FlatMapOf, InsOf, MapOf, MappedOf, ParUseIter, XapUse,
10};
11use crate::option_use::ParUseOptionIter;
12use crate::result_use::ParUseResultIter;
13use crate::runner::ParRunner;
14use crate::sizes::One;
15use crate::sizes::Size;
16use crate::use_var::{PairPtr, UseFold};
17use crate::{ChunkSize, IterationOrder, NumThreads, ParExtend, ParUseOption, ParUseResult, Sum};
18use alloc::vec::Vec;
19use core::cmp::Ordering;
20use orx_concurrent_iter::{ConcurrentIter, ExactSizeConcurrentIter};
21
22/// Parallel iterator pipelines with worker-local mutable state.
23///
24/// `ParUse` extends the usual parallel iterator pipeline with an associated
25/// [`Use`](crate::Use) value that is passed into transformation and reduction
26/// steps as mutable worker-local state. This is useful when each worker needs
27/// its own reusable scratch space, accumulator, or other per-thread context.
28///
29/// You can enter this mode from [`Par`](crate::Par) via
30/// [`use_new`](crate::Par::use_new),
31/// [`use_vec`](crate::Par::use_vec), or
32/// [`use_slice`](crate::Par::use_slice).
33///
34/// Related traits:
35/// - [`Par`](crate::Par) for pipelines without worker-local state,
36/// - [`ParUseOption`](crate::ParUseOption) via [`into_optional`](crate::ParUse::into_optional),
37/// - [`ParUseResult`](crate::ParUseResult) via [`into_fallible`](crate::ParUse::into_fallible).
38///
39/// # Examples
40///
41/// ```
42/// use orx_parallel::*;
43///
44/// let n = 10_000usize;
45/// let mut partial_sums = UseVec::new(|_| 0usize);
46///
47/// (0..n)
48/// .into_par()
49/// .use_vec(&mut partial_sums)
50/// .for_each(|thread_sum, x| *thread_sum += x);
51///
52/// let total: usize = partial_sums.into_vec().into_iter().sum();
53/// assert_eq!(total, (n - 1) * n / 2);
54/// ```
55///
56/// Using an RNG as mutable worker-local state:
57///
58/// ```
59/// use orx_parallel::*;
60/// use rand::prelude::*;
61/// use rand_chacha::ChaCha8Rng;
62///
63/// let values: Vec<_> = (0..128usize)
64/// .into_par()
65/// .use_new(|thread_idx| ChaCha8Rng::seed_from_u64(42 + thread_idx as u64))
66/// .map(|rng, x| x + rng.random_range(0..10))
67/// .collect();
68///
69/// assert_eq!(values.len(), 128);
70/// assert!(
71/// values
72/// .iter()
73/// .enumerate()
74/// .all(|(i, v)| *v >= i && *v < i + 10)
75/// );
76/// ```
77pub trait ParUse: Sized + ParUseCore {
78 // configuration
79
80 /// Replaces the current parallel runner with `runner`.
81 ///
82 /// This allows per-computation control over execution strategy.
83 ///
84 /// Please see [`Runner`](crate::Runner) for available runners.
85 ///
86 /// # Examples
87 ///
88 /// ```
89 /// use orx_parallel::*;
90 ///
91 /// let par = (1..101).par().use_new(|_| ());
92 ///
93 /// let par = par.runner(Runner::fixed());
94 ///
95 /// let sum = par.sum();
96 /// assert_eq!(sum, 5050);
97 /// ```
98 fn runner<Q: ParRunner>(
99 self,
100 runner: Q,
101 ) -> impl ParUse<Item = Self::Item, Use = Self::Use, Xap = Self::Xap, Input = Self::Input>;
102
103 #[cfg(feature = "std")]
104 /// Wraps the current runner with diagnostics-enabled execution.
105 ///
106 /// The resulting pipeline behaves the same, while also printing runtime
107 /// diagnostics at the end.
108 ///
109 /// # Examples
110 ///
111 /// ```
112 /// use orx_parallel::*;
113 ///
114 /// let par = (1..1001).par().use_new(|_| ());
115 ///
116 /// #[cfg(feature = "std")]
117 /// let par = par.runner_with_diagnostics();
118 ///
119 /// let sum = par.sum();
120 /// assert_eq!(sum, 500500);
121 /// ```
122 fn runner_with_diagnostics(
123 self,
124 ) -> impl ParUse<Item = Self::Item, Use = Self::Use, Xap = Self::Xap, Input = Self::Input>;
125
126 /// Sets the maximum number of worker threads for this computation.
127 ///
128 /// Integer values map as follows:
129 /// - `0` => automatic (default)
130 /// - `n > 0` => at most `n` threads
131 ///
132 /// # Examples
133 ///
134 /// ```
135 /// use orx_parallel::*;
136 ///
137 /// let sum: usize = (1..11)
138 /// .into_par()
139 /// .use_new(|_| ())
140 /// .num_threads(1)
141 /// .sum();
142 ///
143 /// assert_eq!(sum, 55);
144 /// ```
145 fn num_threads(self, num_threads: impl Into<NumThreads>) -> Self;
146
147 /// Sets chunk size used when pulling items from the concurrent input.
148 ///
149 /// Integer values map as follows:
150 /// - `0` => automatic (default)
151 /// - `n > 0` => exact chunk size `n`
152 ///
153 /// # Examples
154 ///
155 /// ```
156 /// use orx_parallel::*;
157 ///
158 /// let values: Vec<_> = (0..16)
159 /// .into_par()
160 /// .use_new(|_| ())
161 /// .chunk_size(4)
162 /// .map(|_, x| x + 1)
163 /// .collect();
164 ///
165 /// assert_eq!(values.len(), 16);
166 /// assert_eq!(values[0], 1);
167 /// ```
168 fn chunk_size(self, chunk_size: impl Into<ChunkSize>) -> Self;
169
170 /// Sets iteration order semantics for order-sensitive operations.
171 ///
172 /// With `Ordered` (default), methods like `first` and `find` follow input
173 /// position. With `Arbitrary`, any matching item found first in parallel
174 /// execution may be returned.
175 ///
176 /// # Examples
177 ///
178 /// ```
179 /// use orx_parallel::*;
180 ///
181 /// let ordered = (1..10_000)
182 /// .into_par()
183 /// .use_new(|_| ())
184 /// .iteration_order(IterationOrder::Ordered)
185 /// .find(|_, x| x % 3421 == 0);
186 /// assert_eq!(ordered, Some(3421));
187 ///
188 /// let any = (1..10_000)
189 /// .into_par()
190 /// .use_new(|_| ())
191 /// .iteration_order(IterationOrder::Arbitrary)
192 /// .find(|_, x| x % 3421 == 0)
193 /// .unwrap();
194 /// assert!([3421, 6842].contains(&any));
195 /// ```
196 fn iteration_order(self, collect: IterationOrder) -> Self;
197
198 // kind transformations
199
200 /// Converts `ParUse<Item = Option<T>>` into [`ParUseOption`](crate::ParUseOption).
201 ///
202 /// The result short-circuits to `None` if any element is `None`.
203 ///
204 /// # Examples
205 ///
206 /// ```
207 /// use orx_parallel::*;
208 ///
209 /// let ok: Option<Vec<_>> = ["1", "2", "3"]
210 /// .into_par()
211 /// .use_new(|_| ())
212 /// .map(|_, s| s.parse::<i32>().ok())
213 /// .into_optional()
214 /// .map(|_, x| x * 2)
215 /// .collect();
216 /// assert_eq!(ok, Some(vec![2, 4, 6]));
217 ///
218 /// let fail: Option<Vec<_>> = ["1", "x", "3"]
219 /// .into_par()
220 /// .use_new(|_| ())
221 /// .map(|_, s| s.parse::<i32>().ok())
222 /// .into_optional()
223 /// .map(|_, x| x * 2)
224 /// .collect();
225 /// assert_eq!(fail, None);
226 /// ```
227 fn into_optional<T>(
228 self,
229 ) -> impl ParUseOption<
230 Elem = T,
231 Use = Self::Use,
232 Xap1 = Self::Xap,
233 M = T,
234 Xap2 = IdUse<Id<T>, Self::Use>,
235 Input = Self::Input,
236 Size = <<Self::Xap as XapUse>::Size as Size>::IntoPair,
237 >
238 where
239 Self::Xap: XapUse<U = Self::Use, I = <Self::Input as ConcurrentIter>::Item, O = Option<T>>,
240 {
241 let (u, iter, xap, exe, params) = self.destruct();
242 ParUseOptionIter::new(u, iter, xap, IdUse::new(Id::new()), exe, params)
243 }
244
245 /// Converts `ParUse<Item = Result<T, E>>` into [`ParUseResult`](crate::ParUseResult).
246 ///
247 /// The result short-circuits and returns the first observed error.
248 ///
249 /// # Examples
250 ///
251 /// ```
252 /// use orx_parallel::*;
253 ///
254 /// let ok: Result<Vec<_>, _> = ["1", "2", "3"]
255 /// .into_par()
256 /// .use_new(|_| ())
257 /// .map(|_, s| s.parse::<i32>())
258 /// .into_fallible()
259 /// .map(|_, x| x * 2)
260 /// .collect();
261 /// assert_eq!(ok, Ok(vec![2, 4, 6]));
262 ///
263 /// let fail: Result<Vec<_>, _> = ["1", "x", "3"]
264 /// .into_par()
265 /// .use_new(|_| ())
266 /// .map(|_, s| s.parse::<i32>())
267 /// .into_fallible()
268 /// .map(|_, x| x * 2)
269 /// .collect();
270 /// assert!(fail.is_err());
271 /// ```
272 fn into_fallible<T, E>(
273 self,
274 ) -> impl ParUseResult<
275 Elem = T,
276 Error = E,
277 Use = Self::Use,
278 Xap1 = Self::Xap,
279 M = T,
280 Xap2 = IdUse<Id<T>, Self::Use>,
281 Input = Self::Input,
282 Size = <<Self::Xap as XapUse>::Size as Size>::IntoPair,
283 >
284 where
285 Self::Xap:
286 XapUse<U = Self::Use, I = <Self::Input as ConcurrentIter>::Item, O = Result<T, E>>,
287 {
288 let (u, iter, xap, exe, params) = self.destruct();
289 ParUseResultIter::new(u, iter, xap, IdUse::new(Id::new()), exe, params)
290 }
291
292 /// Copies elements of a reference iterator.
293 ///
294 /// Equivalent to `.map(|_, &x| x)`.
295 ///
296 /// # Examples
297 ///
298 /// ```
299 /// use orx_parallel::*;
300 ///
301 /// let data = vec![1, 2, 3];
302 /// let copied: Vec<_> = data.par().use_new(|_| ()).copied().collect();
303 ///
304 /// assert_eq!(copied, vec![1, 2, 3]);
305 /// ```
306 fn copied<'a, O>(
307 self,
308 ) -> impl ParUse<
309 Item = O,
310 Use = Self::Use,
311 Xap = MappedOf<Self::Xap, UFnCopied<'a, Self::Use, O>>,
312 Input = Self::Input,
313 >
314 where
315 Self: ParUse<Item = &'a O>,
316 O: Copy + 'a,
317 Self::Use: 'a,
318 {
319 let (u, iter, xap, exe, params) = self.destruct();
320 ParUseIter::new(u, iter, xap.mapped(UFnCopied::new()), exe, params)
321 }
322
323 /// Clones elements of a reference iterator.
324 ///
325 /// Equivalent to `.map(|_, x| x.clone())`.
326 ///
327 /// # Examples
328 ///
329 /// ```
330 /// use orx_parallel::*;
331 ///
332 /// let data = vec!["a".to_string(), "b".to_string()];
333 /// let cloned: Vec<_> = data.par().use_new(|_| ()).cloned().collect();
334 ///
335 /// assert_eq!(cloned, vec!["a".to_string(), "b".to_string()]);
336 /// ```
337 fn cloned<'a, O>(
338 self,
339 ) -> impl ParUse<
340 Item = O,
341 Use = Self::Use,
342 Xap = MappedOf<Self::Xap, UFnCloned<'a, Self::Use, O>>,
343 Input = Self::Input,
344 >
345 where
346 Self: ParUse<Item = &'a O>,
347 O: Clone + 'a,
348 Self::Use: 'a,
349 {
350 let (u, iter, xap, exe, params) = self.destruct();
351 ParUseIter::new(u, iter, xap.mapped(UFnCloned::new()), exe, params)
352 }
353
354 // transformations
355
356 /// Maps each element with closure `h`.
357 ///
358 /// # Examples
359 ///
360 /// ```
361 /// use orx_parallel::*;
362 ///
363 /// let doubled: Vec<_> = (1..4)
364 /// .into_par()
365 /// .use_new(|_| ())
366 /// .map(|_, x| 2 * x)
367 /// .collect();
368 ///
369 /// assert_eq!(doubled, vec![2, 4, 6]);
370 /// ```
371 fn map<Q, H>(
372 self,
373 h: H,
374 ) -> impl ParUse<Item = Q, Use = Self::Use, Xap = MapOf<Self::Xap, Q, H>, Input = Self::Input>
375 where
376 H: Fn(&mut Self::Use, Self::Item) -> Q + Copy + Send;
377
378 /// Runs `h` on each element and forwards the item unchanged.
379 ///
380 /// Useful for logging, metrics, and tracing with worker-local state.
381 ///
382 /// # Examples
383 ///
384 /// ```
385 /// use orx_parallel::*;
386 ///
387 /// let mut calls = UseVec::new(|_| 0usize);
388 ///
389 /// let out: Vec<_> = (1..5)
390 /// .into_par()
391 /// .use_vec(&mut calls)
392 /// .inspect(|count, _| *count += 1)
393 /// .collect();
394 ///
395 /// assert_eq!(out, vec![1, 2, 3, 4]);
396 /// assert_eq!(calls.into_vec().into_iter().sum::<usize>(), 4);
397 /// ```
398 fn inspect<H>(
399 self,
400 h: H,
401 ) -> impl ParUse<Item = Self::Item, Use = Self::Use, Xap = InsOf<Self::Xap, H>, Input = Self::Input>
402 where
403 H: Fn(&mut Self::Use, &Self::Item) + Copy + Send;
404
405 /// Keeps only elements satisfying predicate `h`.
406 ///
407 /// # Examples
408 ///
409 /// ```
410 /// use orx_parallel::*;
411 ///
412 /// let odds: Vec<_> = (1..7)
413 /// .into_par()
414 /// .use_new(|_| ())
415 /// .filter(|_, x| x % 2 == 1)
416 /// .collect();
417 ///
418 /// assert_eq!(odds, vec![1, 3, 5]);
419 /// ```
420 fn filter<H>(
421 self,
422 h: H,
423 ) -> impl ParUse<Item = Self::Item, Use = Self::Use, Xap = FilOf<Self::Xap, H>, Input = Self::Input>
424 where
425 H: Fn(&mut Self::Use, &Self::Item) -> bool + Copy + Send;
426
427 /// Maps and filters in a single pass.
428 ///
429 /// Returns mapped values for elements where `h` returns `Some(_)`.
430 ///
431 /// # Examples
432 ///
433 /// ```
434 /// use orx_parallel::*;
435 ///
436 /// let nums: Vec<_> = ["1", "x", "5"]
437 /// .into_par()
438 /// .use_new(|_| ())
439 /// .filter_map(|_, s| s.parse::<usize>().ok())
440 /// .collect();
441 ///
442 /// assert_eq!(nums, vec![1, 5]);
443 /// ```
444 fn filter_map<Q, H>(
445 self,
446 h: H,
447 ) -> impl ParUse<Item = Q, Use = Self::Use, Xap = FilMapOf<Self::Xap, Q, H>, Input = Self::Input>
448 where
449 H: Fn(&mut Self::Use, Self::Item) -> Option<Q> + Copy + Send;
450
451 /// Maps each element to an iterator and flattens one level.
452 ///
453 /// # Examples
454 ///
455 /// ```
456 /// use orx_parallel::*;
457 ///
458 /// let out: Vec<_> = (1..4)
459 /// .into_par()
460 /// .use_new(|_| ())
461 /// .flat_map(|_, x| [x, x + 10])
462 /// .collect();
463 ///
464 /// assert_eq!(out, vec![1, 11, 2, 12, 3, 13]);
465 /// ```
466 fn flat_map<V, H>(
467 self,
468 h: H,
469 ) -> impl ParUse<
470 Item = V::Item,
471 Use = Self::Use,
472 Xap = FlatMapOf<Self::Xap, V, H>,
473 Input = Self::Input,
474 >
475 where
476 V: IntoIterator,
477 H: Fn(&mut Self::Use, Self::Item) -> V + Copy + Send;
478
479 /// Flattens one level of nested iterables.
480 ///
481 /// # Examples
482 ///
483 /// ```
484 /// use orx_parallel::*;
485 ///
486 /// let nested = vec![vec![1, 2], vec![3, 4]];
487 /// let flat: Vec<_> = nested.into_par().use_new(|_| ()).flatten().collect();
488 ///
489 /// assert_eq!(flat, vec![1, 2, 3, 4]);
490 /// ```
491 fn flatten(
492 self,
493 ) -> impl ParUse<
494 Item = <Self::Item as IntoIterator>::Item,
495 Use = Self::Use,
496 Xap = FlattenOf<Self::Xap>,
497 Input = Self::Input,
498 >
499 where
500 Self::Item: IntoIterator;
501
502 // get
503
504 /// Returns a lower and optional upper bound on the number of output items.
505 ///
506 /// The bounds follow the usual [`Iterator::size_hint`] convention. For an
507 /// exact-size input and a one-to-one transformation, both bounds are exact.
508 /// Transformations such as `filter` may reduce the lower bound while keeping
509 /// the input length as the upper bound.
510 ///
511 /// # Examples
512 ///
513 /// ```
514 /// use orx_parallel::*;
515 ///
516 /// let mapped = (0..4)
517 /// .into_par()
518 /// .use_new(|_| ())
519 /// .map(|_, x| x * 2);
520 /// assert_eq!(mapped.size_hint(), (4, Some(4)));
521 ///
522 /// let filtered = (0..4)
523 /// .into_par()
524 /// .use_new(|_| ())
525 /// .filter(|_, x| x % 2 == 0);
526 /// assert_eq!(filtered.size_hint(), (0, Some(4)));
527 /// ```
528 fn size_hint(&self) -> (usize, Option<usize>);
529
530 /// Returns the exact number of output items.
531 fn len(&self) -> usize
532 where
533 Self::Input: ExactSizeConcurrentIter,
534 Self::Xap: XapUse<Size = One>,
535 {
536 self.size_hint().0
537 }
538
539 /// Returns `true` when the parallel iterator has no output items.
540 fn is_empty(&self) -> bool
541 where
542 Self::Input: ExactSizeConcurrentIter,
543 Self::Xap: XapUse<Size = One>,
544 {
545 self.len() == 0
546 }
547
548 // compute
549
550 /// Returns the first item according to iteration order, or `None` if empty.
551 ///
552 /// With [`IterationOrder::Ordered`] (default), this is the earliest matching
553 /// item by input position. With [`IterationOrder::Arbitrary`], this may be
554 /// any matching item reached first in parallel execution.
555 ///
556 /// # Examples
557 ///
558 /// ```
559 /// use orx_parallel::*;
560 ///
561 /// assert_eq!(Vec::<usize>::new().into_par().use_new(|_| ()).first(), None);
562 /// assert_eq!((1..4).into_par().use_new(|_| ()).first(), Some(1));
563 /// ```
564 fn first(self) -> Option<Self::Item>
565 where
566 Self::Item: Send;
567
568 /// Reduces items into one value using reducer `f`.
569 ///
570 /// Returns `None` for an empty iterator.
571 ///
572 /// # Examples
573 ///
574 /// ```
575 /// use orx_parallel::*;
576 ///
577 /// let reduced = (1..6)
578 /// .into_par()
579 /// .use_new(|_| ())
580 /// .reduce(|_, a, b| a + b);
581 ///
582 /// assert_eq!(reduced, Some(15));
583 /// ```
584 fn reduce<F>(self, f: F) -> Option<Self::Item>
585 where
586 F: Fn(&mut Self::Use, Self::Item, Self::Item) -> Self::Item + Send + Copy,
587 Self::Item: Send;
588
589 /// Collects all items into `dst`.
590 ///
591 /// # Examples
592 ///
593 /// ```
594 /// use orx_parallel::*;
595 ///
596 /// let mut dst = vec![10];
597 /// (0..3).into_par().use_new(|_| ()).collect_into(&mut dst);
598 /// assert_eq!(dst, vec![10, 0, 1, 2]);
599 /// ```
600 fn collect_into<P>(self, dst: &mut P)
601 where
602 P: ParExtend<Self::Item>,
603 Self::Item: Send;
604
605 /// Collects all items into a new collection.
606 ///
607 /// # Examples
608 ///
609 /// ```
610 /// use orx_parallel::*;
611 ///
612 /// let out: Vec<_> = (1..4)
613 /// .into_par()
614 /// .use_new(|_| ())
615 /// .map(|_, x| x * 2)
616 /// .collect();
617 ///
618 /// assert_eq!(out, vec![2, 4, 6]);
619 /// ```
620 fn collect<P>(self) -> P
621 where
622 P: ParExtend<Self::Item> + Default,
623 Self::Item: Send,
624 {
625 let mut dst = P::default();
626 self.collect_into(&mut dst);
627 dst
628 }
629
630 // compute - derived
631
632 /// Returns `true` if all items satisfy predicate `f`.
633 ///
634 /// Empty iterators return `true`.
635 ///
636 /// # Examples
637 ///
638 /// ```
639 /// use orx_parallel::*;
640 ///
641 /// assert!((1..5).into_par().use_new(|_| ()).all(|_, x| x > &0));
642 /// assert!(!(1..5).into_par().use_new(|_| ()).all(|_, x| x % 2 == 0));
643 /// ```
644 fn all<F>(self, f: F) -> bool
645 where
646 F: Fn(&mut Self::Use, &Self::Item) -> bool + Sync,
647 {
648 self.map(|u, x| f(u, &x)).find(|_, x| !*x).is_none()
649 }
650
651 /// Returns `true` if any item satisfies predicate `f`.
652 ///
653 /// Empty iterators return `false`.
654 ///
655 /// # Examples
656 ///
657 /// ```
658 /// use orx_parallel::*;
659 ///
660 /// assert!((1..5).into_par().use_new(|_| ()).any(|_, x| x % 2 == 0));
661 /// assert!(!(1..5).into_par().use_new(|_| ()).any(|_, x| x > &10));
662 /// ```
663 fn any<F>(self, f: F) -> bool
664 where
665 F: Fn(&mut Self::Use, &Self::Item) -> bool + Sync,
666 {
667 self.map(|u, x| f(u, &x)).find(|_, x| *x).is_some()
668 }
669
670 /// Counts elements.
671 ///
672 /// # Examples
673 ///
674 /// ```
675 /// use orx_parallel::*;
676 ///
677 /// let n = (1..11)
678 /// .into_par()
679 /// .use_new(|_| ())
680 /// .filter(|_, x| x % 3 == 0)
681 /// .count();
682 ///
683 /// assert_eq!(n, 3);
684 /// ```
685 fn count(self) -> usize {
686 self.map(|_, _| 1).reduce(|_, a, b| a + b).unwrap_or(0)
687 }
688
689 /// Finds first (ordered) or any (arbitrary) item satisfying predicate `f`.
690 ///
691 /// Equivalent to `self.filter(f).first()`.
692 ///
693 /// # Examples
694 ///
695 /// ```
696 /// use orx_parallel::*;
697 ///
698 /// let found = (1..101)
699 /// .into_par()
700 /// .use_new(|_| ())
701 /// .find(|_, x| x % 17 == 0);
702 ///
703 /// assert_eq!(found, Some(17));
704 /// ```
705 fn find<F>(self, f: F) -> Option<Self::Item>
706 where
707 Self::Item: Send,
708 F: Fn(&mut Self::Use, &Self::Item) -> bool + Sync,
709 {
710 self.filter(&f).first()
711 }
712
713 /// Folds elements into per-thread accumulators and returns them.
714 ///
715 /// The output contains one accumulator for each participating worker.
716 ///
717 /// # Examples
718 ///
719 /// ```
720 /// use orx_parallel::*;
721 ///
722 /// let num_threads = 4;
723 /// let partials: Vec<usize> = (1..6)
724 /// .into_par()
725 /// .use_new(|_| ())
726 /// .num_threads(num_threads)
727 /// .fold(|| 0usize, |_, acc, x| *acc += x);
728 ///
729 /// assert!(partials.len() <= num_threads);
730 /// assert_eq!(partials.iter().sum::<usize>(), 15);
731 /// ```
732 fn fold<B, I, F>(self, init: I, f: F) -> Vec<B>
733 where
734 B: Send,
735 I: Fn() -> B + Sync,
736 F: Fn(&mut Self::Use, &mut B, Self::Item) + Copy + Send,
737 {
738 let (u, iter, xap, exe, params) = self.destruct();
739 let mut use_fold = UseFold::new(u, |_| init());
740 let xap = UDummyPair::<Self::Xap, B>::new(xap);
741 let par = ParUseIter::new(&mut use_fold, iter, xap, exe, params);
742
743 par.for_each(move |a: &mut PairPtr<Self::Use, B>, x| {
744 let (u, v) = a.u_v_mut();
745 f(u, v, x);
746 });
747
748 use_fold.into_vec()
749 }
750
751 /// Executes `f` for each item.
752 ///
753 /// # Examples
754 ///
755 /// ```
756 /// use orx_parallel::*;
757 ///
758 /// let mut sums = UseVec::new(|_| 0usize);
759 ///
760 /// (1..5)
761 /// .into_par()
762 /// .use_vec(&mut sums)
763 /// .for_each(|local, x| *local += x);
764 ///
765 /// assert_eq!(sums.into_vec().into_iter().sum::<usize>(), 10);
766 /// ```
767 fn for_each<F>(self, f: F)
768 where
769 F: Fn(&mut Self::Use, Self::Item) + Send + Copy,
770 {
771 let _ = self.map(f).reduce(|_, _, _| {});
772 }
773
774 /// Returns maximum element, or `None` if empty.
775 ///
776 /// # Examples
777 ///
778 /// ```
779 /// use orx_parallel::*;
780 ///
781 /// assert_eq!((1..5).into_par().use_new(|_| ()).max(), Some(4));
782 /// assert_eq!(Vec::<usize>::new().into_par().use_new(|_| ()).max(), None);
783 /// ```
784 fn max(self) -> Option<Self::Item>
785 where
786 Self::Item: Ord + Send,
787 {
788 self.reduce(|_, a, b| Ord::max(a, b))
789 }
790
791 /// Returns element considered maximum by comparator `f`.
792 ///
793 /// # Examples
794 ///
795 /// ```
796 /// use core::cmp::Ordering;
797 /// use orx_parallel::*;
798 ///
799 /// let x = vec![-3_i32, 0, 1, 5, -10]
800 /// .into_par()
801 /// .use_new(|_| ())
802 /// .max_by(|_, a, b| a.cmp(b));
803 /// assert_eq!(x, Some(5));
804 /// ```
805 fn max_by<F>(self, f: F) -> Option<Self::Item>
806 where
807 Self::Item: Send,
808 F: Fn(&mut Self::Use, &Self::Item, &Self::Item) -> Ordering + Sync,
809 {
810 let reduce = |u: &mut Self::Use, x, y| match f(u, &x, &y) {
811 Ordering::Greater | Ordering::Equal => x,
812 Ordering::Less => y,
813 };
814 self.reduce(reduce)
815 }
816
817 /// Returns element with maximum key value.
818 ///
819 /// # Examples
820 ///
821 /// ```
822 /// use orx_parallel::*;
823 ///
824 /// let x = vec![-3_i32, 0, 1, 5, -10]
825 /// .into_par()
826 /// .use_new(|_| ())
827 /// .max_by_key(|_, x| x.abs());
828 /// assert_eq!(x, Some(-10));
829 /// ```
830 fn max_by_key<B, F>(self, f: F) -> Option<Self::Item>
831 where
832 Self::Item: Send,
833 B: Ord,
834 F: Fn(&mut Self::Use, &Self::Item) -> B + Sync,
835 {
836 let reduce = |u: &mut Self::Use, x, y| match f(u, &x).cmp(&f(u, &y)) {
837 Ordering::Greater | Ordering::Equal => x,
838 Ordering::Less => y,
839 };
840 self.reduce(reduce)
841 }
842
843 /// Returns minimum element, or `None` if empty.
844 ///
845 /// # Examples
846 ///
847 /// ```
848 /// use orx_parallel::*;
849 ///
850 /// assert_eq!((1..5).into_par().use_new(|_| ()).min(), Some(1));
851 /// assert_eq!(Vec::<usize>::new().into_par().use_new(|_| ()).min(), None);
852 /// ```
853 fn min(self) -> Option<Self::Item>
854 where
855 Self::Item: Ord + Send,
856 {
857 self.reduce(|_, a, b| Ord::min(a, b))
858 }
859
860 /// Returns element considered minimum by comparator `f`.
861 ///
862 /// # Examples
863 ///
864 /// ```
865 /// use orx_parallel::*;
866 ///
867 /// let x = vec![-3_i32, 0, 1, 5, -10]
868 /// .into_par()
869 /// .use_new(|_| ())
870 /// .min_by(|_, a, b| a.cmp(b));
871 /// assert_eq!(x, Some(-10));
872 /// ```
873 fn min_by<F>(self, f: F) -> Option<Self::Item>
874 where
875 Self::Item: Send,
876 F: Fn(&mut Self::Use, &Self::Item, &Self::Item) -> Ordering + Sync,
877 {
878 let reduce = |u: &mut Self::Use, x, y| match f(u, &x, &y) {
879 Ordering::Less | Ordering::Equal => x,
880 Ordering::Greater => y,
881 };
882 self.reduce(reduce)
883 }
884
885 /// Returns element with minimum key value.
886 ///
887 /// # Examples
888 ///
889 /// ```
890 /// use orx_parallel::*;
891 ///
892 /// let x = vec![-3_i32, 0, 1, 5, -10]
893 /// .into_par()
894 /// .use_new(|_| ())
895 /// .min_by_key(|_, x| x.abs());
896 /// assert_eq!(x, Some(0));
897 /// ```
898 fn min_by_key<B, F>(self, f: F) -> Option<Self::Item>
899 where
900 Self::Item: Send,
901 B: Ord,
902 F: Fn(&mut Self::Use, &Self::Item) -> B + Sync,
903 {
904 let reduce = |u: &mut Self::Use, x, y| match f(u, &x).cmp(&f(u, &y)) {
905 Ordering::Less | Ordering::Equal => x,
906 Ordering::Greater => y,
907 };
908 self.reduce(reduce)
909 }
910
911 /// Sums elements using [`Sum`] implementation of the item type.
912 ///
913 /// Empty iterators return additive identity (`zero`).
914 ///
915 /// # Examples
916 ///
917 /// ```
918 /// use orx_parallel::*;
919 ///
920 /// let sum: usize = (1..5).into_par().use_new(|_| ()).sum();
921 /// assert_eq!(sum, 10);
922 /// ```
923 fn sum<S>(self) -> S
924 where
925 Self::Item: Sum<S>,
926 S: Send,
927 {
928 self.map(|_, x| Self::Item::owned(x))
929 .reduce(|_, a, b| Self::Item::add(a, b))
930 .unwrap_or(Self::Item::zero())
931 }
932}