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