From 88427605bbd3271d52d064f339e344da2892b9cb Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 12 Mar 2015 00:13:37 +0100 Subject: [PATCH] Make `AdditiveIterator` and `MultiplicativeIterator` extensible Previously it could not be implemented for types outside `libcore/iter.rs` due to coherence issues. --- src/libcore/iter.rs | 130 +++++++++++++++++++++++++++++++------------- 1 file changed, 93 insertions(+), 37 deletions(-) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 939d9b4ab0ec4..52bad579f47d1 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -1225,7 +1225,10 @@ impl RandomAccessIterator for Rev /// A trait for iterators over elements which can be added together #[unstable(feature = "core", reason = "needs to be re-evaluated as part of numerics reform")] -pub trait AdditiveIterator { +pub trait AdditiveIterator { + /// The result of summing over the iterator. + type SumResult; + /// Iterates over the entire iterator, summing up all the elements /// /// # Examples @@ -1238,37 +1241,65 @@ pub trait AdditiveIterator { /// let mut it = a.iter().cloned(); /// assert!(it.sum() == 15); /// ``` - fn sum(self) -> A; + fn sum(self) -> Self::SumResult; +} + +/// The sum operation of an iterator's item type. Implementing this allows +/// calling `.sum()` on the iterator. +#[unstable(feature = "core", reason = "trait is experimental")] +pub trait AdditiveIteratorItem { + /// The type of the intermediate sums. + type SumResult; + /// The start value of the sum, usually something like `0`. + fn start() -> Self::SumResult; + /// Adds another element of the iterator to the intermediate sum. + fn combine(self, other: Self::SumResult) -> Self::SumResult; +} + +#[unstable(feature = "core", reason = "trait is experimental")] +impl AdditiveIterator for I where + ::Item: AdditiveIteratorItem +{ + type SumResult = <::Item as AdditiveIteratorItem>::SumResult; + fn sum(self) -> ::SumResult { + let mut sum = <::Item as AdditiveIteratorItem>::start(); + for x in self { + sum = x.combine(sum); + } + sum + } } macro_rules! impl_additive { - ($A:ty, $init:expr) => { + ($T:ty, $init:expr) => { #[unstable(feature = "core", reason = "trait is experimental")] - impl> AdditiveIterator<$A> for T { - #[inline] - fn sum(self) -> $A { - self.fold($init, |acc, x| acc + x) - } + impl AdditiveIteratorItem for $T { + type SumResult = $T; + fn start() -> $T { $init } + fn combine(self, other: $T) -> $T { self + other } } }; } -impl_additive! { i8, 0 } -impl_additive! { i16, 0 } -impl_additive! { i32, 0 } -impl_additive! { i64, 0 } -impl_additive! { isize, 0 } -impl_additive! { u8, 0 } -impl_additive! { u16, 0 } -impl_additive! { u32, 0 } -impl_additive! { u64, 0 } +impl_additive! { i8, 0 } +impl_additive! { i16, 0 } +impl_additive! { i32, 0 } +impl_additive! { i64, 0 } +impl_additive! { isize, 0 } +impl_additive! { u8, 0 } +impl_additive! { u16, 0 } +impl_additive! { u32, 0 } +impl_additive! { u64, 0 } impl_additive! { usize, 0 } -impl_additive! { f32, 0.0 } -impl_additive! { f64, 0.0 } +impl_additive! { f32, 0.0 } +impl_additive! { f64, 0.0 } /// A trait for iterators over elements which can be multiplied together. #[unstable(feature = "core", reason = "needs to be re-evaluated as part of numerics reform")] -pub trait MultiplicativeIterator { +pub trait MultiplicativeIterator { + /// The result of multiplying the elements of the iterator. + type ProductResult; + /// Iterates over the entire iterator, multiplying all the elements /// /// # Examples @@ -1284,29 +1315,54 @@ pub trait MultiplicativeIterator { /// assert!(factorial(1) == 1); /// assert!(factorial(5) == 120); /// ``` - fn product(self) -> A; + fn product(self) -> Self::ProductResult; +} + +/// The product operation of an iterator's item type. Implementing this allows +/// calling `.product()` on the iterator. +#[unstable(feature = "core", reason = "trait is experimental")] +pub trait MultiplicativeIteratorItem { + /// The type of the intermediate products. + type ProductResult; + /// The start value of the product, usually something like `1`. + fn start() -> Self::ProductResult; + /// Multiplies another element of the iterator to the intermediate product. + fn combine(self, other: Self::ProductResult) -> Self::ProductResult; } -macro_rules! impl_multiplicative { - ($A:ty, $init:expr) => { +#[unstable(feature = "core", reason = "trait is experimental")] +impl MultiplicativeIterator for I where + ::Item: MultiplicativeIteratorItem +{ + type ProductResult = <::Item as MultiplicativeIteratorItem>::ProductResult; + fn product(self) -> ::ProductResult { + let mut product = <::Item as MultiplicativeIteratorItem>::start(); + for x in self { + product = x.combine(product); + } + product + } +} + +macro_rules! impl_multiplicative { + ($T:ty, $init:expr) => { #[unstable(feature = "core", reason = "trait is experimental")] - impl> MultiplicativeIterator<$A> for T { - #[inline] - fn product(self) -> $A { - self.fold($init, |acc, x| acc * x) - } + impl MultiplicativeIteratorItem for $T { + type ProductResult = $T; + fn start() -> $T { $init } + fn combine(self, other: $T) -> $T { self * other } } }; } -impl_multiplicative! { i8, 1 } -impl_multiplicative! { i16, 1 } -impl_multiplicative! { i32, 1 } -impl_multiplicative! { i64, 1 } -impl_multiplicative! { isize, 1 } -impl_multiplicative! { u8, 1 } -impl_multiplicative! { u16, 1 } -impl_multiplicative! { u32, 1 } -impl_multiplicative! { u64, 1 } +impl_multiplicative! { i8, 1 } +impl_multiplicative! { i16, 1 } +impl_multiplicative! { i32, 1 } +impl_multiplicative! { i64, 1 } +impl_multiplicative! { isize, 1 } +impl_multiplicative! { u8, 1 } +impl_multiplicative! { u16, 1 } +impl_multiplicative! { u32, 1 } +impl_multiplicative! { u64, 1 } impl_multiplicative! { usize, 1 } impl_multiplicative! { f32, 1.0 } impl_multiplicative! { f64, 1.0 }