diff --git a/include/rusty_iterators/concepts.hpp b/include/rusty_iterators/concepts.hpp index 07dc908..91f2f4a 100644 --- a/include/rusty_iterators/concepts.hpp +++ b/include/rusty_iterators/concepts.hpp @@ -60,6 +60,11 @@ concept InspectFunctor = requires(Functor f, T& t) { template concept PositionFunctor = AllFunctor; +template +concept Multiplyable = requires(T first, T second) { + { first* second } -> std::same_as; +}; + template concept ReduceFunctor = FoldFunctor; diff --git a/include/rusty_iterators/interface.hpp b/include/rusty_iterators/interface.hpp index 1978ee0..12bf678 100644 --- a/include/rusty_iterators/interface.hpp +++ b/include/rusty_iterators/interface.hpp @@ -30,6 +30,7 @@ using concepts::FoldFunctor; using concepts::ForEachFunctor; using concepts::Indexable; using concepts::InspectFunctor; +using concepts::Multiplyable; using concepts::NeFunctor; using concepts::PositionFunctor; using concepts::ReduceFunctor; @@ -149,6 +150,10 @@ class IterInterface requires PositionFunctor [[nodiscard]] auto position(Functor&& f) -> std::optional; + template + requires Multiplyable + [[nodiscard]] auto product() -> std::optional; + template requires ReduceFunctor [[nodiscard]] auto reduce(Functor&& f) -> std::optional; @@ -434,6 +439,14 @@ auto rusty_iterators::interface::IterInterface::position(Functor&& f return std::nullopt; } +template +template + requires rusty_iterators::concepts::Multiplyable +auto rusty_iterators::interface::IterInterface::product() -> std::optional +{ + return self().reduce([](auto acc, auto x) { return acc * x; }); +} + template template requires rusty_iterators::concepts::ReduceFunctor diff --git a/include/rusty_iterators/iterator.hpp b/include/rusty_iterators/iterator.hpp index 698ed74..dfc4c33 100644 --- a/include/rusty_iterators/iterator.hpp +++ b/include/rusty_iterators/iterator.hpp @@ -16,6 +16,7 @@ using Item = std::reference_wrapper; namespace rusty_iterators::iterator { using concepts::FoldFunctor; +using concepts::Multiplyable; using concepts::Summable; template @@ -32,6 +33,10 @@ class LazyIterator : public interface::IterInterface, LazyIterat auto next() -> std::optional; [[nodiscard]] auto sizeHint() const -> std::optional; + template + requires Multiplyable + [[nodiscard]] auto product() -> std::optional; + template requires Summable [[nodiscard]] auto sum() -> R; @@ -62,11 +67,20 @@ auto rusty_iterators::iterator::LazyIterator::sizeHint() const -> std return end - ptr; } +template + requires std::ranges::range +template + requires rusty_iterators::concepts::Multiplyable +auto rusty_iterators::iterator::LazyIterator::product() -> std::optional +{ + return this->map([](auto x) { return x.get(); }).product(); +} + template requires std::ranges::range template requires rusty_iterators::concepts::Summable auto rusty_iterators::iterator::LazyIterator::sum() -> R { - return this->fold(RawT{}, [](auto acc, auto x) { return acc + x; }); + return this->map([](auto x) { return x.get(); }).sum(); } diff --git a/tests/iterator.test.cpp b/tests/iterator.test.cpp index 7fe014c..180f045 100644 --- a/tests/iterator.test.cpp +++ b/tests/iterator.test.cpp @@ -379,3 +379,19 @@ TEST(TestIterator, TestLast) ASSERT_EQ(it.last(), 3); } + +TEST(TestIterator, TestLazyIteratorProduct) +{ + auto vec = std::vector{1, 2, 3, 4}; + auto it = LazyIterator{vec}; + + ASSERT_EQ(it.product(), 1 * 2 * 3 * 4); +} + +TEST(TestIterator, TestProductOnMapIterator) +{ + auto vec = std::vector{1, 2, 3, 4}; + auto it = LazyIterator{vec}.map([](auto x) { return x * 2; }); + + ASSERT_EQ(it.product(), 2 * 4 * 6 * 8); +}