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 <list>
16 #include <type_traits>
17
18
19 struct basic_bidirectional_iter : boost::stl_interfaces::iterator_interface<
20 basic_bidirectional_iter,
21 std::bidirectional_iterator_tag,
22 int>
23 {
basic_bidirectional_iterbasic_bidirectional_iter24 basic_bidirectional_iter() : it_(nullptr) {}
basic_bidirectional_iterbasic_bidirectional_iter25 basic_bidirectional_iter(int * it) : it_(it) {}
26
operator *basic_bidirectional_iter27 int & operator*() const { return *it_; }
operator ++basic_bidirectional_iter28 basic_bidirectional_iter & operator++()
29 {
30 ++it_;
31 return *this;
32 }
operator --basic_bidirectional_iter33 basic_bidirectional_iter & operator--()
34 {
35 --it_;
36 return *this;
37 }
operator ==(basic_bidirectional_iter lhs,basic_bidirectional_iter rhs)38 friend bool operator==(
39 basic_bidirectional_iter lhs, basic_bidirectional_iter rhs) noexcept
40 {
41 return lhs.it_ == rhs.it_;
42 }
43
44 using base_type = boost::stl_interfaces::iterator_interface<
45 basic_bidirectional_iter,
46 std::bidirectional_iterator_tag,
47 int>;
48 using base_type::operator++;
49 using base_type::operator--;
50
51 private:
52 int * it_;
53 };
54
55 BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(
56 basic_bidirectional_iter, std::bidirectional_iterator)
57 BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(
58 basic_bidirectional_iter,
59 std::bidirectional_iterator_tag,
60 std::bidirectional_iterator_tag,
61 int,
62 int &,
63 int *,
64 std::ptrdiff_t)
65
66 static_assert(
67 !boost::stl_interfaces::v1::v1_dtl::
68 plus_eq<basic_bidirectional_iter, std::ptrdiff_t>::value,
69 "");
70
71 struct basic_adapted_bidirectional_ptr_iter
72 : boost::stl_interfaces::iterator_interface<
73 basic_adapted_bidirectional_ptr_iter,
74 std::bidirectional_iterator_tag,
75 int>
76 {
basic_adapted_bidirectional_ptr_iterbasic_adapted_bidirectional_ptr_iter77 basic_adapted_bidirectional_ptr_iter() : it_(nullptr) {}
basic_adapted_bidirectional_ptr_iterbasic_adapted_bidirectional_ptr_iter78 basic_adapted_bidirectional_ptr_iter(int * it) : it_(it) {}
79
80 private:
81 friend boost::stl_interfaces::access;
base_referencebasic_adapted_bidirectional_ptr_iter82 int *& base_reference() noexcept { return it_; }
base_referencebasic_adapted_bidirectional_ptr_iter83 int * base_reference() const noexcept { return it_; }
84
85 int * it_;
86 };
87
88 BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(
89 basic_adapted_bidirectional_ptr_iter, std::bidirectional_iterator)
90 BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(
91 basic_adapted_bidirectional_ptr_iter,
92 std::bidirectional_iterator_tag,
93 std::bidirectional_iterator_tag,
94 int,
95 int &,
96 int *,
97 std::ptrdiff_t)
98
99 struct basic_adapted_bidirectional_list_iter
100 : boost::stl_interfaces::iterator_interface<
101 basic_adapted_bidirectional_list_iter,
102 std::bidirectional_iterator_tag,
103 int>
104 {
basic_adapted_bidirectional_list_iterbasic_adapted_bidirectional_list_iter105 basic_adapted_bidirectional_list_iter() : it_() {}
basic_adapted_bidirectional_list_iterbasic_adapted_bidirectional_list_iter106 basic_adapted_bidirectional_list_iter(std::list<int>::iterator it) : it_(it)
107 {}
108
109 private:
110 friend boost::stl_interfaces::access;
base_referencebasic_adapted_bidirectional_list_iter111 std::list<int>::iterator & base_reference() noexcept { return it_; }
base_referencebasic_adapted_bidirectional_list_iter112 std::list<int>::iterator base_reference() const noexcept { return it_; }
113
114 std::list<int>::iterator it_;
115 };
116
117 BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(
118 basic_adapted_bidirectional_list_iter, std::bidirectional_iterator)
119 BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(
120 basic_adapted_bidirectional_list_iter,
121 std::bidirectional_iterator_tag,
122 std::bidirectional_iterator_tag,
123 int,
124 int &,
125 int *,
126 std::ptrdiff_t)
127
128 template<typename ValueType>
129 struct adapted_bidirectional_ptr_iter
130 : boost::stl_interfaces::iterator_interface<
131 adapted_bidirectional_ptr_iter<ValueType>,
132 std::bidirectional_iterator_tag,
133 ValueType>
134 {
adapted_bidirectional_ptr_iteradapted_bidirectional_ptr_iter135 adapted_bidirectional_ptr_iter() : it_(nullptr) {}
adapted_bidirectional_ptr_iteradapted_bidirectional_ptr_iter136 adapted_bidirectional_ptr_iter(ValueType * it) : it_(it) {}
137
138 template<typename ValueType2>
adapted_bidirectional_ptr_iteradapted_bidirectional_ptr_iter139 adapted_bidirectional_ptr_iter(
140 adapted_bidirectional_ptr_iter<ValueType2> other) :
141 it_(other.it_)
142 {}
143
144 template<typename ValueType2>
145 friend struct adapted_bidirectional_ptr_iter;
146
147 private:
148 friend boost::stl_interfaces::access;
base_referenceadapted_bidirectional_ptr_iter149 ValueType *& base_reference() noexcept { return it_; }
base_referenceadapted_bidirectional_ptr_iter150 ValueType * base_reference() const noexcept { return it_; }
151
152 ValueType * it_;
153 };
154
155 static_assert(
156 !boost::stl_interfaces::v1_dtl::ra_iter<
157 adapted_bidirectional_ptr_iter<int>>::value,
158 "");
159 static_assert(
160 !boost::stl_interfaces::v1_dtl::ra_iter<
161 adapted_bidirectional_ptr_iter<int const>>::value,
162 "");
163
164 BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(
165 adapted_bidirectional_ptr_iter<int>, std::bidirectional_iterator)
166 BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(
167 adapted_bidirectional_ptr_iter<int>,
168 std::bidirectional_iterator_tag,
169 std::bidirectional_iterator_tag,
170 int,
171 int &,
172 int *,
173 std::ptrdiff_t)
174 BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(
175 adapted_bidirectional_ptr_iter<int const>, std::bidirectional_iterator)
176 BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(
177 adapted_bidirectional_ptr_iter<int const>,
178 std::bidirectional_iterator_tag,
179 std::bidirectional_iterator_tag,
180 int,
181 int const &,
182 int const *,
183 std::ptrdiff_t)
184
185 template<typename ValueType>
186 struct bidirectional_iter : boost::stl_interfaces::iterator_interface<
187 bidirectional_iter<ValueType>,
188 std::bidirectional_iterator_tag,
189 ValueType>
190 {
bidirectional_iterbidirectional_iter191 bidirectional_iter() : it_(nullptr) {}
bidirectional_iterbidirectional_iter192 bidirectional_iter(ValueType * it) : it_(it) {}
193 template<
194 typename ValueType2,
195 typename E = std::enable_if_t<
196 std::is_convertible<ValueType2 *, ValueType *>::value>>
bidirectional_iterbidirectional_iter197 bidirectional_iter(bidirectional_iter<ValueType2> it) : it_(it.it_)
198 {}
199
operator *bidirectional_iter200 ValueType & operator*() const { return *it_; }
operator ++bidirectional_iter201 bidirectional_iter & operator++()
202 {
203 ++it_;
204 return *this;
205 }
operator --bidirectional_iter206 bidirectional_iter & operator--()
207 {
208 --it_;
209 return *this;
210 }
211 friend bool
operator ==(bidirectional_iter lhs,bidirectional_iter rhs)212 operator==(bidirectional_iter lhs, bidirectional_iter rhs) noexcept
213 {
214 return lhs.it_ == rhs.it_;
215 }
216
217 using base_type = boost::stl_interfaces::iterator_interface<
218 bidirectional_iter<ValueType>,
219 std::bidirectional_iterator_tag,
220 ValueType>;
221 using base_type::operator++;
222 using base_type::operator--;
223
224 private:
225 ValueType * it_;
226
227 template<typename ValueType2>
228 friend struct bidirectional_iter;
229 };
230
231 using bidirectional = bidirectional_iter<int>;
232 using const_bidirectional = bidirectional_iter<int const>;
233
234 BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(
235 bidirectional, std::bidirectional_iterator)
236 BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(
237 bidirectional,
238 std::bidirectional_iterator_tag,
239 std::bidirectional_iterator_tag,
240 int,
241 int &,
242 int *,
243 std::ptrdiff_t)
244
245 BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(
246 const_bidirectional, std::bidirectional_iterator)
247 BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(
248 const_bidirectional,
249 std::bidirectional_iterator_tag,
250 std::bidirectional_iterator_tag,
251 int,
252 int const &,
253 int const *,
254 std::ptrdiff_t)
255
256
257 std::array<int, 10> ints = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}};
258
259
260 ////////////////////
261 // view_interface //
262 ////////////////////
263 #include "view_tests.hpp"
264
265 template<typename T>
266 using data_t = decltype(std::declval<T>().data());
267
268 static_assert(
269 ill_formed<
270 data_t,
271 subrange<
272 basic_bidirectional_iter,
273 basic_bidirectional_iter,
274 boost::stl_interfaces::v1::element_layout::discontiguous>>::value,
275 "");
276 static_assert(
277 ill_formed<
278 data_t,
279 subrange<
280 basic_bidirectional_iter,
281 basic_bidirectional_iter,
282 boost::stl_interfaces::v1::element_layout::discontiguous> const>::
283 value,
284 "");
285
286 template<typename T>
287 using size_t_ = decltype(std::declval<T>().size());
288
289 static_assert(
290 ill_formed<
291 size_t_,
292 subrange<
293 basic_bidirectional_iter,
294 basic_bidirectional_iter,
295 boost::stl_interfaces::v1::element_layout::discontiguous>>::value,
296 "");
297 static_assert(
298 ill_formed<
299 size_t_,
300 subrange<
301 basic_bidirectional_iter,
302 basic_bidirectional_iter,
303 boost::stl_interfaces::v1::element_layout::discontiguous> const>::
304 value,
305 "");
306
307 template<typename T>
308 using index_operator_t = decltype(std::declval<T>()[0]);
309
310 static_assert(
311 ill_formed<
312 index_operator_t,
313 subrange<
314 basic_bidirectional_iter,
315 basic_bidirectional_iter,
316 boost::stl_interfaces::v1::element_layout::discontiguous>>::value,
317 "");
318 static_assert(
319 ill_formed<
320 index_operator_t,
321 subrange<
322 basic_bidirectional_iter,
323 basic_bidirectional_iter,
324 boost::stl_interfaces::v1::element_layout::discontiguous> const>::
325 value,
326 "");
327
328
main()329 int main()
330 {
331
332 {
333 basic_bidirectional_iter first(ints.data());
334 basic_bidirectional_iter last(ints.data() + ints.size());
335
336 {
337 std::array<int, 10> ints_copy;
338 std::copy(first, last, ints_copy.begin());
339 BOOST_TEST(ints_copy == ints);
340 }
341
342 {
343 std::array<int, 10> ints_copy;
344 std::copy(
345 std::make_reverse_iterator(last),
346 std::make_reverse_iterator(first),
347 ints_copy.begin());
348 std::reverse(ints_copy.begin(), ints_copy.end());
349 BOOST_TEST(ints_copy == ints);
350 }
351
352 {
353 std::array<int, 10> iota_ints;
354 basic_bidirectional_iter first(iota_ints.data());
355 basic_bidirectional_iter last(iota_ints.data() + iota_ints.size());
356 std::iota(first, last, 0);
357 BOOST_TEST(iota_ints == ints);
358 }
359
360 {
361 std::array<int, 10> iota_ints;
362 basic_bidirectional_iter first(iota_ints.data());
363 basic_bidirectional_iter last(iota_ints.data() + iota_ints.size());
364 std::iota(
365 std::make_reverse_iterator(last),
366 std::make_reverse_iterator(first),
367 0);
368 std::reverse(iota_ints.begin(), iota_ints.end());
369 BOOST_TEST(iota_ints == ints);
370 }
371 }
372
373
374 {
375 basic_adapted_bidirectional_ptr_iter first(ints.data());
376 basic_adapted_bidirectional_ptr_iter last(ints.data() + ints.size());
377
378 {
379 std::array<int, 10> ints_copy;
380 std::copy(first, last, ints_copy.begin());
381 BOOST_TEST(ints_copy == ints);
382 }
383
384 {
385 std::array<int, 10> ints_copy;
386 std::copy(
387 std::make_reverse_iterator(last),
388 std::make_reverse_iterator(first),
389 ints_copy.begin());
390 std::reverse(ints_copy.begin(), ints_copy.end());
391 BOOST_TEST(ints_copy == ints);
392 }
393
394 {
395 std::array<int, 10> iota_ints;
396 basic_adapted_bidirectional_ptr_iter first(iota_ints.data());
397 basic_adapted_bidirectional_ptr_iter last(
398 iota_ints.data() + iota_ints.size());
399 std::iota(first, last, 0);
400 BOOST_TEST(iota_ints == ints);
401 }
402
403 {
404 std::array<int, 10> iota_ints;
405 basic_adapted_bidirectional_ptr_iter first(iota_ints.data());
406 basic_adapted_bidirectional_ptr_iter last(
407 iota_ints.data() + iota_ints.size());
408 std::iota(
409 std::make_reverse_iterator(last),
410 std::make_reverse_iterator(first),
411 0);
412 std::reverse(iota_ints.begin(), iota_ints.end());
413 BOOST_TEST(iota_ints == ints);
414 }
415 }
416
417
418 {
419 std::list<int> ints = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
420
421 basic_adapted_bidirectional_list_iter first(ints.begin());
422 basic_adapted_bidirectional_list_iter last(ints.end());
423
424 {
425 std::list<int> ints_copy;
426 std::copy(first, last, std::back_inserter(ints_copy));
427 BOOST_TEST(ints_copy == ints);
428 }
429
430 {
431 std::list<int> ints_copy;
432 std::copy(
433 std::make_reverse_iterator(last),
434 std::make_reverse_iterator(first),
435 std::back_inserter(ints_copy));
436 std::reverse(ints_copy.begin(), ints_copy.end());
437 BOOST_TEST(ints_copy == ints);
438 }
439 }
440
441
442 {
443 {
444 bidirectional first(ints.data());
445 bidirectional last(ints.data() + ints.size());
446 const_bidirectional first_copy(first);
447 const_bidirectional last_copy(last);
448 std::equal(first, last, first_copy, last_copy);
449 }
450
451 {
452 adapted_bidirectional_ptr_iter<int> first(ints.data());
453 adapted_bidirectional_ptr_iter<int> last(ints.data() + ints.size());
454 adapted_bidirectional_ptr_iter<int const> first_copy(
455 (int const *)ints.data());
456 adapted_bidirectional_ptr_iter<int const> last_copy(
457 (int const *)ints.data() + ints.size());
458 std::equal(first, last, first_copy, last_copy);
459 }
460 }
461
462
463 {
464 {
465 bidirectional first(ints.data());
466 bidirectional last(ints.data() + ints.size());
467 const_bidirectional first_const(first);
468 const_bidirectional last_const(last);
469
470 BOOST_TEST(first == first_const);
471 BOOST_TEST(first_const == first);
472 BOOST_TEST(first != last_const);
473 BOOST_TEST(last_const != first);
474 }
475
476 {
477 adapted_bidirectional_ptr_iter<int> first(ints.data());
478 adapted_bidirectional_ptr_iter<int> last(ints.data() + ints.size());
479 adapted_bidirectional_ptr_iter<int const> first_const(
480 (int const *)ints.data());
481 adapted_bidirectional_ptr_iter<int const> last_const(
482 (int const *)ints.data() + ints.size());
483
484 static_assert(
485 !boost::stl_interfaces::v1_dtl::ra_iter<
486 adapted_bidirectional_ptr_iter<int>>::value,
487 "");
488
489 BOOST_TEST(first == first_const);
490 BOOST_TEST(first_const == first);
491 BOOST_TEST(first != last_const);
492 BOOST_TEST(last_const != first);
493 }
494 }
495
496
497 {
498 {
499 bidirectional first(ints.data());
500 bidirectional last(ints.data() + ints.size());
501 while (first != last && !(first == last))
502 first++;
503 }
504
505 {
506 bidirectional first(ints.data());
507 bidirectional last(ints.data() + ints.size());
508 while (first != last && !(first == last))
509 last--;
510 }
511
512 {
513 basic_bidirectional_iter first(ints.data());
514 basic_bidirectional_iter last(ints.data() + ints.size());
515 while (first != last && !(first == last))
516 first++;
517 }
518
519 {
520 basic_bidirectional_iter first(ints.data());
521 basic_bidirectional_iter last(ints.data() + ints.size());
522 while (first != last && !(first == last))
523 last--;
524 }
525
526 {
527 basic_adapted_bidirectional_ptr_iter first(ints.data());
528 basic_adapted_bidirectional_ptr_iter last(ints.data() + ints.size());
529 while (first != last && !(first == last))
530 first++;
531 }
532
533 {
534 basic_adapted_bidirectional_ptr_iter first(ints.data());
535 basic_adapted_bidirectional_ptr_iter last(ints.data() + ints.size());
536 while (first != last && !(first == last))
537 last--;
538 }
539
540 {
541 std::list<int> ints = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
542 basic_adapted_bidirectional_list_iter first(ints.begin());
543 basic_adapted_bidirectional_list_iter last(ints.end());
544 while (first != last && !(first == last))
545 first++;
546 }
547
548 {
549 std::list<int> ints = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
550 basic_adapted_bidirectional_list_iter first(ints.begin());
551 basic_adapted_bidirectional_list_iter last(ints.end());
552 while (first != last && !(first == last))
553 last--;
554 }
555 }
556
557
558 {
559 bidirectional first(ints.data());
560 bidirectional last(ints.data() + ints.size());
561
562 {
563 std::array<int, 10> ints_copy;
564 std::copy(first, last, ints_copy.begin());
565 BOOST_TEST(ints_copy == ints);
566 }
567
568 {
569 std::array<int, 10> ints_copy;
570 std::copy(
571 std::make_reverse_iterator(last),
572 std::make_reverse_iterator(first),
573 ints_copy.begin());
574 std::reverse(ints_copy.begin(), ints_copy.end());
575 BOOST_TEST(ints_copy == ints);
576 }
577
578 {
579 std::array<int, 10> iota_ints;
580 bidirectional first(iota_ints.data());
581 bidirectional last(iota_ints.data() + iota_ints.size());
582 std::iota(first, last, 0);
583 BOOST_TEST(iota_ints == ints);
584 }
585
586 {
587 std::array<int, 10> iota_ints;
588 bidirectional first(iota_ints.data());
589 bidirectional last(iota_ints.data() + iota_ints.size());
590 std::iota(
591 std::make_reverse_iterator(last),
592 std::make_reverse_iterator(first),
593 0);
594 std::reverse(iota_ints.begin(), iota_ints.end());
595 BOOST_TEST(iota_ints == ints);
596 }
597 }
598
599
600 {
601 const_bidirectional first(ints.data());
602 const_bidirectional last(ints.data() + ints.size());
603
604 {
605 std::array<int, 10> ints_copy;
606 std::copy(first, last, ints_copy.begin());
607 BOOST_TEST(ints_copy == ints);
608 }
609
610 {
611 BOOST_TEST(std::binary_search(first, last, 3));
612 BOOST_TEST(std::binary_search(
613 std::make_reverse_iterator(last),
614 std::make_reverse_iterator(first),
615 3,
616 std::greater<>{}));
617 }
618 }
619
620 {
621 basic_bidirectional_iter first(ints.data());
622 basic_bidirectional_iter last(ints.data() + ints.size());
623
624 auto r = range<boost::stl_interfaces::v1::element_layout::discontiguous>(
625 first, last);
626 auto empty =
627 range<boost::stl_interfaces::v1::element_layout::discontiguous>(
628 first, first);
629
630 // range begin/end
631 {
632 std::array<int, 10> ints_copy;
633 std::copy(r.begin(), r.end(), ints_copy.begin());
634 BOOST_TEST(ints_copy == ints);
635
636 BOOST_TEST(empty.begin() == empty.end());
637 }
638
639 // empty/op bool
640 {
641 BOOST_TEST(!r.empty());
642 BOOST_TEST(r);
643
644 BOOST_TEST(empty.empty());
645 BOOST_TEST(!empty);
646
647 auto const cr = r;
648 BOOST_TEST(!cr.empty());
649 BOOST_TEST(cr);
650
651 auto const cempty = empty;
652 BOOST_TEST(cempty.empty());
653 BOOST_TEST(!cempty);
654 }
655
656 // front/back
657 {
658 BOOST_TEST(r.front() == 0);
659 BOOST_TEST(r.back() == 9);
660
661 auto const cr = r;
662 BOOST_TEST(cr.front() == 0);
663 BOOST_TEST(cr.back() == 9);
664 }
665 }
666
667 return boost::report_errors();
668 }
669