1 // Range v3 library
2 //
3 //  Copyright Gonzalo Brito Gadeschi 2015
4 //
5 //  Use, modification and distribution is subject to the
6 //  Boost Software License, Version 1.0. (See accompanying
7 //  file LICENSE_1_0.txt or copy at
8 //  http://www.boost.org/LICENSE_1_0.txt)
9 //
10 // Project home: https://github.com/ericniebler/range-v3
11 
12 #include <range/v3/detail/config.hpp>
13 
14 #if RANGES_CXX_CONSTEXPR >= RANGES_CXX_CONSTEXPR_14
15 
16 #include <range/v3/range/access.hpp>
17 #include <range/v3/range/operations.hpp>
18 #include <range/v3/range/primitives.hpp>
19 #include <range/v3/utility/addressof.hpp>
20 
21 #include "array.hpp"
22 #include "test_iterators.hpp"
23 
24 // Test sequence 1,2,3,4
25 template<typename It>
test_it_back(It,It last,std::bidirectional_iterator_tag)26 constexpr /*c++14*/ auto test_it_back(It, It last,
27     std::bidirectional_iterator_tag) -> bool
28 {
29     auto end_m1_2 = It{ranges::prev(last, 1)};
30     if (*end_m1_2 != 4) { return false; }
31     return true;
32 }
33 
34 template<typename It, typename Concept>
test_it_back(It,It,Concept)35 constexpr /*c++14*/ auto test_it_back(It, It, Concept) -> bool
36 {
37     return true;
38 }
39 
40 template<typename It>
test_it_(It beg,It last)41 constexpr /*c++14*/ auto test_it_(It beg, It last) -> bool
42 {
43     if (*beg != 1) { return false; }
44     if (ranges::distance(beg, last) != 4) { return false; }
45     if (ranges::next(beg, 4) != last) { return false; }
46     auto end_m1 = It{ranges::next(beg, 3)};
47     if (*end_m1 != 4) { return false; }
48 
49     if (!test_it_back(beg, last, ranges::iterator_tag_of<It>{})) { return false; }
50     auto end2 = beg;
51     ranges::advance(end2, last);
52     if (end2 != last) { return false; }
53     auto end3 = beg;
54     ranges::advance(end3, 4);
55     if (end3 != last) { return false; }
56     if (ranges::iter_enumerate(beg, last) != std::pair<std::ptrdiff_t, It>{4, last})
57     {
58         return false;
59     }
60     if (ranges::iter_distance(beg, last) != 4) { return false; }
61     if (ranges::iter_distance_compare(beg, last, 4) != 0) { return false; }
62     if (ranges::iter_distance_compare(beg, last, 3) != 1) { return false; }
63     if (ranges::iter_distance_compare(beg, last, 5) != -1) { return false; }
64     return true;
65 }
66 
67 // Test sequence 4,3,2,1 (for reverse iterators)
68 template<typename It>
test_rit_(It beg,It last)69 constexpr /*c++14*/ auto test_rit_(It beg, It last) -> bool
70 {
71     if (ranges::distance(beg, last) != 4) { return false; }
72     if (ranges::next(beg, 4) != last) { return false; }
73     auto end_m1 = It{ranges::next(beg, 3)};
74     if (*end_m1 != 1) { return false; }
75     if (ranges::detail::is_convertible<ranges::iterator_tag_of<It>,
76                                        std::bidirectional_iterator_tag>{})
77     {
78         auto end_m1_2 = It{ranges::prev(last, 1)};
79         if (*end_m1_2 != 1) { return false; }
80     }
81     auto end2 = beg;
82     ranges::advance(end2, last);
83     if (end2 != last) { return false; }
84     auto end3 = beg;
85     ranges::advance(end3, 4);
86     if (end3 != last) { return false; }
87     using D = ranges::iter_difference_t<It>;
88     if (ranges::iter_enumerate(beg, last) != std::pair<D, It>{4, last})
89     {
90         return false;
91     }
92     if (ranges::iter_distance(beg, last) != 4) { return false; }
93     if (ranges::iter_distance_compare(beg, last, 4) != 0) { return false; }
94     if (ranges::iter_distance_compare(beg, last, 3) != 1) { return false; }
95     if (ranges::iter_distance_compare(beg, last, 5) != -1) { return false; }
96     return true;
97 }
98 
99 template<typename It, typename Sequence1234>
test_it(Sequence1234 && a)100 constexpr /*c++14*/ auto test_it(Sequence1234&& a) -> bool
101 {
102     auto beg = It{ranges::begin(a)};
103     auto last = It{ranges::end(a)};
104     return test_it_(beg, last);
105 }
106 
107 template<typename Sequence1234>
test_its_c(Sequence1234 && a)108 constexpr /*c++14*/ auto test_its_c(Sequence1234&& a) -> bool
109 {
110     return     test_it<InputIterator<int const *>>(a)
111             && test_it<ForwardIterator<int const *>>(a)
112             && test_it<BidirectionalIterator<int const *>>(a)
113             && test_it<RandomAccessIterator<int const *>>(a);
114 
115 }
116 
117 template<typename Sequence1234>
test_its(Sequence1234 && a)118 constexpr /*c++14*/ auto test_its(Sequence1234&& a) -> bool
119 {
120     return     test_it<InputIterator<int *>>(a)
121             && test_it<ForwardIterator<int *>>(a)
122             && test_it<BidirectionalIterator<int *>>(a)
123             && test_it<RandomAccessIterator<int *>>(a)
124             && test_its_c(a);
125 
126 }
127 
128 template<typename It, typename Sequence1234>
test_rit(Sequence1234 && a)129 constexpr /*c++14*/ auto test_rit(Sequence1234&& a) -> bool
130 {
131     auto beg = It{ranges::rbegin(a)};
132     auto last = It{ranges::rend(a)};
133     return test_rit_(beg, last);
134 }
135 
136 template<typename Sequence1234>
test_rits(Sequence1234 && a)137 constexpr /*c++14*/ auto test_rits(Sequence1234&& a) -> bool
138 {
139     using rit = decltype(ranges::rbegin(a));
140     return     test_rit<BidirectionalIterator<rit>>(a)
141             && test_rit<BidirectionalIterator<rit>>(a);
142 }
143 
144 template<typename It, typename Sequence1234>
test_cit(Sequence1234 && a)145 constexpr /*c++14*/ auto test_cit(Sequence1234&& a) -> bool
146 {
147     auto beg = It{ranges::cbegin(a)};
148     auto last = It{ranges::cend(a)};
149     return test_it_(beg, last);
150 }
151 
152 template<typename Sequence1234>
test_cits(Sequence1234 && a)153 constexpr /*c++14*/ auto test_cits(Sequence1234&& a) -> bool
154 {
155     return     test_cit<InputIterator<int const *>>(a)
156             && test_cit<ForwardIterator<int const *>>(a)
157             && test_cit<BidirectionalIterator<int const *>>(a)
158             && test_cit<RandomAccessIterator<int const *>>(a);
159 }
160 
161 
162 template<typename It, typename Sequence1234>
test_crit(Sequence1234 && a)163 constexpr /*c++14*/ auto test_crit(Sequence1234&& a) -> bool
164 {
165     auto beg = It{ranges::crbegin(a)};
166     auto last = It{ranges::crend(a)};
167     return test_rit_(beg, last);
168 }
169 
170 template<typename Sequence1234>
test_crits(Sequence1234 && a)171 constexpr /*c++14*/ auto test_crits(Sequence1234&& a) -> bool
172 {
173     using rit = decltype(ranges::crbegin(a));
174     return     test_crit<BidirectionalIterator<rit>>(a)
175             && test_crit<RandomAccessIterator<rit>>(a);
176 }
177 
178 template<typename Sequence1234>
test_non_member_f(Sequence1234 && a)179 constexpr /*c++14*/ auto test_non_member_f(Sequence1234&& a) -> bool
180 {
181     if (ranges::empty(a)) { return false; }
182     if (ranges::front(a) != 1) { return false; }
183     if (ranges::back(a) != 4) { return false; }
184     if (ranges::index(a, 2) != 3) { return false; }
185     if (ranges::at(a, 2) != 3) { return false; }
186     if (ranges::size(a) != 4) { return false; }
187     return true;
188 }
189 
test_array()190 constexpr /*c++14*/ auto test_array() -> bool
191 {
192     test::array<int, 4> a{{1, 2, 3, 4}};
193 
194     auto beg = ranges::begin(a);
195     auto three = ranges::next(beg, 2);
196 
197     if ((false)) {
198       ranges::iter_swap(beg, three);
199       if (*beg != 3) { return false; }
200       if (*three != 1) { return false; }
201       ranges::iter_swap(beg, three);
202     }
203 
204     if (!test_its(a)) { return false; }
205     if (!test_cits(a)) { return false; }
206     if (!test_rits(a)) { return false; }
207     if (!test_crits(a)) { return false; }
208     if (!test_non_member_f(a)) { return false; }
209 
210     // This can be worked around but is just bad:
211     test::array<int, 4> b{{5, 6, 7, 8}};
212     ranges::swap(a, b);
213     if (a[0] != 5 || b[0] != 1 || a[3] != 8 || b[3] != 4) { return false; }
214 
215     return true;
216 }
217 
test_c_array()218 constexpr /*c++14*/ auto test_c_array() -> bool
219 {
220     int a[4]{1, 2, 3, 4};
221     if (!test_its(a)) { return false; }
222     if (!test_cits(a)) { return false; }
223     if (!test_rits(a)) { return false; }
224     if (!test_crits(a)) { return false; }
225     if (!test_non_member_f(a)) { return false; }
226 
227     // C-arrays have no associated namespace, so this can't work:
228     // int b[4]{5, 6, 7, 8};
229     // ranges::swap(a, b);
230     // if (a[0] != 5 || b[0] != 1 || a[3] != 8 || b[3] != 4) { return false; }
231 
232     return true;
233 }
234 
test_init_list()235 constexpr /*c++14*/ auto test_init_list() -> bool
236 {
237     std::initializer_list<int> a{1, 2, 3, 4};
238     if (!test_its_c(a)) { return false; }
239     if (!test_cits(a)) { return false; }
240     if (!test_rits(a)) { return false; }
241     if (!test_crits(a)) { return false; }
242     if (!test_non_member_f(a)) { return false; }
243 
244     std::initializer_list<int> b{5, 6, 7, 8};
245     ranges::swap(a, b);
246     if (ranges::at(a, 0) != 5 || ranges::at(b, 0) != 1
247         || ranges::at(a, 3) != 8 || ranges::at(b, 3) != 4)
248     {
249         return false;
250     }
251 
252     return true;
253 }
254 
255 #ifdef __cpp_lib_addressof_constexpr
256 #define ADDR_CONSTEXPR constexpr
257 #else
258 #define ADDR_CONSTEXPR
259 #endif
260 
261 namespace addr {
262     struct Good { };
263     struct Bad { void operator&() const; };
264     struct Bad2 { friend void operator&(Bad2); };
265 }
266 
test_constexpr_addressof()267 void test_constexpr_addressof() {
268     static constexpr int i = 0;
269     static constexpr int const* pi = ranges::detail::addressof(i);
270     static_assert(&i == pi, "");
271 
272     static constexpr addr::Good g = {};
273     static constexpr addr::Good const* pg = ranges::detail::addressof(g);
274     static_assert(&g == pg, "");
275 
276     static constexpr addr::Bad b = {};
277     static ADDR_CONSTEXPR addr::Bad const* pb = ranges::detail::addressof(b);
278 
279     static constexpr addr::Bad2 b2 = {};
280     static ADDR_CONSTEXPR addr::Bad2 const* pb2 = ranges::detail::addressof(b2);
281 
282 #ifdef __cpp_lib_addressof_constexpr
283     static_assert(std::addressof(b) == pb, "");
284     static_assert(std::addressof(b2) == pb2, "");
285 #else
286     (void)pb;
287     (void)pb2;
288 #endif
289 }
290 
main()291 int main()
292 {
293     static_assert(test_array(), "");
294     static_assert(test_c_array(), "");
295     static_assert(test_init_list(), "");
296 }
297 
298 #else
main()299 int main() {}
300 #endif
301