Skip to content

Commit f52c06e

Browse files
fix: potential undefined behaviour in nth (#104)
1 parent eb38e34 commit f52c06e

File tree

7 files changed

+30
-24
lines changed

7 files changed

+30
-24
lines changed

include/rusty_iterators/interface.hpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class IterInterface
6464
IterInterface(IterInterface&&) = default;
6565
IterInterface& operator=(IterInterface&&) = default;
6666

67-
[[nodiscard]] auto advanceBy(size_t amount) -> Derived;
67+
auto advanceBy(size_t amount) -> void;
6868

6969
template <class Functor>
7070
requires AnyFunctor<T, Functor>
@@ -183,14 +183,13 @@ class IterInterface
183183
} // namespace rusty_iterators::interface
184184

185185
template <class T, class Derived>
186-
auto rusty_iterators::interface::IterInterface<T, Derived>::advanceBy(size_t amount) -> Derived
186+
auto rusty_iterators::interface::IterInterface<T, Derived>::advanceBy(size_t n) -> void
187187
{
188-
for (size_t i = 0; i < amount; i++)
188+
for (size_t i = 0; i < n; ++i)
189189
{
190190
[[unlikely]] if (!self().next().has_value())
191191
break;
192192
}
193-
return std::move(self());
194193
}
195194

196195
template <class T, class Derived>
@@ -222,8 +221,7 @@ auto rusty_iterators::interface::IterInterface<T, Derived>::collect() -> std::ve
222221
auto size = sizeHintChecked();
223222

224223
collection.reserve(size);
225-
226-
forEach([&collection](auto&& x) { collection.push_back(std::move(x)); });
224+
self().forEach([&collection](auto&& x) { collection.push_back(std::move(x)); });
227225

228226
return std::move(collection);
229227
}
@@ -233,7 +231,7 @@ auto rusty_iterators::interface::IterInterface<T, Derived>::count() -> size_t
233231
{
234232
size_t count = 0;
235233

236-
forEach([&count](auto&& _) { count += 1; });
234+
self().forEach([&count](auto&& _) { count += 1; });
237235

238236
return count;
239237
}
@@ -404,9 +402,10 @@ auto rusty_iterators::interface::IterInterface<T, Derived>::neBy(Other&& it, Fun
404402
}
405403

406404
template <class T, class Derived>
407-
auto rusty_iterators::interface::IterInterface<T, Derived>::nth(size_t element) -> std::optional<T>
405+
auto rusty_iterators::interface::IterInterface<T, Derived>::nth(size_t n) -> std::optional<T>
408406
{
409-
return self().advanceBy(element).next();
407+
self().advanceBy(n);
408+
return self().next();
410409
}
411410

412411
template <class T, class Derived>

include/rusty_iterators/skip.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ auto rusty_iterators::iterator::Skip<T, Other>::next() -> std::optional<T>
2929
{
3030
[[unlikely]] if (n > 0)
3131
{
32-
it = it.advanceBy(n);
33-
n = 0;
34-
return std::move(it.next());
32+
auto item = it.nth(n);
33+
n = 0;
34+
return std::move(item);
3535
}
3636
return std::move(it.next());
3737
}

include/rusty_iterators/zip.hpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class Zip : public IterInterface<std::tuple<T, R>, Zip<T, R, First, Second>>
1818
: first(std::forward<First>(f)), second(std::forward<Second>(s))
1919
{}
2020

21-
[[nodiscard]] auto advanceBy(size_t amount) -> Zip<T, R, First, Second>;
21+
auto advanceBy(size_t amount) -> void;
2222
auto next() -> std::optional<std::tuple<T, R>>;
2323
[[nodiscard]] auto sizeHint() const -> std::optional<size_t>;
2424

@@ -29,13 +29,10 @@ class Zip : public IterInterface<std::tuple<T, R>, Zip<T, R, First, Second>>
2929
} // namespace rusty_iterators::iterator
3030

3131
template <class T, class R, class First, class Second>
32-
auto rusty_iterators::iterator::Zip<T, R, First, Second>::advanceBy(size_t amount)
33-
-> Zip<T, R, First, Second>
32+
auto rusty_iterators::iterator::Zip<T, R, First, Second>::advanceBy(size_t amount) -> void
3433
{
35-
first = first.advanceBy(amount);
36-
second = second.advanceBy(amount);
37-
38-
return std::move(static_cast<Zip<T, R, First, Second>&>(*this));
34+
first.advanceBy(amount);
35+
second.advanceBy(amount);
3936
}
4037

4138
template <class T, class R, class First, class Second>

tests/file_iterator.test.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ TEST(TestBufferedFileIterator, TestSizeHint)
8181
TEST(TestBufferedFileIterator, TestSizeHintAfterConsumption)
8282
{
8383
auto testFileName = std::string{"./tests/test_data.txt"};
84-
auto it = FileIterator<FIterType::Buffered>{testFileName}.advanceBy(2);
84+
auto it = FileIterator<FIterType::Buffered>{testFileName};
85+
86+
it.advanceBy(2);
8587

8688
ASSERT_EQ(it.sizeHint(), 2);
8789
}

tests/integration.test.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ TEST(TestIteratorIntegration, TestWindowsOverCycle)
8787
TEST(TestIteratorIntegration, TestCycleAdvanceBy)
8888
{
8989
auto vec = std::vector{1, 2};
90-
auto it = LazyIterator{vec}.cycle().advanceBy(3);
90+
auto it = LazyIterator{vec}.cycle();
91+
92+
it.advanceBy(3);
9193

9294
ASSERT_EQ(it.next().value(), 2);
9395
ASSERT_EQ(it.next().value(), 1);

tests/iterator.test.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,15 +211,19 @@ TEST(TestIterator, AllReturnsFalseIfOneDoesntFit)
211211
TEST(TestIterator, AdvanceByMovesIteratorPtr)
212212
{
213213
auto vec = std::vector{1, 2, 3, 4};
214-
auto it = LazyIterator{vec}.advanceBy(3);
214+
auto it = LazyIterator{vec};
215+
216+
it.advanceBy(3);
215217

216218
ASSERT_EQ(it.next().value(), 4);
217219
}
218220

219221
TEST(TestIterator, AdvanceByBiggerThanSize)
220222
{
221223
auto vec = std::vector{1, 2, 3};
222-
auto it = LazyIterator{vec}.advanceBy(4);
224+
auto it = LazyIterator{vec};
225+
226+
it.advanceBy(4);
223227

224228
ASSERT_EQ(it.next(), std::nullopt);
225229
}

tests/zip.test.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ TEST(TestZipIterator, TestAdvanceBy)
7676
auto v1 = std::vector{1, 2, 3};
7777
auto v2 = std::vector{4, 5, 6};
7878

79-
auto it = LazyIterator{v1}.zip(LazyIterator{v2}).advanceBy(2);
79+
auto it = LazyIterator{v1}.zip(LazyIterator{v2});
80+
81+
it.advanceBy(2);
8082

8183
EXPECT_THAT(it.next().value(), FieldsAre(3, 6));
8284
}

0 commit comments

Comments
 (0)