From f02c8b8e29842a5432e50e635fb1e703aa094648 Mon Sep 17 00:00:00 2001 From: MagisterDaIlis <196101336+MagisterDaIlis@users.noreply.github.com> Date: Mon, 27 Jan 2025 08:24:34 +0100 Subject: [PATCH] feat(corelib): Iterator::Sum (#7142) --- corelib/src/iter.cairo | 2 +- corelib/src/iter/traits.cairo | 2 +- corelib/src/iter/traits/accum.cairo | 19 ++++++++++++++++ corelib/src/iter/traits/iterator.cairo | 30 +++++++++++++++++++++++++- corelib/src/test/iter_test.cairo | 6 ++++++ 5 files changed, 56 insertions(+), 3 deletions(-) diff --git a/corelib/src/iter.cairo b/corelib/src/iter.cairo index 8220190bbf1..a0d75e911f0 100644 --- a/corelib/src/iter.cairo +++ b/corelib/src/iter.cairo @@ -232,4 +232,4 @@ mod adapters; mod traits; pub use adapters::PeekableTrait; -pub use traits::{FromIterator, IntoIterator, Iterator, Product}; +pub use traits::{FromIterator, IntoIterator, Iterator, Product, Sum}; diff --git a/corelib/src/iter/traits.cairo b/corelib/src/iter/traits.cairo index 57a8e5fac7a..d44e90b26e3 100644 --- a/corelib/src/iter/traits.cairo +++ b/corelib/src/iter/traits.cairo @@ -1,6 +1,6 @@ mod accum; mod collect; mod iterator; -pub use accum::Product; +pub use accum::{Product, Sum}; pub use collect::{FromIterator, IntoIterator}; pub use iterator::Iterator; diff --git a/corelib/src/iter/traits/accum.cairo b/corelib/src/iter/traits/accum.cairo index e0e0bcb1a92..129a76dfc8b 100644 --- a/corelib/src/iter/traits/accum.cairo +++ b/corelib/src/iter/traits/accum.cairo @@ -1,3 +1,22 @@ +/// Trait to represent types that can be created by summing up an iterator. +/// +/// This trait is used to implement [`Iterator::sum()`]. Types which implement +/// this trait can be generated by using the [`sum()`] method on an iterator. +/// Like [`FromIterator`], this trait should rarely be called directly. +/// +/// [`sum()`]: crate::iter::Iterator::sum +/// [`FromIterator`]: crate::iter::FromIterator +pub trait Sum { + /// Takes an iterator and generates `Self` from the elements by "summing up" + /// the items. + fn sum[Item: A], +Destruct, +Destruct>(iter: I) -> A; +} + +impl SumAddableTypesImpl, impl ZeroA: core::num::traits::Zero> of Sum { + fn sum[Item: A], +Destruct, +Destruct>(mut iter: I) -> A { + iter.fold(ZeroA::zero(), |acc, x| acc + x) + } +} /// Trait to represent types that can be created by multiplying elements of an /// iterator. /// diff --git a/corelib/src/iter/traits/iterator.cairo b/corelib/src/iter/traits/iterator.cairo index 10d42cc4239..b1996bc05ab 100644 --- a/corelib/src/iter/traits/iterator.cairo +++ b/corelib/src/iter/traits/iterator.cairo @@ -2,7 +2,7 @@ use crate::iter::adapters::{ Enumerate, Map, Peekable, Zip, enumerated_iterator, mapped_iterator, peekable_iterator, zipped_iterator, }; -use crate::iter::traits::Product; +use crate::iter::traits::{Product, Sum}; /// A trait for dealing with iterators. /// @@ -473,6 +473,34 @@ pub trait Iterator { peekable_iterator(self) } + /// Sums the elements of an iterator. + /// + /// Takes each element, adds them together, and returns the result. + /// + /// An empty iterator returns the zero value of the type. + /// + /// `sum()` can be used to sum any type implementing [`Sum`][`core::iter::Sum`], + /// including [`Option`][`Option::sum`] and [`Result`][`Result::sum`]. + /// + /// # Panics + /// + /// When calling `sum()` and a primitive integer type is being returned, this + /// method will panic if the computation overflows. + /// + /// # Examples + /// + /// ``` + /// let mut iter = array![1, 2, 3].into_iter(); + /// let sum: usize = iter.sum(); + /// + /// assert_eq!(sum, 6); + /// ``` + fn sum<+Destruct, +Destruct, +Sum>( + self: T, + ) -> Self::Item { + Sum::::sum::(self) + } + /// Iterates over the entire iterator, multiplying all the elements /// /// An empty iterator returns the one value of the type. diff --git a/corelib/src/test/iter_test.cairo b/corelib/src/test/iter_test.cairo index c1111bae772..b2615c1ca93 100644 --- a/corelib/src/test/iter_test.cairo +++ b/corelib/src/test/iter_test.cairo @@ -98,6 +98,12 @@ fn test_iter_adapter_peekable() { assert_eq!(iter.next(), Option::None); } +#[test] +fn test_iter_accum_sum() { + assert_eq!(array![1, 2, 3].into_iter().sum(), 6); + assert_eq!(array![].into_iter().sum(), 0); +} + #[test] fn test_iter_accum_product() { assert_eq!((1_usize..=0).into_iter().product(), 1);