use std::ops::{Add, AddAssign};
use num_traits::Zero;
#[cfg(feature = "parallel")]
use rayon::iter::ParallelIterator;
pub use crate::sum::ifastsum::IFastSum;
#[cfg(feature = "parallel")]
use crate::sum::SumConsumer;
pub trait SumAccumulator<F>: Add<F, Output = Self> + AddAssign<F> + From<F> + Clone {
fn zero() -> Self
where
F: Zero,
{
Self::from(F::zero())
}
fn sum(self) -> F;
fn absorb<I>(self, it: I) -> Self
where
I: IntoIterator<Item = F>,
{
it.into_iter().fold(self, |acc, x| acc + x)
}
}
pub trait SumWithAccumulator<F> {
fn sum_with_accumulator<Acc>(self) -> F
where
Acc: SumAccumulator<F>,
F: Zero;
}
impl<I, F> SumWithAccumulator<F> for I
where
I: IntoIterator<Item = F>,
{
fn sum_with_accumulator<Acc>(self) -> F
where
Acc: SumAccumulator<F>,
F: Zero,
{
Acc::zero().absorb(self).sum()
}
}
#[cfg(feature = "parallel")]
pub trait ParallelSumAccumulator<F>:
SumAccumulator<F> + Add<Self, Output = Self> + Send + Sized
{
#[inline]
fn into_consumer(self) -> SumConsumer<Self> {
SumConsumer(self)
}
}
#[cfg(feature = "parallel")]
impl<Acc, F> ParallelSumAccumulator<F> for Acc where
Acc: SumAccumulator<F> + Add<Acc, Output = Acc> + Send + Sized
{
}
#[cfg(feature = "parallel")]
pub trait ParallelSumWithAccumulator<F>: ParallelIterator<Item = F>
where
F: Send,
{
fn parallel_sum_with_accumulator<Acc>(self) -> F
where
Acc: ParallelSumAccumulator<F>,
F: Zero,
{
self.drive_unindexed(Acc::zero().into_consumer()).sum()
}
}
#[cfg(feature = "parallel")]
impl<T, F> ParallelSumWithAccumulator<F> for T
where
T: ParallelIterator<Item = F>,
F: Zero + Send,
{
}