Skip to content

Commit 1bd4a76

Browse files
feat: add enumerate to iterator interface (#98)
1 parent f23ed3b commit 1bd4a76

File tree

3 files changed

+107
-0
lines changed

3 files changed

+107
-0
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#pragma once
2+
3+
#include "interface.fwd.hpp"
4+
5+
#include <optional>
6+
#include <tuple>
7+
8+
namespace rusty_iterators::iterator
9+
{
10+
using interface::IterInterface;
11+
12+
template <class T, class Other>
13+
class Enumerate : public IterInterface<std::tuple<size_t, T>, Enumerate<T, Other>>
14+
{
15+
public:
16+
explicit Enumerate(Other&& it) : it(std::forward<Other>(it)) {}
17+
18+
[[nodiscard]] auto count() -> size_t;
19+
auto next() -> std::optional<std::tuple<size_t, T>>;
20+
[[nodiscard]] auto sizeHint() const -> std::optional<size_t>;
21+
22+
private:
23+
Other it;
24+
size_t idx = 0;
25+
};
26+
} // namespace rusty_iterators::iterator
27+
28+
template <class T, class Other>
29+
auto rusty_iterators::iterator::Enumerate<T, Other>::count() -> size_t
30+
{
31+
return it.count();
32+
}
33+
34+
template <class T, class Other>
35+
auto rusty_iterators::iterator::Enumerate<T, Other>::next() -> std::optional<std::tuple<size_t, T>>
36+
{
37+
auto nextItem = it.next();
38+
39+
if (!nextItem.has_value())
40+
{
41+
return std::nullopt;
42+
}
43+
return std::tuple{idx++, std::move(nextItem.value())};
44+
}
45+
46+
template <class T, class Other>
47+
auto rusty_iterators::iterator::Enumerate<T, Other>::sizeHint() const -> std::optional<size_t>
48+
{
49+
return it.sizeHint();
50+
}

include/rusty_iterators/interface.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "chain.hpp"
44
#include "concepts.hpp"
55
#include "cycle.hpp"
6+
#include "enumerate.hpp"
67
#include "filter.hpp"
78
#include "filter_map.hpp"
89
#include "inspect.hpp"
@@ -37,6 +38,7 @@ using iterator::CacheCycle;
3738
using iterator::Chain;
3839
using iterator::CopyCycle;
3940
using iterator::CycleType;
41+
using iterator::Enumerate;
4042
using iterator::Filter;
4143
using iterator::FilterMap;
4244
using iterator::Inspect;
@@ -83,6 +85,8 @@ class IterInterface
8385
template <class Second>
8486
[[nodiscard]] auto chain(Second&& it) -> Chain<T, Derived, Second>;
8587

88+
[[nodiscard]] auto enumerate() -> Enumerate<T, Derived>;
89+
8690
template <class Other>
8791
[[nodiscard]] auto eq(Other&& it) -> bool;
8892

@@ -251,6 +255,12 @@ auto rusty_iterators::interface::IterInterface<T, Derived>::chain(Second&& it)
251255
return Chain<T, Derived, Second>{std::forward<Derived>(self()), std::forward<Second>(it)};
252256
}
253257

258+
template <class T, class Derived>
259+
auto rusty_iterators::interface::IterInterface<T, Derived>::enumerate() -> Enumerate<T, Derived>
260+
{
261+
return Enumerate<T, Derived>{std::forward<Derived>(self())};
262+
}
263+
254264
template <class T, class Derived>
255265
template <class Other>
256266
auto rusty_iterators::interface::IterInterface<T, Derived>::eq(Other&& it) -> bool

tests/enumerate.test.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#include <gmock/gmock.h>
2+
#include <gtest/gtest.h>
3+
4+
#include <rusty_iterators/iterator.hpp>
5+
6+
using ::rusty_iterators::iterator::LazyIterator;
7+
using ::testing::FieldsAre;
8+
9+
TEST(TestEnumerateIterator, TestNextReturnsIndexedValue)
10+
{
11+
auto vec = std::vector{1, 2, 3};
12+
auto it = LazyIterator{vec}.enumerate();
13+
14+
EXPECT_THAT(it.next().value(), FieldsAre(0, 1));
15+
EXPECT_THAT(it.next().value(), FieldsAre(1, 2));
16+
EXPECT_THAT(it.next().value(), FieldsAre(2, 3));
17+
ASSERT_EQ(it.next(), std::nullopt);
18+
}
19+
20+
TEST(TestEnumerateIterator, TestCollectedTuples)
21+
{
22+
auto vec = std::vector{1, 2, 3};
23+
auto result = LazyIterator{vec}.enumerate().collect();
24+
25+
ASSERT_EQ(result.size(), 3);
26+
EXPECT_THAT(result[0], FieldsAre(0, 1));
27+
EXPECT_THAT(result[1], FieldsAre(1, 2));
28+
EXPECT_THAT(result[2], FieldsAre(2, 3));
29+
}
30+
31+
TEST(TestEnumerateIterator, TestSizeHintReturnsUnderlyingSize)
32+
{
33+
auto vec = std::vector{1, 2, 3};
34+
auto it = LazyIterator{vec}.enumerate();
35+
36+
ASSERT_EQ(it.sizeHint(), 3);
37+
}
38+
39+
TEST(TestEnumerateIterator, TestCountReturnsRealCount)
40+
{
41+
auto vec = std::vector{1, 2, 3};
42+
auto it = LazyIterator{vec}.enumerate();
43+
44+
it.next();
45+
46+
ASSERT_EQ(it.count(), 2);
47+
}

0 commit comments

Comments
 (0)