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