• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2019 T. Zachary Laine
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 #include <boost/stl_interfaces/iterator_interface.hpp>
7 
8 #include "ill_formed.hpp"
9 
10 #include <boost/core/lightweight_test.hpp>
11 
12 #include <algorithm>
13 #include <array>
14 #include <numeric>
15 #include <tuple>
16 #include <type_traits>
17 
18 
19 struct basic_random_access_iter : boost::stl_interfaces::iterator_interface<
20                                       basic_random_access_iter,
21                                       std::random_access_iterator_tag,
22                                       int>
23 {
basic_random_access_iterbasic_random_access_iter24     basic_random_access_iter() {}
basic_random_access_iterbasic_random_access_iter25     basic_random_access_iter(int * it) : it_(it) {}
26 
operator *basic_random_access_iter27     int & operator*() const { return *it_; }
operator +=basic_random_access_iter28     basic_random_access_iter & operator+=(std::ptrdiff_t i)
29     {
30         it_ += i;
31         return *this;
32     }
operator -(basic_random_access_iter lhs,basic_random_access_iter rhs)33     friend std::ptrdiff_t operator-(
34         basic_random_access_iter lhs, basic_random_access_iter rhs) noexcept
35     {
36         return lhs.it_ - rhs.it_;
37     }
38 
39 private:
40     int * it_;
41 };
42 
43 BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(
44     basic_random_access_iter, std::random_access_iterator)
45 BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(
46     basic_random_access_iter,
47     std::random_access_iterator_tag,
48     std::random_access_iterator_tag,
49     int,
50     int &,
51     int *,
52     std::ptrdiff_t)
53 
54 static_assert(
55     boost::stl_interfaces::v1::v1_dtl::
56         plus_eq<basic_random_access_iter, std::ptrdiff_t>::value,
57     "");
58 
59 struct basic_adapted_random_access_iter
60     : boost::stl_interfaces::iterator_interface<
61           basic_adapted_random_access_iter,
62           std::random_access_iterator_tag,
63           int>
64 {
basic_adapted_random_access_iterbasic_adapted_random_access_iter65     basic_adapted_random_access_iter() {}
basic_adapted_random_access_iterbasic_adapted_random_access_iter66     basic_adapted_random_access_iter(int * it) : it_(it) {}
67 
68 private:
69     friend boost::stl_interfaces::access;
base_referencebasic_adapted_random_access_iter70     int *& base_reference() noexcept { return it_; }
base_referencebasic_adapted_random_access_iter71     int * base_reference() const noexcept { return it_; }
72 
73     int * it_;
74 };
75 
76 BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(
77     basic_adapted_random_access_iter, std::random_access_iterator)
78 BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(
79     basic_adapted_random_access_iter,
80     std::random_access_iterator_tag,
81     std::random_access_iterator_tag,
82     int,
83     int &,
84     int *,
85     std::ptrdiff_t)
86 
87 template<typename ValueType>
88 struct adapted_random_access_iter : boost::stl_interfaces::iterator_interface<
89                                         adapted_random_access_iter<ValueType>,
90                                         std::random_access_iterator_tag,
91                                         ValueType>
92 {
adapted_random_access_iteradapted_random_access_iter93     adapted_random_access_iter() {}
adapted_random_access_iteradapted_random_access_iter94     adapted_random_access_iter(ValueType * it) : it_(it) {}
95 
96     template<
97         typename ValueType2,
98         typename Enable = std::enable_if_t<
99             std::is_convertible<ValueType2 *, ValueType *>::value>>
adapted_random_access_iteradapted_random_access_iter100     adapted_random_access_iter(adapted_random_access_iter<ValueType2> other) :
101         it_(other.it_)
102     {}
103 
104     template<typename ValueType2>
105     friend struct adapted_random_access_iter;
106 
107 private:
108     friend boost::stl_interfaces::access;
base_referenceadapted_random_access_iter109     ValueType *& base_reference() noexcept { return it_; }
base_referenceadapted_random_access_iter110     ValueType * base_reference() const noexcept { return it_; }
111 
112     ValueType * it_;
113 };
114 
115 BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(
116     adapted_random_access_iter<int>, std::random_access_iterator)
117 BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(
118     adapted_random_access_iter<int>,
119     std::random_access_iterator_tag,
120     std::random_access_iterator_tag,
121     int,
122     int &,
123     int *,
124     std::ptrdiff_t)
125 BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(
126     adapted_random_access_iter<int const>, std::random_access_iterator)
127 BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(
128     adapted_random_access_iter<int const>,
129     std::random_access_iterator_tag,
130     std::random_access_iterator_tag,
131     int,
132     int const &,
133     int const *,
134     std::ptrdiff_t)
135 
136 template<typename ValueType>
137 struct random_access_iter : boost::stl_interfaces::iterator_interface<
138                                 random_access_iter<ValueType>,
139                                 std::random_access_iterator_tag,
140                                 ValueType>
141 {
random_access_iterrandom_access_iter142     random_access_iter() {}
random_access_iterrandom_access_iter143     random_access_iter(ValueType * it) : it_(it) {}
144     template<
145         typename ValueType2,
146         typename E = std::enable_if_t<
147             std::is_convertible<ValueType2 *, ValueType *>::value>>
random_access_iterrandom_access_iter148     random_access_iter(random_access_iter<ValueType2> it) : it_(it.it_)
149     {}
150 
operator *random_access_iter151     ValueType & operator*() const { return *it_; }
operator +=random_access_iter152     random_access_iter & operator+=(std::ptrdiff_t i)
153     {
154         it_ += i;
155         return *this;
156     }
157     friend std::ptrdiff_t
operator -(random_access_iter lhs,random_access_iter rhs)158     operator-(random_access_iter lhs, random_access_iter rhs) noexcept
159     {
160         return lhs.it_ - rhs.it_;
161     }
162 
163 private:
164     ValueType * it_;
165 
166     template<typename ValueType2>
167     friend struct random_access_iter;
168 };
169 
170 using random_access = random_access_iter<int>;
171 using const_random_access = random_access_iter<int const>;
172 
173 BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(
174     random_access, std::random_access_iterator)
175 BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(
176     random_access,
177     std::random_access_iterator_tag,
178     std::random_access_iterator_tag,
179     int,
180     int &,
181     int *,
182     std::ptrdiff_t)
183 
184 BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(
185     const_random_access, std::random_access_iterator)
186 BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(
187     const_random_access,
188     std::random_access_iterator_tag,
189     std::random_access_iterator_tag,
190     int,
191     int const &,
192     int const *,
193     std::ptrdiff_t)
194 
195 struct zip_iter : boost::stl_interfaces::proxy_iterator_interface<
196                       zip_iter,
197                       std::random_access_iterator_tag,
198                       std::tuple<int, int>,
199                       std::tuple<int &, int &>>
200 {
zip_iterzip_iter201     zip_iter() : it1_(nullptr), it2_(nullptr) {}
zip_iterzip_iter202     zip_iter(int * it1, int * it2) : it1_(it1), it2_(it2) {}
203 
operator *zip_iter204     std::tuple<int &, int &> operator*() const
205     {
206         return std::tuple<int &, int &>{*it1_, *it2_};
207     }
operator +=zip_iter208     zip_iter & operator+=(std::ptrdiff_t i)
209     {
210         it1_ += i;
211         it2_ += i;
212         return *this;
213     }
operator -(zip_iter lhs,zip_iter rhs)214     friend std::ptrdiff_t operator-(zip_iter lhs, zip_iter rhs) noexcept
215     {
216         return lhs.it1_ - rhs.it1_;
217     }
218 
219 private:
220     int * it1_;
221     int * it2_;
222 };
223 
224 using int_pair = std::tuple<int, int>;
225 using int_refs_pair = std::tuple<int &, int &>;
226 
227 BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(
228     zip_iter, std::random_access_iterator)
229 BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(
230     zip_iter,
231     std::random_access_iterator_tag,
232     std::random_access_iterator_tag,
233     int_pair,
234     int_refs_pair,
235     boost::stl_interfaces::proxy_arrow_result<int_refs_pair>,
236     std::ptrdiff_t)
237 
238 struct int_t
239 {
240     int value_;
241 
operator ==int_t242     bool operator==(int_t other) const { return value_ == other.value_; }
operator !=int_t243     bool operator!=(int_t other) const { return value_ != other.value_; }
operator <int_t244     bool operator<(int_t other) const { return value_ < other.value_; }
245 
operator ==int_t246     bool operator==(int other) const { return value_ == other; }
operator !=int_t247     bool operator!=(int other) const { return value_ != other; }
operator <int_t248     bool operator<(int other) const { return value_ < other; }
249 
operator ==(int lhs,int_t rhs)250     friend bool operator==(int lhs, int_t rhs) { return lhs == rhs.value_; }
operator !=(int lhs,int_t rhs)251     friend bool operator!=(int lhs, int_t rhs) { return lhs != rhs.value_; }
operator <(int lhs,int_t rhs)252     friend bool operator<(int lhs, int_t rhs) { return lhs < rhs.value_; }
253 };
254 
255 struct udt_zip_iter : boost::stl_interfaces::proxy_iterator_interface<
256                           udt_zip_iter,
257                           std::random_access_iterator_tag,
258                           std::tuple<int_t, int>,
259                           std::tuple<int_t &, int &>>
260 {
udt_zip_iterudt_zip_iter261     udt_zip_iter() : it1_(nullptr), it2_(nullptr) {}
udt_zip_iterudt_zip_iter262     udt_zip_iter(int_t * it1, int * it2) : it1_(it1), it2_(it2) {}
263 
operator *udt_zip_iter264     std::tuple<int_t &, int &> operator*() const
265     {
266         return std::tuple<int_t &, int &>{*it1_, *it2_};
267     }
operator +=udt_zip_iter268     udt_zip_iter & operator+=(std::ptrdiff_t i)
269     {
270         it1_ += i;
271         it2_ += i;
272         return *this;
273     }
operator -(udt_zip_iter lhs,udt_zip_iter rhs)274     friend std::ptrdiff_t operator-(udt_zip_iter lhs, udt_zip_iter rhs) noexcept
275     {
276         return lhs.it1_ - rhs.it1_;
277     }
278 
279 private:
280     int_t * it1_;
281     int * it2_;
282 };
283 
284 using int_t_int_pair = std::tuple<int_t, int>;
285 using int_t_int_refs_pair = std::tuple<int_t &, int &>;
286 
287 BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(
288     udt_zip_iter, std::random_access_iterator)
289 BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(
290     udt_zip_iter,
291     std::random_access_iterator_tag,
292     std::random_access_iterator_tag,
293     int_t_int_pair,
294     int_t_int_refs_pair,
295     boost::stl_interfaces::proxy_arrow_result<int_t_int_refs_pair>,
296     std::ptrdiff_t)
297 
298 namespace std {
299     // Required for std::sort to work with zip_iter.  If zip_iter::reference
300     // were not a std::tuple with builtin types as its template parameters, we
301     // could have put this in another namespace.
swap(zip_iter::reference && lhs,zip_iter::reference && rhs)302     void swap(zip_iter::reference && lhs, zip_iter::reference && rhs)
303     {
304         using std::swap;
305         swap(std::get<0>(lhs), std::get<0>(rhs));
306         swap(std::get<1>(lhs), std::get<1>(rhs));
307     }
308 }
309 
swap(udt_zip_iter::reference && lhs,udt_zip_iter::reference && rhs)310 void swap(udt_zip_iter::reference && lhs, udt_zip_iter::reference && rhs)
311 {
312     using std::swap;
313     swap(std::get<0>(lhs), std::get<0>(rhs));
314     swap(std::get<1>(lhs), std::get<1>(rhs));
315 }
316 
317 std::array<int, 10> ints = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}};
318 std::array<int, 10> ones = {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}};
319 std::array<std::tuple<int, int>, 10> tuples = {{
320     {0, 1},
321     {1, 1},
322     {2, 1},
323     {3, 1},
324     {4, 1},
325     {5, 1},
326     {6, 1},
327     {7, 1},
328     {8, 1},
329     {9, 1},
330 }};
331 
332 std::array<int_t, 10> udts = {
333     {{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}}};
334 std::array<std::tuple<int_t, int>, 10> udt_tuples = {{
335     std::tuple<int_t, int>{{0}, 1},
336     std::tuple<int_t, int>{{1}, 1},
337     std::tuple<int_t, int>{{2}, 1},
338     std::tuple<int_t, int>{{3}, 1},
339     std::tuple<int_t, int>{{4}, 1},
340     std::tuple<int_t, int>{{5}, 1},
341     std::tuple<int_t, int>{{6}, 1},
342     std::tuple<int_t, int>{{7}, 1},
343     std::tuple<int_t, int>{{8}, 1},
344     std::tuple<int_t, int>{{9}, 1},
345 }};
346 
347 
348 ////////////////////
349 // view_interface //
350 ////////////////////
351 #include "view_tests.hpp"
352 
353 template<typename T>
354 using data_t = decltype(std::declval<T>().data());
355 
356 static_assert(
357     ill_formed<
358         data_t,
359         subrange<
360             basic_random_access_iter,
361             basic_random_access_iter,
362             boost::stl_interfaces::v1::element_layout::discontiguous>>::value,
363     "");
364 static_assert(
365     ill_formed<
366         data_t,
367         subrange<
368             basic_random_access_iter,
369             basic_random_access_iter,
370             boost::stl_interfaces::v1::element_layout::discontiguous> const>::
371         value,
372     "");
373 
374 template<typename T>
375 using back_t = decltype(std::declval<T>().back());
376 
377 static_assert(
378     ill_formed<
379         back_t,
380         subrange<
381             int *,
382             int const *,
383             boost::stl_interfaces::v1::element_layout::discontiguous>>::value,
384     "");
385 static_assert(
386     ill_formed<
387         back_t,
388         subrange<
389             int *,
390             int const *,
391             boost::stl_interfaces::v1::element_layout::discontiguous> const>::
392         value,
393     "");
394 
395 
main()396 int main()
397 {
398 
399 {
400     basic_random_access_iter first(ints.data());
401     basic_random_access_iter last(ints.data() + ints.size());
402 
403     BOOST_TEST(*first == 0);
404     BOOST_TEST(*(first + 1) == 1);
405     BOOST_TEST(*(first + 2) == 2);
406     BOOST_TEST(*(1 + first) == 1);
407     BOOST_TEST(*(2 + first) == 2);
408 
409     BOOST_TEST(first[0] == 0);
410     BOOST_TEST(first[1] == 1);
411     BOOST_TEST(first[2] == 2);
412 
413     BOOST_TEST(*(last - 1) == 9);
414     BOOST_TEST(*(last - 2) == 8);
415     BOOST_TEST(*(last - 3) == 7);
416 
417     BOOST_TEST(last[-1] == 9);
418     BOOST_TEST(last[-2] == 8);
419     BOOST_TEST(last[-3] == 7);
420 
421     BOOST_TEST(last - first == 10);
422     BOOST_TEST(first == first);
423     BOOST_TEST(first != last);
424     BOOST_TEST(first < last);
425     BOOST_TEST(first <= last);
426     BOOST_TEST(first <= first);
427     BOOST_TEST(last > first);
428     BOOST_TEST(last >= first);
429     BOOST_TEST(last >= last);
430 
431     {
432         auto first_copy = first;
433         first_copy += 10;
434         BOOST_TEST(first_copy == last);
435     }
436 
437     {
438         auto last_copy = last;
439         last_copy -= 10;
440         BOOST_TEST(last_copy == first);
441     }
442 }
443 
444 
445 {
446     {
447         std::array<int, 10> ints_copy;
448         basic_random_access_iter first(ints.data());
449         basic_random_access_iter last(ints.data() + ints.size());
450         std::copy(first, last, ints_copy.begin());
451         BOOST_TEST(ints_copy == ints);
452     }
453 
454     {
455         std::array<int, 10> ints_copy;
456         basic_random_access_iter first(ints.data());
457         basic_random_access_iter last(ints.data() + ints.size());
458         std::copy(
459             std::make_reverse_iterator(last),
460             std::make_reverse_iterator(first),
461             ints_copy.begin());
462         std::reverse(ints_copy.begin(), ints_copy.end());
463         BOOST_TEST(ints_copy == ints);
464     }
465 
466     {
467         std::array<int, 10> iota_ints;
468         basic_random_access_iter first(iota_ints.data());
469         basic_random_access_iter last(iota_ints.data() + iota_ints.size());
470         std::iota(first, last, 0);
471         BOOST_TEST(iota_ints == ints);
472     }
473 
474     {
475         std::array<int, 10> iota_ints;
476         basic_random_access_iter first(iota_ints.data());
477         basic_random_access_iter last(iota_ints.data() + iota_ints.size());
478         std::iota(
479             std::make_reverse_iterator(last),
480             std::make_reverse_iterator(first),
481             0);
482         std::reverse(iota_ints.begin(), iota_ints.end());
483         BOOST_TEST(iota_ints == ints);
484     }
485 
486     {
487         std::array<int, 10> iota_ints;
488         basic_random_access_iter first(iota_ints.data());
489         basic_random_access_iter last(iota_ints.data() + iota_ints.size());
490         std::iota(
491             std::make_reverse_iterator(last),
492             std::make_reverse_iterator(first),
493             0);
494         std::sort(first, last);
495         BOOST_TEST(iota_ints == ints);
496     }
497 }
498 
499 
500 {
501     basic_adapted_random_access_iter first(ints.data());
502     basic_adapted_random_access_iter last(ints.data() + ints.size());
503 
504     BOOST_TEST(*first == 0);
505     BOOST_TEST(*(first + 1) == 1);
506     BOOST_TEST(*(first + 2) == 2);
507     BOOST_TEST(*(1 + first) == 1);
508     BOOST_TEST(*(2 + first) == 2);
509 
510     BOOST_TEST(first[0] == 0);
511     BOOST_TEST(first[1] == 1);
512     BOOST_TEST(first[2] == 2);
513 
514     BOOST_TEST(*(last - 1) == 9);
515     BOOST_TEST(*(last - 2) == 8);
516     BOOST_TEST(*(last - 3) == 7);
517 
518     BOOST_TEST(last[-1] == 9);
519     BOOST_TEST(last[-2] == 8);
520     BOOST_TEST(last[-3] == 7);
521 
522     BOOST_TEST(last - first == 10);
523     BOOST_TEST(first == first);
524     BOOST_TEST(first != last);
525     BOOST_TEST(first < last);
526     BOOST_TEST(first <= last);
527     BOOST_TEST(first <= first);
528     BOOST_TEST(last > first);
529     BOOST_TEST(last >= first);
530     BOOST_TEST(last >= last);
531 
532     {
533         auto first_copy = first;
534         first_copy += 10;
535         BOOST_TEST(first_copy == last);
536     }
537 
538     {
539         auto last_copy = last;
540         last_copy -= 10;
541         BOOST_TEST(last_copy == first);
542     }
543 }
544 
545 
546 {
547     {
548         std::array<int, 10> ints_copy;
549         basic_adapted_random_access_iter first(ints.data());
550         basic_adapted_random_access_iter last(ints.data() + ints.size());
551         std::copy(first, last, ints_copy.begin());
552         BOOST_TEST(ints_copy == ints);
553     }
554 
555     {
556         std::array<int, 10> ints_copy;
557         basic_adapted_random_access_iter first(ints.data());
558         basic_adapted_random_access_iter last(ints.data() + ints.size());
559         std::copy(
560             std::make_reverse_iterator(last),
561             std::make_reverse_iterator(first),
562             ints_copy.begin());
563         std::reverse(ints_copy.begin(), ints_copy.end());
564         BOOST_TEST(ints_copy == ints);
565     }
566 
567     {
568         std::array<int, 10> iota_ints;
569         basic_adapted_random_access_iter first(iota_ints.data());
570         basic_adapted_random_access_iter last(
571             iota_ints.data() + iota_ints.size());
572         std::iota(first, last, 0);
573         BOOST_TEST(iota_ints == ints);
574     }
575 
576     {
577         std::array<int, 10> iota_ints;
578         basic_adapted_random_access_iter first(iota_ints.data());
579         basic_adapted_random_access_iter last(
580             iota_ints.data() + iota_ints.size());
581         std::iota(
582             std::make_reverse_iterator(last),
583             std::make_reverse_iterator(first),
584             0);
585         std::reverse(iota_ints.begin(), iota_ints.end());
586         BOOST_TEST(iota_ints == ints);
587     }
588 
589     {
590         std::array<int, 10> iota_ints;
591         basic_adapted_random_access_iter first(iota_ints.data());
592         basic_adapted_random_access_iter last(
593             iota_ints.data() + iota_ints.size());
594         std::iota(
595             std::make_reverse_iterator(last),
596             std::make_reverse_iterator(first),
597             0);
598         std::sort(first, last);
599         BOOST_TEST(iota_ints == ints);
600     }
601 }
602 
603 
604 {
605     {
606         random_access first(ints.data());
607         random_access last(ints.data() + ints.size());
608         const_random_access first_copy(first);
609         const_random_access last_copy(last);
610         std::equal(first, last, first_copy, last_copy);
611     }
612 
613     {
614         adapted_random_access_iter<int> first(ints.data());
615         adapted_random_access_iter<int> last(ints.data() + ints.size());
616         adapted_random_access_iter<int const> first_copy(
617             (int const *)ints.data());
618         adapted_random_access_iter<int const> last_copy(
619             (int const *)ints.data() + ints.size());
620         std::equal(first, last, first_copy, last_copy);
621     }
622 }
623 
624 
625 {
626     {
627         random_access first(ints.data());
628         random_access last(ints.data() + ints.size());
629         const_random_access first_const(first);
630         const_random_access last_const(last);
631 
632         BOOST_TEST(first == first_const);
633         BOOST_TEST(first_const == first);
634         BOOST_TEST(first != last_const);
635         BOOST_TEST(last_const != first);
636         BOOST_TEST(first <= first_const);
637         BOOST_TEST(first_const <= first);
638         BOOST_TEST(first >= first_const);
639         BOOST_TEST(first_const >= first);
640         BOOST_TEST(last_const > first);
641         BOOST_TEST(last > first_const);
642         BOOST_TEST(first_const < last);
643         BOOST_TEST(first < last_const);
644     }
645 
646     {
647         adapted_random_access_iter<int> first(ints.data());
648         adapted_random_access_iter<int> last(ints.data() + ints.size());
649         adapted_random_access_iter<int const> first_const(first);
650         adapted_random_access_iter<int const> last_const(last);
651 
652         BOOST_TEST(first == first_const);
653         BOOST_TEST(first_const == first);
654         BOOST_TEST(first != last_const);
655         BOOST_TEST(last_const != first);
656         BOOST_TEST(first <= first_const);
657         BOOST_TEST(first_const <= first);
658         BOOST_TEST(first >= first_const);
659         BOOST_TEST(first_const >= first);
660         BOOST_TEST(last_const > first);
661         BOOST_TEST(last > first_const);
662         BOOST_TEST(first_const < last);
663         BOOST_TEST(first < last_const);
664     }
665 }
666 
667 
668 {
669     {
670         random_access first(ints.data());
671         random_access last(ints.data() + ints.size());
672         while (first != last)
673             first++;
674     }
675 
676     {
677         random_access first(ints.data());
678         random_access last(ints.data() + ints.size());
679         while (first != last)
680             last--;
681     }
682 
683     {
684         basic_random_access_iter first(ints.data());
685         basic_random_access_iter last(ints.data() + ints.size());
686         while (first != last)
687             first++;
688     }
689 
690     {
691         basic_random_access_iter first(ints.data());
692         basic_random_access_iter last(ints.data() + ints.size());
693         while (first != last)
694             last--;
695     }
696 
697     {
698         basic_adapted_random_access_iter first(ints.data());
699         basic_adapted_random_access_iter last(ints.data() + ints.size());
700         while (first != last)
701             first++;
702     }
703 
704     {
705         basic_adapted_random_access_iter first(ints.data());
706         basic_adapted_random_access_iter last(ints.data() + ints.size());
707         while (first != last)
708             last--;
709     }
710 }
711 
712 
713 {
714     random_access first(ints.data());
715     random_access last(ints.data() + ints.size());
716 
717     BOOST_TEST(*first == 0);
718     BOOST_TEST(*(first + 1) == 1);
719     BOOST_TEST(*(first + 2) == 2);
720     BOOST_TEST(*(1 + first) == 1);
721     BOOST_TEST(*(2 + first) == 2);
722 
723     BOOST_TEST(first[0] == 0);
724     BOOST_TEST(first[1] == 1);
725     BOOST_TEST(first[2] == 2);
726 
727     BOOST_TEST(*(last - 1) == 9);
728     BOOST_TEST(*(last - 2) == 8);
729     BOOST_TEST(*(last - 3) == 7);
730 
731     BOOST_TEST(last[-1] == 9);
732     BOOST_TEST(last[-2] == 8);
733     BOOST_TEST(last[-3] == 7);
734 
735     BOOST_TEST(last - first == 10);
736     BOOST_TEST(first == first);
737     BOOST_TEST(first != last);
738     BOOST_TEST(first < last);
739     BOOST_TEST(first <= last);
740     BOOST_TEST(first <= first);
741     BOOST_TEST(last > first);
742     BOOST_TEST(last >= first);
743     BOOST_TEST(last >= last);
744 
745     {
746         auto first_copy = first;
747         first_copy += 10;
748         BOOST_TEST(first_copy == last);
749     }
750 
751     {
752         auto last_copy = last;
753         last_copy -= 10;
754         BOOST_TEST(last_copy == first);
755     }
756 }
757 
758 
759 {
760     random_access first(ints.data());
761     random_access last(ints.data() + ints.size());
762 
763     {
764         std::array<int, 10> ints_copy;
765         std::copy(first, last, ints_copy.begin());
766         BOOST_TEST(ints_copy == ints);
767     }
768 
769     {
770         std::array<int, 10> ints_copy;
771         std::copy(
772             std::make_reverse_iterator(last),
773             std::make_reverse_iterator(first),
774             ints_copy.begin());
775         std::reverse(ints_copy.begin(), ints_copy.end());
776         BOOST_TEST(ints_copy == ints);
777     }
778 
779     {
780         std::array<int, 10> iota_ints;
781         random_access first(iota_ints.data());
782         random_access last(iota_ints.data() + iota_ints.size());
783         std::iota(first, last, 0);
784         BOOST_TEST(iota_ints == ints);
785     }
786 
787     {
788         std::array<int, 10> iota_ints;
789         random_access first(iota_ints.data());
790         random_access last(iota_ints.data() + iota_ints.size());
791         std::iota(
792             std::make_reverse_iterator(last),
793             std::make_reverse_iterator(first),
794             0);
795         std::reverse(iota_ints.begin(), iota_ints.end());
796         BOOST_TEST(iota_ints == ints);
797     }
798 
799     {
800         std::array<int, 10> iota_ints;
801         random_access first(iota_ints.data());
802         random_access last(iota_ints.data() + iota_ints.size());
803         std::iota(
804             std::make_reverse_iterator(last),
805             std::make_reverse_iterator(first),
806             0);
807         std::sort(first, last);
808         BOOST_TEST(iota_ints == ints);
809     }
810 }
811 
812 
813 {
814     const_random_access first(ints.data());
815     const_random_access last(ints.data() + ints.size());
816 
817     {
818         std::array<int, 10> ints_copy;
819         std::copy(first, last, ints_copy.begin());
820         BOOST_TEST(ints_copy == ints);
821     }
822 
823     {
824         BOOST_TEST(std::binary_search(first, last, 3));
825         BOOST_TEST(std::binary_search(
826             std::make_reverse_iterator(last),
827             std::make_reverse_iterator(first),
828             3,
829             std::greater<>{}));
830     }
831 }
832 
833 
834 {
835     {
836         zip_iter first(ints.data(), ones.data());
837         zip_iter last(ints.data() + ints.size(), ones.data() + ones.size());
838         BOOST_TEST(std::equal(first, last, tuples.begin(), tuples.end()));
839     }
840 
841     {
842         auto ints_copy = ints;
843         std::reverse(ints_copy.begin(), ints_copy.end());
844         auto ones_copy = ones;
845         zip_iter first(ints_copy.data(), ones_copy.data());
846         zip_iter last(
847             ints_copy.data() + ints_copy.size(),
848             ones_copy.data() + ones_copy.size());
849         BOOST_TEST(!std::equal(first, last, tuples.begin(), tuples.end()));
850         std::sort(first, last);
851         BOOST_TEST(std::equal(first, last, tuples.begin(), tuples.end()));
852     }
853 
854     {
855         udt_zip_iter first(udts.data(), ones.data());
856         udt_zip_iter last(udts.data() + udts.size(), ones.data() + ones.size());
857         BOOST_TEST(
858             std::equal(first, last, udt_tuples.begin(), udt_tuples.end()));
859     }
860 
861     {
862         auto udts_copy = udts;
863         std::reverse(udts_copy.begin(), udts_copy.end());
864         auto ones_copy = ones;
865         udt_zip_iter first(udts_copy.data(), ones_copy.data());
866         udt_zip_iter last(
867             udts_copy.data() + udts_copy.size(),
868             ones_copy.data() + ones_copy.size());
869         BOOST_TEST(
870             !std::equal(first, last, udt_tuples.begin(), udt_tuples.end()));
871         std::sort(first, last);
872         BOOST_TEST(
873             std::equal(first, last, udt_tuples.begin(), udt_tuples.end()));
874     }
875 }
876 
877 {
878     basic_random_access_iter first(ints.data());
879     basic_random_access_iter last(ints.data() + ints.size());
880 
881     auto r = range<boost::stl_interfaces::v1::element_layout::contiguous>(
882         first, last);
883     auto empty = range<boost::stl_interfaces::v1::element_layout::contiguous>(
884         first, first);
885 
886     // range begin/end
887     {
888         std::array<int, 10> ints_copy;
889         std::copy(r.begin(), r.end(), ints_copy.begin());
890         BOOST_TEST(ints_copy == ints);
891 
892         BOOST_TEST(empty.begin() == empty.end());
893     }
894 
895     // empty/op bool
896     {
897         BOOST_TEST(!r.empty());
898         BOOST_TEST(r);
899 
900         BOOST_TEST(empty.empty());
901         BOOST_TEST(!empty);
902 
903         auto const cr = r;
904         BOOST_TEST(!cr.empty());
905         BOOST_TEST(cr);
906 
907         auto const cempty = empty;
908         BOOST_TEST(cempty.empty());
909         BOOST_TEST(!cempty);
910     }
911 
912     // data
913     {
914         BOOST_TEST(r.data() != nullptr);
915         BOOST_TEST(r.data()[2] == 2);
916 
917         BOOST_TEST(empty.data() != nullptr);
918 
919         auto const cr = r;
920         BOOST_TEST(cr.data() != nullptr);
921         BOOST_TEST(cr.data()[2] == 2);
922 
923         auto const cempty = empty;
924         BOOST_TEST(cempty.data() != nullptr);
925     }
926 
927     // size
928     {
929         BOOST_TEST(r.size() == 10u);
930 
931         BOOST_TEST(empty.size() == 0u);
932 
933         auto const cr = r;
934         BOOST_TEST(cr.size() == 10u);
935 
936         auto const cempty = empty;
937         BOOST_TEST(cempty.size() == 0u);
938     }
939 
940     // front/back
941     {
942         BOOST_TEST(r.front() == 0);
943         BOOST_TEST(r.back() == 9);
944 
945         auto const cr = r;
946         BOOST_TEST(cr.front() == 0);
947         BOOST_TEST(cr.back() == 9);
948     }
949 
950     // op[]
951     {
952         BOOST_TEST(r[2] == 2);
953 
954         auto const cr = r;
955         BOOST_TEST(cr[2] == 2);
956     }
957 }
958 
959 
960 {
961     zip_iter first(ints.data(), ones.data());
962     zip_iter last(ints.data() + ints.size(), ones.data() + ones.size());
963 
964     auto r = range<boost::stl_interfaces::v1::element_layout::discontiguous>(
965         first, last);
966     auto empty =
967         range<boost::stl_interfaces::v1::element_layout::discontiguous>(
968             first, first);
969 
970     // range begin/end
971     {
972         BOOST_TEST(std::equal(first, last, tuples.begin(), tuples.end()));
973     }
974 
975     // empty/op bool
976     {
977         BOOST_TEST(!r.empty());
978         BOOST_TEST(r);
979 
980         BOOST_TEST(empty.empty());
981         BOOST_TEST(!empty);
982 
983         auto const cr = r;
984         BOOST_TEST(!cr.empty());
985         BOOST_TEST(cr);
986 
987         auto const cempty = empty;
988         BOOST_TEST(cempty.empty());
989         BOOST_TEST(!cempty);
990     }
991 
992     // size
993     {
994         BOOST_TEST(r.size() == 10u);
995 
996         BOOST_TEST(empty.size() == 0u);
997 
998         auto const cr = r;
999         BOOST_TEST(cr.size() == 10u);
1000 
1001         auto const cempty = empty;
1002         BOOST_TEST(cempty.size() == 0u);
1003     }
1004 
1005     // front/back
1006     {
1007         BOOST_TEST(r.front() == (std::tuple<int, int>(0, 1)));
1008         BOOST_TEST(r.back() == (std::tuple<int, int>(9, 1)));
1009 
1010         auto const cr = r;
1011         BOOST_TEST(cr.front() == (std::tuple<int, int>(0, 1)));
1012         BOOST_TEST(cr.back() == (std::tuple<int, int>(9, 1)));
1013     }
1014 
1015     // op[]
1016     {
1017         BOOST_TEST(r[2] == (std::tuple<int, int>(2, 1)));
1018 
1019         auto const cr = r;
1020         BOOST_TEST(cr[2] == (std::tuple<int, int>(2, 1)));
1021     }
1022 }
1023 
1024     return boost::report_errors();
1025 }
1026