Skip to content
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ target
*~
TAGS
*.bk
.idea
.idea
.devcontainer
16 changes: 16 additions & 0 deletions src/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ impl<'data, T: Sync + 'data, const N: usize> IntoParallelIterator for &'data [T;
fn into_par_iter(self) -> Self::Iter {
<&[T]>::into_par_iter(self)
}

fn const_length() -> Option<usize> {
Some(N)
}
}

impl<'data, T: Send + 'data, const N: usize> IntoParallelIterator for &'data mut [T; N] {
Expand All @@ -27,6 +31,10 @@ impl<'data, T: Send + 'data, const N: usize> IntoParallelIterator for &'data mut
fn into_par_iter(self) -> Self::Iter {
<&mut [T]>::into_par_iter(self)
}

fn const_length() -> Option<usize> {
Some(N)
}
}

impl<T: Send, const N: usize> IntoParallelIterator for [T; N] {
Expand All @@ -36,6 +44,10 @@ impl<T: Send, const N: usize> IntoParallelIterator for [T; N] {
fn into_par_iter(self) -> Self::Iter {
IntoIter { array: self }
}

fn const_length() -> Option<usize> {
Some(N)
}
}

/// Parallel iterator that moves out of an array.
Expand All @@ -57,6 +69,10 @@ impl<T: Send, const N: usize> ParallelIterator for IntoIter<T, N> {
fn opt_len(&self) -> Option<usize> {
Some(N)
}

fn const_length() -> Option<usize> {
Some(N)
}
}

impl<T: Send, const N: usize> IndexedParallelIterator for IntoIter<T, N> {
Expand Down
17 changes: 13 additions & 4 deletions src/iter/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ struct BlocksCallback<S, C> {

impl<T, S, C> ProducerCallback<T> for BlocksCallback<S, C>
where
C: UnindexedConsumer<T>,
C: Consumer<T>,
S: Iterator<Item = usize>,
{
type Output = C::Result;
Expand All @@ -20,7 +20,7 @@ where

// we need a local variable for the accumulated results
// we call the reducer's identity by splitting at 0
let (left_consumer, right_consumer, _) = consumer.split_at(0);
let (left_consumer, right_consumer, mut reducer) = consumer.split_at(0);
let mut leftmost_res = left_consumer.into_folder().complete();
consumer = right_consumer;

Expand All @@ -36,13 +36,14 @@ where
producer = right_producer;

// split the consumer
let (left_consumer, right_consumer, _) = consumer.split_at(capped_size);
let (left_consumer, right_consumer, next_reducer) = consumer.split_at(capped_size);
consumer = right_consumer;

leftmost_res = consumer.to_reducer().reduce(
leftmost_res = reducer.reduce(
leftmost_res,
bridge_producer_consumer(capped_size, left_producer, left_consumer),
);
reducer = next_reducer;
}
leftmost_res
}
Expand Down Expand Up @@ -85,6 +86,10 @@ where
};
self.base.with_producer(callback)
}

fn opt_len(&self) -> Option<usize> {
self.base.opt_len()
}
}

fn exponential_size(size: &usize) -> Option<usize> {
Expand Down Expand Up @@ -128,4 +133,8 @@ where
};
self.base.with_producer(callback)
}

fn opt_len(&self) -> Option<usize> {
self.base.opt_len()
}
}
4 changes: 4 additions & 0 deletions src/iter/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ where
fn opt_len(&self) -> Option<usize> {
self.a.opt_len()?.checked_add(self.b.opt_len()?)
}

fn const_length() -> Option<usize> {
A::const_length()?.checked_add(B::const_length()?)
}
}

impl<A, B> IndexedParallelIterator for Chain<A, B>
Expand Down
4 changes: 4 additions & 0 deletions src/iter/cloned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ where
fn opt_len(&self) -> Option<usize> {
self.base.opt_len()
}

fn const_length() -> Option<usize> {
I::const_length()
}
}

impl<'a, T, I> IndexedParallelIterator for Cloned<I>
Expand Down
4 changes: 4 additions & 0 deletions src/iter/copied.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ where
fn opt_len(&self) -> Option<usize> {
self.base.opt_len()
}

fn const_length() -> Option<usize> {
I::const_length()
}
}

impl<'a, T, I> IndexedParallelIterator for Copied<I>
Expand Down
4 changes: 4 additions & 0 deletions src/iter/empty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ impl<T: Send> ParallelIterator for Empty<T> {
fn opt_len(&self) -> Option<usize> {
Some(0)
}

fn const_length() -> Option<usize> {
Some(0)
}
}

impl<T: Send> IndexedParallelIterator for Empty<T> {
Expand Down
4 changes: 4 additions & 0 deletions src/iter/enumerate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ where
fn opt_len(&self) -> Option<usize> {
Some(self.len())
}

fn const_length() -> Option<usize> {
I::const_length()
}
}

impl<I> IndexedParallelIterator for Enumerate<I>
Expand Down
37 changes: 33 additions & 4 deletions src/iter/flat_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@ where
let consumer = FlatMapConsumer::new(consumer, &self.map_op);
self.base.drive_unindexed(consumer)
}

fn opt_len(&self) -> Option<usize> {
let base_len = self.base.opt_len()?;
let sub_len = PI::const_length()?;

base_len.checked_mul(sub_len)
}

fn const_length() -> Option<usize> {
let base_len = I::const_length()?;
let sub_len = PI::const_length()?;

base_len.checked_mul(sub_len)
}
}

/// ////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -70,7 +84,14 @@ where
type Result = C::Result;

