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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
use super::wrappers::values::ConIterValues;
use crate::{next::Next, ConIterIdsAndValues, NextChunk, NextManyExact};
/// Trait defining a concurrent iterator with `next` and `next_id_and_chunk` methods which can safely be called my multiple threads concurrently.
pub trait ConcurrentIter: Send + Sync {
/// Type of the items that the iterator yields.
type Item: Send + Sync;
/// Advances the iterator and returns the next value together with its enumeration index.
///
/// Returns [None] when iteration is finished.
fn next_id_and_value(&self) -> Option<Next<Self::Item>>;
/// Advances the iterator `chunk_size` times and returns an iterator of at most `chunk_size` consecutive next values.
/// Further, the beginning enumeration index of the yielded values is returned.
///
/// This method:
/// * returns an iterator of `chunk_size` elements if there exists sufficient elements left in the iteration, or
/// * it might return an iterator of `m < chunk_size` elements if there exists only `m` elements left, or
/// * it might return an empty iterator.
///
/// This call would be equivalent to calling `next_id_and_value` method `chunk_size` times in a single-threaded execution.
/// However, calling `next` method `chunk_size` times in a concurrent execution does not guarantee to return `chunk_size` consecutive elements.
/// On the other hand, `next_id_and_chunk` guarantees that it returns consecutive elements, preventing any intermediate calls.
fn next_chunk(&self, chunk_size: usize) -> impl NextChunk<Self::Item>;
/// Advances the iterator and returns the next value.
///
/// Returns [None] when iteration is finished.
#[inline(always)]
fn next(&self) -> Option<Self::Item> {
self.next_id_and_value().map(|x| x.value)
}
/// Returns an `Iterator` over the values of elements of the concurrent iterator.
///
/// The iterator's `next` method does nothing but call the `next`; this iterator is only to allow for using `for` loops directly.
fn values(&self) -> ConIterValues<Self>
where
Self: Sized,
{
self.into()
}
/// Returns an `Iterator` over the ids and values of elements of the concurrent iterator.
///
/// The iterator's `next` method does nothing but call the `next_id_and_value`; this iterator is only to allow for using `for` loops directly.
fn ids_and_values(&self) -> ConIterIdsAndValues<Self>
where
Self: Sized,
{
self.into()
}
}
/// A concurrent iterator that knows its exact length.
pub trait ExactSizeConcurrentIter: ConcurrentIter {
/// Returns the exact remaining length of the concurrent iterator.
fn len(&self) -> usize;
/// Returns true if the iterator is empty.
fn is_empty(&self) -> bool {
self.len() == 0
}
/// Returns the next chunk with the requested `chunk_size`:
/// * Returns `None` if there are no more elements to yield.
/// * Returns `Some` of a [`crate::NextManyExact`] which contains the following information:
/// * `begin_idx`: the index of the first element to be yielded by the `values` iterator.
/// * `values`: an `ExactSizeIterator` with known `len` which is guaranteed to be positive and less than or equal to `chunk_size`.
fn next_exact_chunk(
&self,
chunk_size: usize,
) -> Option<NextManyExact<Self::Item, impl ExactSizeIterator<Item = Self::Item>>>;
}