Skip to content

Commit d6eb22a

Browse files
committed
[fix] take on single-pass ranges
1 parent 7a8a7fd commit d6eb22a

File tree

2 files changed

+66
-21
lines changed

2 files changed

+66
-21
lines changed

include/radr/rad/take.hpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,24 @@ inline constexpr auto take_coro = []<std::ranges::input_range URange>(URange &&
114114
return [](auto urange_, std::size_t const n)
115115
-> radr::generator<std::ranges::range_reference_t<URange>, std::ranges::range_value_t<URange>>
116116
{
117-
std::size_t i = 0;
118-
for (auto it = radr::begin(urange_); it != radr::end(urange_) && i < n; ++it, ++i)
117+
size_t i = 0;
118+
auto it = radr::begin(urange_);
119+
if (i == n || it == radr::end(urange_))
120+
co_return;
121+
122+
while (true)
123+
{
119124
co_yield *it;
125+
126+
++i;
127+
if (i == n)
128+
break;
129+
130+
/* checks are split up to prevent iterating further than necessary */
131+
++it;
132+
if (it == radr::end(urange_))
133+
break;
134+
}
120135
}(std::move(urange), n);
121136
};
122137

tests/unit/factory/istream.cpp

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,54 +6,84 @@
66
#include <radr/test/gtest_helpers.hpp>
77

88
#include <radr/factory/istream.hpp>
9+
#include <radr/rad/take.hpp>
910

1011
TEST(ViewsIstreamConceptsTest, ConceptValidation)
1112
{
1213
std::istringstream input("1 2 3");
13-
auto view = radr::istream<int>(input);
14+
auto rng = radr::istream<int>(input);
1415

1516
// Checking the relevant concepts
16-
EXPECT_TRUE(std::ranges::input_range<decltype(view)>);
17-
EXPECT_TRUE(std::ranges::view<decltype(view)>);
18-
EXPECT_TRUE(std::is_move_constructible_v<decltype(view)>);
19-
EXPECT_FALSE(std::ranges::common_range<decltype(view)>);
20-
EXPECT_FALSE(std::ranges::sized_range<decltype(view)>);
21-
EXPECT_FALSE(std::ranges::contiguous_range<decltype(view)>);
22-
EXPECT_FALSE(std::is_default_constructible_v<decltype(view)>);
23-
EXPECT_FALSE(std::ranges::random_access_range<decltype(view)>);
17+
EXPECT_TRUE(std::ranges::input_range<decltype(rng)>);
18+
EXPECT_TRUE(std::ranges::view<decltype(rng)>);
19+
EXPECT_TRUE(std::is_move_constructible_v<decltype(rng)>);
20+
EXPECT_FALSE(std::ranges::common_range<decltype(rng)>);
21+
EXPECT_FALSE(std::ranges::sized_range<decltype(rng)>);
22+
EXPECT_FALSE(std::ranges::contiguous_range<decltype(rng)>);
23+
EXPECT_FALSE(std::is_default_constructible_v<decltype(rng)>);
24+
EXPECT_FALSE(std::ranges::random_access_range<decltype(rng)>);
2425
}
2526

2627
TEST(istream, EmptyInput)
2728
{
2829
std::istringstream input("");
29-
auto view = radr::istream<int>(input);
30-
EXPECT_TRUE(view.begin() == view.end());
30+
auto rng = radr::istream<int>(input);
31+
EXPECT_TRUE(rng.begin() == rng.end());
3132
}
3233

3334
TEST(istream, ReadIntegers)
3435
{
3536
std::istringstream input("10 20 30");
36-
auto view = radr::istream<int>(input);
37-
EXPECT_RANGE_EQ(view, (std::vector<int>{10, 20, 30}));
37+
auto rng = radr::istream<int>(input);
38+
EXPECT_RANGE_EQ(rng, (std::vector<int>{10, 20, 30}));
3839
}
3940

4041
TEST(istream, ReadStrings)
4142
{
4243
std::istringstream input("hello world test");
43-
auto view = radr::istream<std::string>(input);
44-
EXPECT_RANGE_EQ(view, (std::vector<std::string>{"hello", "world", "test"}));
44+
auto rng = radr::istream<std::string>(input);
45+
EXPECT_RANGE_EQ(rng, (std::vector<std::string>{"hello", "world", "test"}));
4546
}
4647

4748
TEST(istream, StopOnMalformedData)
4849
{
4950
std::istringstream input("42 invalid 84");
50-
auto view = radr::istream<int>(input);
51-
EXPECT_RANGE_EQ(view, (std::vector<int>{42}));
51+
auto rng = radr::istream<int>(input);
52+
EXPECT_RANGE_EQ(rng, (std::vector<int>{42}));
5253
}
5354

5455
TEST(istream, ReadChars)
5556
{
5657
std::istringstream input("hello world test");
57-
auto view = radr::istream<char>(input);
58-
EXPECT_RANGE_EQ(view, std::string{"helloworldtest"});
58+
auto rng = radr::istream<char>(input);
59+
EXPECT_RANGE_EQ(rng, std::string{"helloworldtest"});
60+
}
61+
62+
TEST(istream, NoReadBehind)
63+
{
64+
{
65+
std::istringstream input("10 20 30 40");
66+
67+
auto rng = radr::istream<int>(input) | radr::take(2);
68+
EXPECT_RANGE_EQ(rng, (std::vector<int>{10, 20}));
69+
70+
int i = 0;
71+
input >> i;
72+
EXPECT_EQ(i, 30);
73+
// NO ELEMENT HAS BEEN SKIPPED
74+
}
75+
76+
#if !defined(_GLIBCXX_RELEASE) || (_GLIBCXX_RELEASE >= 12)
77+
{
78+
std::istringstream input("10 20 30 40");
79+
80+
auto rng = std::views::istream<int>(input) | std::views::take(2);
81+
EXPECT_RANGE_EQ(rng, (std::vector<int>{10, 20}));
82+
83+
int i = 0;
84+
input >> i;
85+
EXPECT_EQ(i, 40);
86+
// ELEMENT HAS BEEN SKIPPED
87+
}
88+
#endif
5989
}

0 commit comments

Comments
 (0)