fn split_at(self, index: usize) -> (Self, Self, C::Reducer) {
let (left, right, reducer) = self.base.split_at(index);
// FIXME: I have NO Idea if this is correct, it almost definately is NOT
// But the tests pass, and I no longer panic so that is a start
let (left, right, reducer) = if let Some(inner_len) = U::const_length() {
self.base.split_at(index * inner_len)
} else {
self.base.split_at(index)
};

(
FlatMapConsumer::new(left, self.map_op),
FlatMapConsumer::new(right, self.map_op),
Expand Down Expand Up @@ -123,19 +144,27 @@ where
fn consume(self, item: T) -> Self {
let map_op = self.map_op;
let par_iter = map_op(item).into_par_iter();
let consumer = self.base.split_off_left();
// TODO: This is a hack, to fake specialisation until it is in Rust proper
let (consumer, rest, reducer) = if let Some(inner_len) = U::const_length() {
// We can to use split_at
self.base.split_at(inner_len)
} else {
// Use the normal Unindexed version
let reducer = self.base.to_reducer();
(self.base.split_off_left(), self.base, reducer)
};

let result = par_iter.drive_unindexed(consumer);

let previous = match self.previous {
None => Some(result),
Some(previous) => {
let reducer = self.base.to_reducer();
Some(reducer.reduce(previous, result))
}
};

FlatMapFolder {
base: self.base,
base: rest,
map_op,
previous,
}
Expand Down
7 changes: 7 additions & 0 deletions src/iter/flatten.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ where
let consumer = FlattenConsumer::new(consumer);
self.base.drive_unindexed(consumer)
}

fn const_length() -> Option<usize> {
let base_len = I::const_length()?;
let sub_len = I::Item::const_length()?;

base_len.checked_mul(sub_len)
}
}

/// ////////////////////////////////////////////////////////////////////////
Expand Down
4 changes: 4 additions & 0 deletions src/iter/len.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ where
fn opt_len(&self) -> Option<usize> {
Some(self.len())
}

fn const_length() -> Option<usize> {
I::const_length()
}
}

impl<I> IndexedParallelIterator for MinLen<I>
Expand Down
4 changes: 4 additions & 0 deletions src/iter/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ where
fn opt_len(&self) -> Option<usize> {
self.base.opt_len()
}

fn const_length() -> Option<usize> {
I::const_length()
}
}

impl<I, F, R> IndexedParallelIterator for Map<I, F>
Expand Down
4 changes: 4 additions & 0 deletions src/iter/map_with.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ where
fn opt_len(&self) -> Option<usize> {
self.base.opt_len()
}

fn const_length() -> Option<usize> {
I::const_length()
}
}

impl<I, T, F, R> IndexedParallelIterator for MapWith<I, T, F>
Expand Down
17 changes: 17 additions & 0 deletions src/iter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@ pub trait IntoParallelIterator {
///
/// [`zip`]: trait.IndexedParallelIterator.html#method.zip
fn into_par_iter(self) -> Self::Iter;

/// Provides the length of the produced Iterator if known
fn const_length() -> Option<usize> {
None
}
}

/// `IntoParallelRefIterator` implements the conversion to a
Expand Down Expand Up @@ -2430,6 +2435,14 @@ pub trait ParallelIterator: Sized + Send {
fn opt_len(&self) -> Option<usize> {
None
}

/// Internal method used to define the behavior of this parallel
/// iterator. You should not need to call this directly.
///
/// Returns the constant length of Iterators of this type, if known
fn const_length() -> Option<usize> where Self: Sized {
None
}
}

impl<T: ParallelIterator> IntoParallelIterator for T {
Expand All @@ -2439,6 +2452,10 @@ impl<T: ParallelIterator> IntoParallelIterator for T {
fn into_par_iter(self) -> T {
self
}

fn const_length() -> Option<usize> {
<T as ParallelIterator>::const_length()
}
}

/// An iterator that supports "random access" to its data, meaning
Expand Down
4 changes: 4 additions & 0 deletions src/iter/once.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ impl<T: Send> ParallelIterator for Once<T> {
fn opt_len(&self) -> Option<usize> {
Some(1)
}

fn const_length() -> Option<usize> {
Some(1)
}
}

impl<T: Send> IndexedParallelIterator for Once<T> {
Expand Down
4 changes: 4 additions & 0 deletions src/iter/panic_fuse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ where
fn opt_len(&self) -> Option<usize> {
self.base.opt_len()
}

fn const_length() -> Option<usize> {
I::const_length()
}
}

impl<I> IndexedParallelIterator for PanicFuse<I>
Expand Down
4 changes: 4 additions & 0 deletions src/iter/rev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ where
fn opt_len(&self) -> Option<usize> {
Some(self.len())
}

fn const_length() -> Option<usize> {
I::const_length()
}
}

impl<I> IndexedParallelIterator for Rev<I>
Expand Down
4 changes: 4 additions & 0 deletions src/iter/zip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ where
fn opt_len(&self) -> Option<usize> {
Some(self.len())
}

fn const_length() -> Option<usize> {
Ord::min(A::const_length(), B::const_length())
}
}

impl<A, B> IndexedParallelIterator for Zip<A, B>
Expand Down
11 changes: 11 additions & 0 deletions src/par_either.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ where
fn opt_len(&self) -> Option<usize> {
self.as_ref().either(L::opt_len, R::opt_len)
}

fn const_length() -> Option<usize> {
let left_len = L::const_length()?;
let right_len = R::const_length()?;

if left_len == right_len {
Some(left_len)
} else {
None
}
}
}

impl<L, R> IndexedParallelIterator for Either<L, R>
Expand Down