orx_concurrent_iter/pullers/enumerated_item_puller.rs
1use crate::concurrent_iter::ConcurrentIter;
2
3/// A regular [`Iterator`] which is created from and linked to and
4/// pulls its elements from a [`ConcurrentIter`].
5///
6/// It can be created using the [`item_puller_with_idx`] method of a concurrent iterator.
7///
8/// This is similar to [`ItemPuller`] except that this iterator additionally returns the
9/// indices of the elements in the source concurrent iterator.
10///
11/// [`item_puller_with_idx`]: crate::ConcurrentIter::item_puller_with_idx
12/// [`ItemPuller`]: crate::ItemPuller
13///
14/// # Examples
15///
16/// See the [`ItemPuller`] for detailed examples.
17/// The following example only demonstrates the additional index that is returned by the
18/// next method of the `EnumeratedItemPuller`.
19///
20/// ```
21/// use orx_concurrent_iter::*;
22///
23/// let num_threads = 4;
24/// let data: Vec<_> = (0..100).map(|x| x.to_string()).collect();
25/// let con_iter = data.con_iter();
26///
27/// std::thread::scope(|s| {
28/// for _ in 0..num_threads {
29/// s.spawn(|| {
30/// for (idx, value) in con_iter.item_puller_with_idx() {
31/// assert_eq!(value, &idx.to_string());
32/// }
33/// });
34/// }
35/// });
36/// ```
37pub struct EnumeratedItemPuller<'a, I>
38where
39 I: ConcurrentIter,
40{
41 con_iter: &'a I,
42}
43
44impl<I: ConcurrentIter> EnumeratedItemPuller<'_, I> {
45 /// Behaves exactly as `next` but additionally provides `thread_idx` to the iterator.
46 /// This information might be useful for certain concurrent iterators, such as the
47 /// [recursive concurrent iterator](https://crates.io/crates/orx-concurrent-recursive-iter).
48 ///
49 /// Assuming a program using `n` threads that accesses this iterator, `thread_idx` is
50 /// assumed to be the internal ordering within this pool of threads taking values in
51 /// `0..n`.
52 #[inline(always)]
53 pub fn next_by(&mut self, thread_idx: usize) -> Option<(usize, I::Item)> {
54 self.con_iter.next_with_idx_by(thread_idx)
55 }
56}
57
58impl<'i, I> From<&'i I> for EnumeratedItemPuller<'i, I>
59where
60 I: ConcurrentIter,
61{
62 fn from(con_iter: &'i I) -> Self {
63 Self { con_iter }
64 }
65}
66
67impl<I> Iterator for EnumeratedItemPuller<'_, I>
68where
69 I: ConcurrentIter,
70{
71 type Item = (usize, I::Item);
72
73 #[inline(always)]
74 fn next(&mut self) -> Option<Self::Item> {
75 self.con_iter.next_with_idx()
76 }
77
78 fn size_hint(&self) -> (usize, Option<usize>) {
79 // lb: other threads might pull all of the elements, hence 0
80 // ub: we might pull all elements, hence ub(con_iter)
81 (0, self.con_iter.size_hint().1)
82 }
83
84 fn fold<B, F>(self, init: B, mut f: F) -> B
85 where
86 Self: Sized,
87 F: FnMut(B, Self::Item) -> B,
88 {
89 let mut acc = init;
90
91 while let Some(elem) = self.con_iter.next_with_idx() {
92 acc = f(acc, elem);
93 }
94
95 acc
96 }
97
98 fn count(self) -> usize
99 where
100 Self: Sized,
101 {
102 self.fold(0, |count, _| count + 1)
103 }
104}