1 // Range v3 library
2 //
3 // Copyright Eric Niebler 2013-present
4 // Copyright Gonzalo Brito Gadeschi 2015
5 //
6 // Use, modification and distribution is subject to the
7 // Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10 //
11 // Project home: https://github.com/ericniebler/range-v3
12
13 #include <list>
14 #include <array>
15 #include <vector>
16 #include <memory>
17 #include <forward_list>
18 #include <range/v3/range_for.hpp>
19 #include <range/v3/algorithm/count_if.hpp>
20 #include <range/v3/view/cycle.hpp>
21 #include <range/v3/view/take.hpp>
22 #include <range/v3/view/take_exactly.hpp>
23 #include <range/v3/view/iota.hpp>
24 #include <range/v3/view/reverse.hpp>
25 #include <range/v3/view/slice.hpp>
26 #include <range/v3/view/c_str.hpp>
27 #include "../simple_test.hpp"
28 #include "../test_utils.hpp"
29
30 using namespace ranges;
31
32 template<typename Rng>
test_const_forward_range(Rng const & rng)33 void test_const_forward_range(Rng const &rng)
34 {
35 auto r = rng | views::cycle;
36 static_assert(is_infinite<decltype(r)>{}, "");
37 static_assert(!common_range<decltype(r)>, "");
38 CHECK(distance(r | views::take_exactly(0)) == 0);
39 CHECK(distance(r | views::take_exactly(1)) == 1);
40 CHECK(distance(r | views::take_exactly(2)) == 2);
41 CHECK(distance(r | views::take_exactly(3)) == 3);
42 CHECK(distance(r | views::take_exactly(4)) == 4);
43 CHECK(distance(r | views::take_exactly(6)) == 6);
44 CHECK(distance(r | views::take_exactly(7)) == 7);
45 CHECK(count_if(r | views::take_exactly(7), [](int) { return true; }) == 7);
46
47 ::check_equal(r | views::take_exactly(0), std::array<int, 0>{});
48 ::check_equal(r | views::take_exactly(1), {0});
49 ::check_equal(r | views::take_exactly(2), {0, 1});
50 ::check_equal(r | views::take_exactly(3), {0, 1, 2});
51 ::check_equal(r | views::take_exactly(4), {0, 1, 2, 0});
52 ::check_equal(r | views::take_exactly(6), {0, 1, 2, 0, 1, 2});
53 ::check_equal(r | views::take_exactly(7), {0, 1, 2, 0, 1, 2, 0});
54
55 CHECK(distance(r | views::take(0)) == 0);
56 CHECK(distance(r | views::take(1)) == 1);
57 CHECK(distance(r | views::take(2)) == 2);
58 CHECK(distance(r | views::take(3)) == 3);
59 CHECK(distance(r | views::take(4)) == 4);
60 CHECK(distance(r | views::take(6)) == 6);
61 CHECK(distance(r | views::take(7)) == 7);
62 CHECK(count_if(r | views::take(7), [](int) { return true; }) == 7);
63
64 ::check_equal(r | views::take(0), std::array<int, 0>{});
65 ::check_equal(r | views::take(1), {0});
66 ::check_equal(r | views::take(2), {0, 1});
67 ::check_equal(r | views::take(3), {0, 1, 2});
68 ::check_equal(r | views::take(4), {0, 1, 2, 0});
69 ::check_equal(r | views::take(6), {0, 1, 2, 0, 1, 2});
70 ::check_equal(r | views::take(7), {0, 1, 2, 0, 1, 2, 0});
71 }
72
73 template<typename Rng>
test_const_forward_reversed_range(Rng const & rng)74 void test_const_forward_reversed_range(Rng const &rng)
75 {
76 test_const_forward_range(rng);
77
78 auto r = rng | views::reverse | views::cycle;
79 static_assert(is_infinite<decltype(r)>{}, "");
80 static_assert(!common_range<decltype(r)>, "");
81
82 CHECK(distance(r | views::take_exactly(0)) == 0);
83 CHECK(distance(r | views::take_exactly(1)) == 1);
84 CHECK(distance(r | views::take_exactly(2)) == 2);
85 CHECK(distance(r | views::take_exactly(3)) == 3);
86 CHECK(distance(r | views::take_exactly(4)) == 4);
87 CHECK(distance(r | views::take_exactly(6)) == 6);
88 CHECK(distance(r | views::take_exactly(7)) == 7);
89 CHECK(count_if(r | views::take_exactly(7), [](int) { return true; }) == 7);
90
91 ::check_equal(r | views::take_exactly(0), std::array<int, 0>{});
92 ::check_equal(r | views::take_exactly(1), {2});
93 ::check_equal(r | views::take_exactly(2), {2, 1});
94 ::check_equal(r | views::take_exactly(3), {2, 1, 0});
95 ::check_equal(r | views::take_exactly(4), {2, 1, 0, 2});
96 ::check_equal(r | views::take_exactly(6), {2, 1, 0, 2, 1, 0});
97 ::check_equal(r | views::take_exactly(7), {2, 1, 0, 2, 1, 0, 2});
98
99 CHECK(distance(r | views::take(0)) == 0);
100 CHECK(distance(r | views::take(1)) == 1);
101 CHECK(distance(r | views::take(2)) == 2);
102 CHECK(distance(r | views::take(3)) == 3);
103 CHECK(distance(r | views::take(4)) == 4);
104 CHECK(distance(r | views::take(6)) == 6);
105 CHECK(distance(r | views::take(7)) == 7);
106 CHECK(count_if(r | views::take(7), [](int) { return true; }) == 7);
107
108 ::check_equal(r | views::take(0), std::array<int, 0>{});
109 ::check_equal(r | views::take(1), {2});
110 ::check_equal(r | views::take(2), {2, 1});
111 ::check_equal(r | views::take(3), {2, 1, 0});
112 ::check_equal(r | views::take(4), {2, 1, 0, 2});
113 ::check_equal(r | views::take(6), {2, 1, 0, 2, 1, 0});
114 ::check_equal(r | views::take(7), {2, 1, 0, 2, 1, 0, 2});
115 }
116
117 template<typename Rng>
test_mutable_forward_range_reversed(Rng & rng)118 void test_mutable_forward_range_reversed(Rng &rng)
119 {
120 test_const_forward_reversed_range(rng);
121 int count = 2;
122 RANGES_FOR(auto &&i, rng | views::cycle | views::take_exactly(6)) { i = ++count; }
123 ::check_equal(rng | views::take_exactly(3), {6, 7, 8});
124 }
125
126 template<typename Rng>
test_forward_it(Rng const & rng)127 void test_forward_it(Rng const &rng)
128 {
129 auto r = rng | views::cycle;
130 static_assert(forward_range<decltype(r)>, "");
131 auto f = begin(r);
132 static_assert(forward_iterator<decltype(f)>, "");
133
134 CHECK((*f) == 0);
135 auto n = next(f, 1);
136 CHECK((*n) == 1);
137 }
138
139 template<typename Rng>
test_bidirectional_it(Rng const & rng)140 void test_bidirectional_it(Rng const &rng)
141 {
142 test_forward_it(rng);
143 auto r = rng | views::cycle;
144 static_assert(bidirectional_range<decltype(r)>, "");
145 auto f = begin(r);
146 static_assert(bidirectional_iterator<decltype(f)>, "");
147
148 CHECK((*f) == 0);
149 auto n = next(f, 1);
150 CHECK((*n) == 1);
151 CHECK((--n) == f);
152 }
153
154 template<typename Rng>
test_random_access_it(Rng const & rng)155 void test_random_access_it(Rng const &rng)
156 {
157 test_bidirectional_it(rng);
158 auto r = rng | views::cycle;
159 static_assert(random_access_range<decltype(r)>, "");
160 auto f = begin(r);
161 static_assert(random_access_iterator<decltype(f)>, "");
162 auto m = begin(r) + 1;
163 auto l = begin(r) + 2;
164 auto f1 = begin(r) + 3;
165 auto f2 = begin(r) + 6;
166
167 CHECK(r[0] == 0);
168 CHECK(r[1] == 1);
169 CHECK(r[2] == 2);
170 CHECK(r[3] == 0);
171 CHECK(r[4] == 1);
172 CHECK(r[5] == 2);
173
174 CHECK((f + 3) == f1);
175 CHECK((f + 6) == f2);
176 CHECK((f1 + 3) == f2);
177 CHECK((f2 - 3) == f1);
178 CHECK((f2 - 6) == f);
179
180 auto e = end(r);
181
182 CHECK(*f == 0);
183 CHECK(f[0] == 0);
184 CHECK(f[1] == 1);
185 CHECK(f[2] == 2);
186 CHECK(f[3] == 0);
187 CHECK(f[4] == 1);
188 CHECK(f[5] == 2);
189
190 CHECK(*m == 1);
191 CHECK(m[0] == 1);
192 CHECK(m[1] == 2);
193 CHECK(m[2] == 0);
194 CHECK(m[3] == 1);
195 CHECK(m[4] == 2);
196 CHECK(m[5] == 0);
197
198 CHECK(m[-1] == 0);
199
200 CHECK(*l == 2);
201 CHECK(l[0] == 2);
202 CHECK(l[1] == 0);
203 CHECK(l[2] == 1);
204 CHECK(l[3] == 2);
205 CHECK(l[4] == 0);
206 CHECK(l[5] == 1);
207
208 CHECK(l[-1] == 1);
209 CHECK(l[-2] == 0);
210
211 CHECK(f != e);
212
213 auto cur = f;
214 for (int i = 0; i < 100; ++i, ++cur)
215 {
216 CHECK((next(begin(r), i) - f) == i);
217 CHECK((cur - f) == i);
218 if(i > 0)
219 CHECK((cur - m) == i - 1);
220 if(i > 1)
221 CHECK((cur - l) == i - 2);
222 }
223 }
224
main()225 int main()
226 {
227 // initializer list
228 {
229 auto il = {0, 1, 2};
230 test_random_access_it(il);
231 test_const_forward_reversed_range(il);
232
233 const auto cil = {0, 1, 2};
234 test_random_access_it(cil);
235 test_const_forward_reversed_range(cil);
236 }
237
238 // array
239 {
240 std::array<int, 3> a = {{0, 1, 2}};
241 test_random_access_it(a);
242 test_mutable_forward_range_reversed(a);
243
244 const std::array<int, 3> ca = {{0, 1, 2}};
245 test_random_access_it(ca);
246 test_const_forward_reversed_range(ca);
247 }
248
249 // list
250 {
251 std::list<int> l = {0, 1, 2};
252 test_bidirectional_it(l);
253 test_mutable_forward_range_reversed(l);
254
255 const std::list<int> cl = {0, 1, 2};
256 test_bidirectional_it(cl);
257 test_const_forward_reversed_range(cl);
258 }
259
260 // forward list
261 {
262 std::forward_list<int> l = {0, 1, 2};
263 test_forward_it(l);
264 test_const_forward_range(l);
265
266 const std::forward_list<int> cl = {0, 1, 2};
267 test_forward_it(cl);
268 test_const_forward_range(cl);
269 }
270
271 // move-only types
272 {
273 std::array<std::unique_ptr<int>, 3> a = {{
274 std::unique_ptr<int>(new int(0)),
275 std::unique_ptr<int>(new int(1)),
276 std::unique_ptr<int>(new int(2))
277 }};
278 auto r = a | views::cycle;
279 auto b = iter_move(r.begin() + 4);
280 CHECK((*(b)) == 1);
281 }
282
283 // infinite
284 {
285 int count = 0;
286 auto il = {0, 1, 2};
287 auto v = 10;
288 RANGES_FOR(auto&& i, il | views::cycle)
289 {
290 if (count == 42) { break; }
291 v = i;
292 ++count;
293 }
294 CHECK(count == 42);
295 CHECK(v == 2);
296 }
297
298 // non-bounded
299 {
300 auto sz = views::c_str((char const *)"hi! ");
301 ::check_equal(
302 sz | views::cycle | views::take(10),
303 {'h','i','!',' ','h','i','!',' ','h','i'} );
304
305 auto rng = sz | views::cycle;
306 auto it = ranges::begin(rng);
307 CHECK(*it == 'h');
308 CHECK(*++it == 'i');
309 CHECK(*++it == '!');
310 CHECK(*++it == ' ');
311 CHECK(*++it == 'h');
312 CHECK(*--it == ' ');
313 CHECK(*--it == '!');
314 CHECK(*--it == 'i');
315 CHECK(*--it == 'h');
316
317 rng = sz | views::cycle;
318 it = ranges::begin(rng);
319 it += 4;
320 CHECK(*it == 'h');
321 }
322
323 // Cycle of an infinite range,
324 // https://github.com/ericniebler/range-v3/issues/780
325 {
326 auto view = ranges::views::iota(0)
327 | ranges::views::cycle;
328 CHECK(view[5] == 5);
329 }
330
331 // Composing ranges::views::cycle with ranges::views::slice
332 // https://github.com/ericniebler/range-v3/issues/778
333 {
334 const auto length = 512;
335 const auto k = 16;
336
337 std::vector<int> input(length);
338
339 auto output = ranges::views::cycle(input)
340 | ranges::views::slice(length + k, 2 * length + k);
341
342 CHECK(bool(ranges::begin(output) != ranges::end(output)));
343 CHECK(ranges::size(output) == 512u);
344 CHECK(ranges::distance(output) == 512);
345 }
346 return test_result();
347 }
348