1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
use super::atomic_counter::AtomicCounter;
use crate::next::{Next, NextChunk};

/// Trait defining a set of concurrent iterators which internally uses an atomic counter of elements to be yielded.
///
/// Note that every `A: AtomicIter` also implements `ConcurrentIter`.
pub trait AtomicIter<T: Send + Sync>: Send + Sync {
    /// Returns a reference to the underlying advanced item counter.
    fn counter(&self) -> &AtomicCounter;

    /// Progresses the atomic counter by `number_to_fetch` elements and returns the beginning index of the elements to be fetched.
    /// Returns None if the iterator is terminated and there are no more elements to be fetched.
    ///
    /// Note that this method must only return when the calling thread is allowed to fetch elements.
    fn progress_and_get_begin_idx(&self, number_to_fetch: usize) -> Option<usize>;

    /// Returns the `item_idx`-th item that the iterator yields; returns None if the iterator completes before.
    fn get(&self, item_idx: usize) -> Option<T>;

    /// Returns the next item that the iterator yields; returns None if the iteration has completed.
    #[inline(always)]
    fn fetch_one(&self) -> Option<Next<T>> {
        let idx = self.counter().fetch_and_increment();
        self.get(idx).map(|value| Next { idx, value })
    }

    /// Returns an iterator of the next `n` **consecutive items** that the iterator yields.
    /// It might return an iterator of less or no items if the iteration does not have sufficient elements left.
    fn fetch_n(&self, n: usize) -> Option<NextChunk<T, impl ExactSizeIterator<Item = T>>>;

    /// Skips all remaining elements of the iterator and assumes that the end of the iterator is reached.
    ///
    /// This method establishes a very primitive, convenient and critical communication among threads for search scenarios with an early exit condition.
    /// Assume, for instance, that we are trying to `find` an element satisfying a predicate using multiple threads.
    /// Whenever a threads finds a match, it can call this method and return the found value.
    /// Then, when the other threads try to pull next element from the iterator, they will observe that the iterator has ended.
    /// Therefore, they will as well return early as desired.
    fn early_exit(&self);
}

/// An atomic counter based iterator with exactly known initial length.
pub trait AtomicIterWithInitialLen<T: Send + Sync>: AtomicIter<T> {
    /// Returns the initial length of the atomic iterator.
    fn initial_len(&self) -> usize;
}