Skip to content

Commit

Permalink
Generic implementation for Sum and Product
Browse files Browse the repository at this point in the history
The succestion came from @cupiver, and it was simple and elegant. Now it
should be possible to use `std::iter::{Sum, Product}` with everything
that can be Add`-ed and `Mul`-tiplied _against_ `BigInt` and `BigUint`
  • Loading branch information
dodomorandi committed Feb 22, 2018
1 parent 11e176e commit 348f82f
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 26 deletions.
42 changes: 16 additions & 26 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,42 +317,32 @@ macro_rules! promote_all_scalars {

macro_rules! impl_sum_iter_type {
($res:ty) => {
impl Sum for $res {
impl_sum_iter_type!($res, $res);
}

impl<'a> Sum<&'a $res> for $res {
impl_sum_iter_type!($res, &'a $res);
}
};

($res:ty, $item:ty) => {
fn sum<I>(iter: I) -> Self
impl<T> Sum<T> for $res
where
I: Iterator<Item = $item>
$res: Add<T, Output=Self>
{
iter.fold(Zero::zero(), <$res>::add)
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = T>
{
iter.fold(Zero::zero(), <$res>::add)
}
}
};
}

macro_rules! impl_product_iter_type {
($res:ty) => {
impl Product for $res {
impl_product_iter_type!($res, $res);
}

impl<'a> Product<&'a $res> for $res {
impl_product_iter_type!($res, &'a $res);
}
};

($res:ty, $item:ty) => {
fn product<I>(iter: I) -> Self
impl<T> Product<T> for $res
where
I: Iterator<Item = $item>
$res: Mul<T, Output=Self>
{
iter.fold(One::one(), <$res>::mul)
fn product<I>(iter: I) -> Self
where
I: Iterator<Item = T>
{
iter.fold(One::one(), <$res>::mul)
}
}
};
}
20 changes: 20 additions & 0 deletions src/tests/bigint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1225,3 +1225,23 @@ fn test_iter_product() {
assert_eq!(result, data.iter().product());
assert_eq!(result, data.into_iter().product());
}

#[test]
fn test_iter_sum_generic() {
let result: BigInt = FromPrimitive::from_isize(-1234567).unwrap();
let data = vec![-1000000, -200000, -30000, -4000, -500, -60, -7];

assert_eq!(result, data.iter().sum());
assert_eq!(result, data.into_iter().sum());
}

#[test]
fn test_iter_product_generic() {
let data = vec![1001, -1002, 1003, -1004, 1005];
let result = data[0].to_bigint().unwrap() * data[1].to_bigint().unwrap()
* data[2].to_bigint().unwrap() * data[3].to_bigint().unwrap()
* data[4].to_bigint().unwrap();

assert_eq!(result, data.iter().product());
assert_eq!(result, data.into_iter().product());
}
20 changes: 20 additions & 0 deletions src/tests/biguint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1709,3 +1709,23 @@ fn test_iter_product() {
assert_eq!(result, data.iter().product());
assert_eq!(result, data.into_iter().product());
}

#[test]
fn test_iter_sum_generic() {
let result: BigUint = FromPrimitive::from_isize(1234567).unwrap();
let data = vec![1000000_u32, 200000, 30000, 4000, 500, 60, 7];

assert_eq!(result, data.iter().sum());
assert_eq!(result, data.into_iter().sum());
}

#[test]
fn test_iter_product_generic() {
let data = vec![1001_u32, 1002, 1003, 1004, 1005];
let result = data[0].to_biguint().unwrap() * data[1].to_biguint().unwrap()
* data[2].to_biguint().unwrap() * data[3].to_biguint().unwrap()
* data[4].to_biguint().unwrap();

assert_eq!(result, data.iter().product());
assert_eq!(result, data.into_iter().product());
}

0 comments on commit 348f82f

Please sign in to comment.