From 6171c36fc20ee47c1d282bb7f58a6711b0b8c49d Mon Sep 17 00:00:00 2001 From: WiktorNowak Date: Sat, 11 Jan 2025 11:23:35 +0100 Subject: [PATCH] feat: add enumerate to iterator interface --- include/rusty_iterators/enumerate.hpp | 50 +++++++++++++++++++++++++++ include/rusty_iterators/interface.hpp | 10 ++++++ tests/enumerate.test.cpp | 47 +++++++++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 include/rusty_iterators/enumerate.hpp create mode 100644 tests/enumerate.test.cpp diff --git a/include/rusty_iterators/enumerate.hpp b/include/rusty_iterators/enumerate.hpp new file mode 100644 index 0000000..7287d11 --- /dev/null +++ b/include/rusty_iterators/enumerate.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include "interface.fwd.hpp" + +#include +#include + +namespace rusty_iterators::iterator +{ +using interface::IterInterface; + +template +class Enumerate : public IterInterface, Enumerate> +{ + public: + explicit Enumerate(Other&& it) : it(std::forward(it)) {} + + [[nodiscard]] auto count() -> size_t; + auto next() -> std::optional>; + [[nodiscard]] auto sizeHint() const -> std::optional; + + private: + Other it; + size_t idx = 0; +}; +} // namespace rusty_iterators::iterator + +template +auto rusty_iterators::iterator::Enumerate::count() -> size_t +{ + return it.count(); +} + +template +auto rusty_iterators::iterator::Enumerate::next() -> std::optional> +{ + auto nextItem = it.next(); + + if (!nextItem.has_value()) + { + return std::nullopt; + } + return std::tuple{idx++, std::move(nextItem.value())}; +} + +template +auto rusty_iterators::iterator::Enumerate::sizeHint() const -> std::optional +{ + return it.sizeHint(); +} diff --git a/include/rusty_iterators/interface.hpp b/include/rusty_iterators/interface.hpp index 6b0c4fa..51e5733 100644 --- a/include/rusty_iterators/interface.hpp +++ b/include/rusty_iterators/interface.hpp @@ -3,6 +3,7 @@ #include "chain.hpp" #include "concepts.hpp" #include "cycle.hpp" +#include "enumerate.hpp" #include "filter.hpp" #include "filter_map.hpp" #include "inspect.hpp" @@ -37,6 +38,7 @@ using iterator::CacheCycle; using iterator::Chain; using iterator::CopyCycle; using iterator::CycleType; +using iterator::Enumerate; using iterator::Filter; using iterator::FilterMap; using iterator::Inspect; @@ -83,6 +85,8 @@ class IterInterface template [[nodiscard]] auto chain(Second&& it) -> Chain; + [[nodiscard]] auto enumerate() -> Enumerate; + template [[nodiscard]] auto eq(Other&& it) -> bool; @@ -251,6 +255,12 @@ auto rusty_iterators::interface::IterInterface::chain(Second&& it) return Chain{std::forward(self()), std::forward(it)}; } +template +auto rusty_iterators::interface::IterInterface::enumerate() -> Enumerate +{ + return Enumerate{std::forward(self())}; +} + template template auto rusty_iterators::interface::IterInterface::eq(Other&& it) -> bool diff --git a/tests/enumerate.test.cpp b/tests/enumerate.test.cpp new file mode 100644 index 0000000..0b91f45 --- /dev/null +++ b/tests/enumerate.test.cpp @@ -0,0 +1,47 @@ +#include +#include + +#include + +using ::rusty_iterators::iterator::LazyIterator; +using ::testing::FieldsAre; + +TEST(TestEnumerateIterator, TestNextReturnsIndexedValue) +{ + auto vec = std::vector{1, 2, 3}; + auto it = LazyIterator{vec}.enumerate(); + + EXPECT_THAT(it.next().value(), FieldsAre(0, 1)); + EXPECT_THAT(it.next().value(), FieldsAre(1, 2)); + EXPECT_THAT(it.next().value(), FieldsAre(2, 3)); + ASSERT_EQ(it.next(), std::nullopt); +} + +TEST(TestEnumerateIterator, TestCollectedTuples) +{ + auto vec = std::vector{1, 2, 3}; + auto result = LazyIterator{vec}.enumerate().collect(); + + ASSERT_EQ(result.size(), 3); + EXPECT_THAT(result[0], FieldsAre(0, 1)); + EXPECT_THAT(result[1], FieldsAre(1, 2)); + EXPECT_THAT(result[2], FieldsAre(2, 3)); +} + +TEST(TestEnumerateIterator, TestSizeHintReturnsUnderlyingSize) +{ + auto vec = std::vector{1, 2, 3}; + auto it = LazyIterator{vec}.enumerate(); + + ASSERT_EQ(it.sizeHint(), 3); +} + +TEST(TestEnumerateIterator, TestCountReturnsRealCount) +{ + auto vec = std::vector{1, 2, 3}; + auto it = LazyIterator{vec}.enumerate(); + + it.next(); + + ASSERT_EQ(it.count(), 2); +}