1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440
|
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef SUPPORT_TEST_ITERATORS_H
#define SUPPORT_TEST_ITERATORS_H
#include <cassert>
#include <concepts>
#include <iterator>
#include <ranges>
#include <stdexcept>
#include <type_traits>
#include <utility>
#include "test_macros.h"
#include "type_algorithms.h"
// This iterator meets C++20's Cpp17OutputIterator requirements, as described
// in Table 90 ([output.iterators]).
template <class It>
class cpp17_output_iterator
{
It it_;
template <class U> friend class cpp17_output_iterator;
public:
typedef std::output_iterator_tag iterator_category;
typedef void value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
TEST_CONSTEXPR explicit cpp17_output_iterator(It it) : it_(std::move(it)) {}
template <class U>
TEST_CONSTEXPR cpp17_output_iterator(const cpp17_output_iterator<U>& u) : it_(u.it_) {}
template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
TEST_CONSTEXPR_CXX14 cpp17_output_iterator(cpp17_output_iterator<U>&& u) : it_(u.it_) { u.it_ = U(); }
TEST_CONSTEXPR reference operator*() const {return *it_;}
TEST_CONSTEXPR_CXX14 cpp17_output_iterator& operator++() {++it_; return *this;}
TEST_CONSTEXPR_CXX14 cpp17_output_iterator operator++(int) {return cpp17_output_iterator(it_++);}
friend TEST_CONSTEXPR It base(const cpp17_output_iterator& i) { return i.it_; }
template <class T>
void operator,(T const &) = delete;
};
#if TEST_STD_VER > 14
template <class It>
cpp17_output_iterator(It) -> cpp17_output_iterator<It>;
#endif
#if TEST_STD_VER > 17
static_assert(std::output_iterator<cpp17_output_iterator<int*>, int>);
#endif
// This iterator meets C++20's Cpp17InputIterator requirements, as described
// in Table 89 ([input.iterators]).
template <class It, class ItTraits = It>
class cpp17_input_iterator
{
typedef std::iterator_traits<ItTraits> Traits;
It it_;
template <class U, class T> friend class cpp17_input_iterator;
public:
typedef std::input_iterator_tag iterator_category;
typedef typename Traits::value_type value_type;
typedef typename Traits::difference_type difference_type;
typedef It pointer;
typedef typename Traits::reference reference;
TEST_CONSTEXPR explicit cpp17_input_iterator(It it) : it_(it) {}
template <class U, class T>
TEST_CONSTEXPR cpp17_input_iterator(const cpp17_input_iterator<U, T>& u) : it_(u.it_) {}
template <class U, class T, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
TEST_CONSTEXPR_CXX14 cpp17_input_iterator(cpp17_input_iterator<U, T>&& u) : it_(u.it_) { u.it_ = U(); }
TEST_CONSTEXPR reference operator*() const {return *it_;}
TEST_CONSTEXPR_CXX14 cpp17_input_iterator& operator++() {++it_; return *this;}
TEST_CONSTEXPR_CXX14 cpp17_input_iterator operator++(int) {return cpp17_input_iterator(it_++);}
friend TEST_CONSTEXPR bool operator==(const cpp17_input_iterator& x, const cpp17_input_iterator& y) {return x.it_ == y.it_;}
friend TEST_CONSTEXPR bool operator!=(const cpp17_input_iterator& x, const cpp17_input_iterator& y) {return x.it_ != y.it_;}
friend TEST_CONSTEXPR It base(const cpp17_input_iterator& i) { return i.it_; }
template <class T>
void operator,(T const &) = delete;
};
#if TEST_STD_VER > 14
template <class It>
cpp17_input_iterator(It) -> cpp17_input_iterator<It>;
#endif
#if TEST_STD_VER > 17
static_assert(std::input_iterator<cpp17_input_iterator<int*>>);
#endif
template <class It>
class forward_iterator
{
It it_;
template <class U> friend class forward_iterator;
public:
typedef std::forward_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
TEST_CONSTEXPR forward_iterator() : it_() {}
TEST_CONSTEXPR explicit forward_iterator(It it) : it_(it) {}
template <class U>
TEST_CONSTEXPR forward_iterator(const forward_iterator<U>& u) : it_(u.it_) {}
template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
TEST_CONSTEXPR_CXX14 forward_iterator(forward_iterator<U>&& other) : it_(other.it_) { other.it_ = U(); }
TEST_CONSTEXPR reference operator*() const {return *it_;}
TEST_CONSTEXPR_CXX14 forward_iterator& operator++() {++it_; return *this;}
TEST_CONSTEXPR_CXX14 forward_iterator operator++(int) {return forward_iterator(it_++);}
friend TEST_CONSTEXPR bool operator==(const forward_iterator& x, const forward_iterator& y) {return x.it_ == y.it_;}
friend TEST_CONSTEXPR bool operator!=(const forward_iterator& x, const forward_iterator& y) {return x.it_ != y.it_;}
friend TEST_CONSTEXPR It base(const forward_iterator& i) { return i.it_; }
template <class T>
void operator,(T const &) = delete;
};
#if TEST_STD_VER > 14
template <class It>
forward_iterator(It) -> forward_iterator<It>;
#endif
template <class It>
class bidirectional_iterator
{
It it_;
template <class U> friend class bidirectional_iterator;
public:
typedef std::bidirectional_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
TEST_CONSTEXPR bidirectional_iterator() : it_() {}
TEST_CONSTEXPR explicit bidirectional_iterator(It it) : it_(it) {}
template <class U>
TEST_CONSTEXPR bidirectional_iterator(const bidirectional_iterator<U>& u) : it_(u.it_) {}
template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
TEST_CONSTEXPR_CXX14 bidirectional_iterator(bidirectional_iterator<U>&& u) : it_(u.it_) { u.it_ = U(); }
TEST_CONSTEXPR reference operator*() const {return *it_;}
TEST_CONSTEXPR_CXX14 bidirectional_iterator& operator++() {++it_; return *this;}
TEST_CONSTEXPR_CXX14 bidirectional_iterator& operator--() {--it_; return *this;}
TEST_CONSTEXPR_CXX14 bidirectional_iterator operator++(int) {return bidirectional_iterator(it_++);}
TEST_CONSTEXPR_CXX14 bidirectional_iterator operator--(int) {return bidirectional_iterator(it_--);}
friend TEST_CONSTEXPR bool operator==(const bidirectional_iterator& x, const bidirectional_iterator& y) {return x.it_ == y.it_;}
friend TEST_CONSTEXPR bool operator!=(const bidirectional_iterator& x, const bidirectional_iterator& y) {return x.it_ != y.it_;}
friend TEST_CONSTEXPR It base(const bidirectional_iterator& i) { return i.it_; }
template <class T>
void operator,(T const &) = delete;
};
#if TEST_STD_VER > 14
template <class It>
bidirectional_iterator(It) -> bidirectional_iterator<It>;
#endif
template <class It>
class random_access_iterator
{
It it_;
template <class U> friend class random_access_iterator;
public:
typedef std::random_access_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
TEST_CONSTEXPR random_access_iterator() : it_() {}
TEST_CONSTEXPR explicit random_access_iterator(It it) : it_(it) {}
template <class U>
TEST_CONSTEXPR random_access_iterator(const random_access_iterator<U>& u) : it_(u.it_) {}
template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
TEST_CONSTEXPR_CXX14 random_access_iterator(random_access_iterator<U>&& u) : it_(u.it_) { u.it_ = U(); }
TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;}
TEST_CONSTEXPR_CXX14 reference operator[](difference_type n) const {return it_[n];}
TEST_CONSTEXPR_CXX14 random_access_iterator& operator++() {++it_; return *this;}
TEST_CONSTEXPR_CXX14 random_access_iterator& operator--() {--it_; return *this;}
TEST_CONSTEXPR_CXX14 random_access_iterator operator++(int) {return random_access_iterator(it_++);}
TEST_CONSTEXPR_CXX14 random_access_iterator operator--(int) {return random_access_iterator(it_--);}
TEST_CONSTEXPR_CXX14 random_access_iterator& operator+=(difference_type n) {it_ += n; return *this;}
TEST_CONSTEXPR_CXX14 random_access_iterator& operator-=(difference_type n) {it_ -= n; return *this;}
friend TEST_CONSTEXPR_CXX14 random_access_iterator operator+(random_access_iterator x, difference_type n) {x += n; return x;}
friend TEST_CONSTEXPR_CXX14 random_access_iterator operator+(difference_type n, random_access_iterator x) {x += n; return x;}
friend TEST_CONSTEXPR_CXX14 random_access_iterator operator-(random_access_iterator x, difference_type n) {x -= n; return x;}
friend TEST_CONSTEXPR difference_type operator-(random_access_iterator x, random_access_iterator y) {return x.it_ - y.it_;}
friend TEST_CONSTEXPR bool operator==(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ == y.it_;}
friend TEST_CONSTEXPR bool operator!=(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ != y.it_;}
friend TEST_CONSTEXPR bool operator< (const random_access_iterator& x, const random_access_iterator& y) {return x.it_ < y.it_;}
friend TEST_CONSTEXPR bool operator<=(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ <= y.it_;}
friend TEST_CONSTEXPR bool operator> (const random_access_iterator& x, const random_access_iterator& y) {return x.it_ > y.it_;}
friend TEST_CONSTEXPR bool operator>=(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ >= y.it_;}
friend TEST_CONSTEXPR It base(const random_access_iterator& i) { return i.it_; }
template <class T>
void operator,(T const &) = delete;
};
#if TEST_STD_VER > 14
template <class It>
random_access_iterator(It) -> random_access_iterator<It>;
#endif
#if TEST_STD_VER > 17
template <std::random_access_iterator It>
class cpp20_random_access_iterator {
It it_;
template <std::random_access_iterator>
friend class cpp20_random_access_iterator;
public:
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::random_access_iterator_tag;
using value_type = typename std::iterator_traits<It>::value_type;
using difference_type = typename std::iterator_traits<It>::difference_type;
constexpr cpp20_random_access_iterator() : it_() {}
constexpr explicit cpp20_random_access_iterator(It it) : it_(it) {}
template <class U>
constexpr cpp20_random_access_iterator(const cpp20_random_access_iterator<U>& u) : it_(u.it_) {}
template <class U>
constexpr cpp20_random_access_iterator(cpp20_random_access_iterator<U>&& u) : it_(u.it_) {
u.it_ = U();
}
constexpr decltype(auto) operator*() const { return *it_; }
constexpr decltype(auto) operator[](difference_type n) const { return it_[n]; }
constexpr cpp20_random_access_iterator& operator++() {
++it_;
return *this;
}
constexpr cpp20_random_access_iterator& operator--() {
--it_;
return *this;
}
constexpr cpp20_random_access_iterator operator++(int) { return cpp20_random_access_iterator(it_++); }
constexpr cpp20_random_access_iterator operator--(int) { return cpp20_random_access_iterator(it_--); }
constexpr cpp20_random_access_iterator& operator+=(difference_type n) {
it_ += n;
return *this;
}
constexpr cpp20_random_access_iterator& operator-=(difference_type n) {
it_ -= n;
return *this;
}
friend constexpr cpp20_random_access_iterator operator+(cpp20_random_access_iterator x, difference_type n) {
x += n;
return x;
}
friend constexpr cpp20_random_access_iterator operator+(difference_type n, cpp20_random_access_iterator x) {
x += n;
return x;
}
friend constexpr cpp20_random_access_iterator operator-(cpp20_random_access_iterator x, difference_type n) {
x -= n;
return x;
}
friend constexpr difference_type operator-(cpp20_random_access_iterator x, cpp20_random_access_iterator y) {
return x.it_ - y.it_;
}
friend constexpr bool operator==(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) {
return x.it_ == y.it_;
}
friend constexpr bool operator!=(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) {
return x.it_ != y.it_;
}
friend constexpr bool operator<(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) {
return x.it_ < y.it_;
}
friend constexpr bool operator<=(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) {
return x.it_ <= y.it_;
}
friend constexpr bool operator>(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) {
return x.it_ > y.it_;
}
friend constexpr bool operator>=(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) {
return x.it_ >= y.it_;
}
friend constexpr It base(const cpp20_random_access_iterator& i) { return i.it_; }
template <class T>
void operator,(T const&) = delete;
};
template <class It>
cpp20_random_access_iterator(It) -> cpp20_random_access_iterator<It>;
static_assert(std::random_access_iterator<cpp20_random_access_iterator<int*>>);
template <class It>
class contiguous_iterator
{
static_assert(std::is_pointer_v<It>, "Things probably break in this case");
It it_;
template <class U> friend class contiguous_iterator;
public:
typedef std::contiguous_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
typedef typename std::remove_pointer<It>::type element_type;
TEST_CONSTEXPR_CXX14 It base() const {return it_;}
TEST_CONSTEXPR_CXX14 contiguous_iterator() : it_() {}
TEST_CONSTEXPR_CXX14 explicit contiguous_iterator(It it) : it_(it) {}
template <class U>
TEST_CONSTEXPR_CXX14 contiguous_iterator(const contiguous_iterator<U>& u) : it_(u.it_) {}
template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
constexpr contiguous_iterator(contiguous_iterator<U>&& u) : it_(u.it_) { u.it_ = U(); }
TEST_CONSTEXPR reference operator*() const {return *it_;}
TEST_CONSTEXPR pointer operator->() const {return it_;}
TEST_CONSTEXPR reference operator[](difference_type n) const {return it_[n];}
TEST_CONSTEXPR_CXX14 contiguous_iterator& operator++() {++it_; return *this;}
TEST_CONSTEXPR_CXX14 contiguous_iterator& operator--() {--it_; return *this;}
TEST_CONSTEXPR_CXX14 contiguous_iterator operator++(int) {return contiguous_iterator(it_++);}
TEST_CONSTEXPR_CXX14 contiguous_iterator operator--(int) {return contiguous_iterator(it_--);}
TEST_CONSTEXPR_CXX14 contiguous_iterator& operator+=(difference_type n) {it_ += n; return *this;}
TEST_CONSTEXPR_CXX14 contiguous_iterator& operator-=(difference_type n) {it_ -= n; return *this;}
friend TEST_CONSTEXPR_CXX14 contiguous_iterator operator+(contiguous_iterator x, difference_type n) {x += n; return x;}
friend TEST_CONSTEXPR_CXX14 contiguous_iterator operator+(difference_type n, contiguous_iterator x) {x += n; return x;}
friend TEST_CONSTEXPR_CXX14 contiguous_iterator operator-(contiguous_iterator x, difference_type n) {x -= n; return x;}
friend TEST_CONSTEXPR difference_type operator-(contiguous_iterator x, contiguous_iterator y) {return x.it_ - y.it_;}
friend TEST_CONSTEXPR bool operator==(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ == y.it_;}
friend TEST_CONSTEXPR bool operator!=(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ != y.it_;}
friend TEST_CONSTEXPR bool operator< (const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ < y.it_;}
friend TEST_CONSTEXPR bool operator<=(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ <= y.it_;}
friend TEST_CONSTEXPR bool operator> (const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ > y.it_;}
friend TEST_CONSTEXPR bool operator>=(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ >= y.it_;}
friend TEST_CONSTEXPR It base(const contiguous_iterator& i) { return i.it_; }
template <class T>
void operator,(T const &) = delete;
};
template <class It>
contiguous_iterator(It) -> contiguous_iterator<It>;
template <class It>
class three_way_contiguous_iterator
{
static_assert(std::is_pointer_v<It>, "Things probably break in this case");
It it_;
template <class U> friend class three_way_contiguous_iterator;
public:
typedef std::contiguous_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
typedef typename std::remove_pointer<It>::type element_type;
constexpr It base() const {return it_;}
constexpr three_way_contiguous_iterator() : it_() {}
constexpr explicit three_way_contiguous_iterator(It it) : it_(it) {}
template <class U>
constexpr three_way_contiguous_iterator(const three_way_contiguous_iterator<U>& u) : it_(u.it_) {}
template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
constexpr three_way_contiguous_iterator(three_way_contiguous_iterator<U>&& u) : it_(u.it_) { u.it_ = U(); }
constexpr reference operator*() const {return *it_;}
constexpr pointer operator->() const {return it_;}
constexpr reference operator[](difference_type n) const {return it_[n];}
constexpr three_way_contiguous_iterator& operator++() {++it_; return *this;}
constexpr three_way_contiguous_iterator& operator--() {--it_; return *this;}
constexpr three_way_contiguous_iterator operator++(int) {return three_way_contiguous_iterator(it_++);}
constexpr three_way_contiguous_iterator operator--(int) {return three_way_contiguous_iterator(it_--);}
constexpr three_way_contiguous_iterator& operator+=(difference_type n) {it_ += n; return *this;}
constexpr three_way_contiguous_iterator& operator-=(difference_type n) {it_ -= n; return *this;}
friend constexpr three_way_contiguous_iterator operator+(three_way_contiguous_iterator x, difference_type n) {x += n; return x;}
friend constexpr three_way_contiguous_iterator operator+(difference_type n, three_way_contiguous_iterator x) {x += n; return x;}
friend constexpr three_way_contiguous_iterator operator-(three_way_contiguous_iterator x, difference_type n) {x -= n; return x;}
friend constexpr difference_type operator-(three_way_contiguous_iterator x, three_way_contiguous_iterator y) {return x.it_ - y.it_;}
friend constexpr auto operator<=>(const three_way_contiguous_iterator& x, const three_way_contiguous_iterator& y) {return x.it_ <=> y.it_;}
friend constexpr bool operator==(const three_way_contiguous_iterator& x, const three_way_contiguous_iterator& y) {return x.it_ == y.it_;}
template <class T>
void operator,(T const &) = delete;
};
template <class It>
three_way_contiguous_iterator(It) -> three_way_contiguous_iterator<It>;
#endif // TEST_STD_VER > 17
template <class Iter> // ADL base() for everything else (including pointers)
TEST_CONSTEXPR Iter base(Iter i) { return i; }
template <typename T>
struct ThrowingIterator {
typedef std::bidirectional_iterator_tag iterator_category;
typedef ptrdiff_t difference_type;
typedef const T value_type;
typedef const T * pointer;
typedef const T & reference;
enum ThrowingAction { TAIncrement, TADecrement, TADereference, TAAssignment, TAComparison };
TEST_CONSTEXPR ThrowingIterator()
: begin_(nullptr), end_(nullptr), current_(nullptr), action_(TADereference), index_(0) {}
TEST_CONSTEXPR explicit ThrowingIterator(const T* first, const T* last, int index = 0,
ThrowingAction action = TADereference)
: begin_(first), end_(last), current_(first), action_(action), index_(index) {}
TEST_CONSTEXPR ThrowingIterator(const ThrowingIterator &rhs)
: begin_(rhs.begin_), end_(rhs.end_), current_(rhs.current_), action_(rhs.action_), index_(rhs.index_) {}
TEST_CONSTEXPR_CXX14 ThrowingIterator& operator=(const ThrowingIterator& rhs) {
if (action_ == TAAssignment && --index_ < 0) {
#ifndef TEST_HAS_NO_EXCEPTIONS
throw std::runtime_error("throw from iterator assignment");
#else
assert(false);
#endif
}
begin_ = rhs.begin_;
end_ = rhs.end_;
current_ = rhs.current_;
action_ = rhs.action_;
index_ = rhs.index_;
return *this;
}
TEST_CONSTEXPR_CXX14 reference operator*() const {
if (action_ == TADereference && --index_ < 0) {
#ifndef TEST_HAS_NO_EXCEPTIONS
throw std::runtime_error("throw from iterator dereference");
#else
assert(false);
#endif
}
return *current_;
}
TEST_CONSTEXPR_CXX14 ThrowingIterator& operator++() {
if (action_ == TAIncrement && --index_ < 0) {
#ifndef TEST_HAS_NO_EXCEPTIONS
throw std::runtime_error("throw from iterator increment");
#else
assert(false);
#endif
}
++current_;
return *this;
}
TEST_CONSTEXPR_CXX14 ThrowingIterator operator++(int) {
ThrowingIterator temp = *this;
++(*this);
return temp;
}
TEST_CONSTEXPR_CXX14 ThrowingIterator& operator--() {
if (action_ == TADecrement && --index_ < 0) {
#ifndef TEST_HAS_NO_EXCEPTIONS
throw std::runtime_error("throw from iterator decrement");
#else
assert(false);
#endif
}
--current_;
return *this;
}
TEST_CONSTEXPR_CXX14 ThrowingIterator operator--(int) {
ThrowingIterator temp = *this;
--(*this);
return temp;
}
TEST_CONSTEXPR_CXX14 friend bool operator==(const ThrowingIterator& a, const ThrowingIterator& b) {
if (a.action_ == TAComparison && --a.index_ < 0) {
#ifndef TEST_HAS_NO_EXCEPTIONS
throw std::runtime_error("throw from iterator comparison");
#else
assert(false);
#endif
}
bool atEndL = a.current_ == a.end_;
bool atEndR = b.current_ == b.end_;
if (atEndL != atEndR) return false; // one is at the end (or empty), the other is not.
if (atEndL) return true; // both are at the end (or empty)
return a.current_ == b.current_;
}
TEST_CONSTEXPR friend bool operator!=(const ThrowingIterator& a, const ThrowingIterator& b) {
return !(a == b);
}
template <class T2>
void operator,(T2 const &) = delete;
private:
const T* begin_;
const T* end_;
const T* current_;
ThrowingAction action_;
mutable int index_;
};
template <typename T>
struct NonThrowingIterator {
typedef std::bidirectional_iterator_tag iterator_category;
typedef ptrdiff_t difference_type;
typedef const T value_type;
typedef const T * pointer;
typedef const T & reference;
NonThrowingIterator()
: begin_(nullptr), end_(nullptr), current_(nullptr) {}
explicit NonThrowingIterator(const T *first, const T *last)
: begin_(first), end_(last), current_(first) {}
NonThrowingIterator(const NonThrowingIterator& rhs)
: begin_(rhs.begin_), end_(rhs.end_), current_(rhs.current_) {}
NonThrowingIterator& operator=(const NonThrowingIterator& rhs) TEST_NOEXCEPT {
begin_ = rhs.begin_;
end_ = rhs.end_;
current_ = rhs.current_;
return *this;
}
reference operator*() const TEST_NOEXCEPT {
return *current_;
}
NonThrowingIterator& operator++() TEST_NOEXCEPT {
++current_;
return *this;
}
NonThrowingIterator operator++(int) TEST_NOEXCEPT {
NonThrowingIterator temp = *this;
++(*this);
return temp;
}
NonThrowingIterator & operator--() TEST_NOEXCEPT {
--current_;
return *this;
}
NonThrowingIterator operator--(int) TEST_NOEXCEPT {
NonThrowingIterator temp = *this;
--(*this);
return temp;
}
friend bool operator==(const NonThrowingIterator& a, const NonThrowingIterator& b) TEST_NOEXCEPT {
bool atEndL = a.current_ == a.end_;
bool atEndR = b.current_ == b.end_;
if (atEndL != atEndR) return false; // one is at the end (or empty), the other is not.
if (atEndL) return true; // both are at the end (or empty)
return a.current_ == b.current_;
}
friend bool operator!=(const NonThrowingIterator& a, const NonThrowingIterator& b) TEST_NOEXCEPT {
return !(a == b);
}
template <class T2>
void operator,(T2 const &) = delete;
private:
const T *begin_;
const T *end_;
const T *current_;
};
#if TEST_STD_VER > 17
template <class It>
class cpp20_input_iterator
{
It it_;
public:
using value_type = std::iter_value_t<It>;
using difference_type = std::iter_difference_t<It>;
using iterator_concept = std::input_iterator_tag;
constexpr explicit cpp20_input_iterator(It it) : it_(it) {}
cpp20_input_iterator(cpp20_input_iterator&&) = default;
cpp20_input_iterator& operator=(cpp20_input_iterator&&) = default;
constexpr decltype(auto) operator*() const { return *it_; }
constexpr cpp20_input_iterator& operator++() { ++it_; return *this; }
constexpr void operator++(int) { ++it_; }
friend constexpr It base(const cpp20_input_iterator& i) { return i.it_; }
template <class T>
void operator,(T const &) = delete;
};
template <class It>
cpp20_input_iterator(It) -> cpp20_input_iterator<It>;
static_assert(std::input_iterator<cpp20_input_iterator<int*>>);
template<std::input_or_output_iterator>
struct iter_value_or_void { using type = void; };
template<std::input_iterator I>
struct iter_value_or_void<I> {
using type = std::iter_value_t<I>;
};
template <class It>
class cpp20_output_iterator {
It it_;
public:
using difference_type = std::iter_difference_t<It>;
constexpr explicit cpp20_output_iterator(It it) : it_(it) {}
cpp20_output_iterator(cpp20_output_iterator&&) = default;
cpp20_output_iterator& operator=(cpp20_output_iterator&&) = default;
constexpr decltype(auto) operator*() const { return *it_; }
constexpr cpp20_output_iterator& operator++() {
++it_;
return *this;
}
constexpr cpp20_output_iterator operator++(int) { return cpp20_output_iterator(it_++); }
friend constexpr It base(const cpp20_output_iterator& i) { return i.it_; }
template <class T>
void operator,(T const&) = delete;
};
template <class It>
cpp20_output_iterator(It) -> cpp20_output_iterator<It>;
static_assert(std::output_iterator<cpp20_output_iterator<int*>, int>);
# if TEST_STD_VER >= 20
// An `input_iterator` that can be used in a `std::ranges::common_range`
template <class Base>
struct common_input_iterator {
Base it_;
using value_type = std::iter_value_t<Base>;
using difference_type = std::intptr_t;
using iterator_concept = std::input_iterator_tag;
constexpr common_input_iterator() = default;
constexpr explicit common_input_iterator(Base it) : it_(it) {}
constexpr common_input_iterator& operator++() {
++it_;
return *this;
}
constexpr void operator++(int) { ++it_; }
constexpr decltype(auto) operator*() const { return *it_; }
friend constexpr bool operator==(common_input_iterator const&, common_input_iterator const&) = default;
};
# endif // TEST_STD_VER >= 20
// Iterator adaptor that counts the number of times the iterator has had a successor/predecessor
// operation called. Has two recorders:
// * `stride_count`, which records the total number of calls to an op++, op--, op+=, or op-=.
// * `stride_displacement`, which records the displacement of the calls. This means that both
// op++/op+= will increase the displacement counter by 1, and op--/op-= will decrease the
// displacement counter by 1.
template <class It>
class stride_counting_iterator {
public:
using value_type = typename iter_value_or_void<It>::type;
using difference_type = std::iter_difference_t<It>;
using iterator_concept =
std::conditional_t<std::contiguous_iterator<It>, std::contiguous_iterator_tag,
std::conditional_t<std::random_access_iterator<It>, std::random_access_iterator_tag,
std::conditional_t<std::bidirectional_iterator<It>, std::bidirectional_iterator_tag,
std::conditional_t<std::forward_iterator<It>, std::forward_iterator_tag,
std::conditional_t<std::input_iterator<It>, std::input_iterator_tag,
/* else */ std::output_iterator_tag
>>>>>;
stride_counting_iterator() requires std::default_initializable<It> = default;
constexpr explicit stride_counting_iterator(It const& it) : base_(base(it)) { }
friend constexpr It base(stride_counting_iterator const& it) { return It(it.base_); }
constexpr difference_type stride_count() const { return stride_count_; }
constexpr difference_type stride_displacement() const { return stride_displacement_; }
constexpr decltype(auto) operator*() const { return *It(base_); }
constexpr decltype(auto) operator[](difference_type n) const { return It(base_)[n]; }
constexpr stride_counting_iterator& operator++() {
It tmp(base_);
base_ = base(++tmp);
++stride_count_;
++stride_displacement_;
return *this;
}
constexpr void operator++(int) { ++*this; }
constexpr stride_counting_iterator operator++(int)
requires std::forward_iterator<It>
{
auto temp = *this;
++*this;
return temp;
}
constexpr stride_counting_iterator& operator--()
requires std::bidirectional_iterator<It>
{
It tmp(base_);
base_ = base(--tmp);
++stride_count_;
--stride_displacement_;
return *this;
}
constexpr stride_counting_iterator operator--(int)
requires std::bidirectional_iterator<It>
{
auto temp = *this;
--*this;
return temp;
}
constexpr stride_counting_iterator& operator+=(difference_type const n)
requires std::random_access_iterator<It>
{
It tmp(base_);
base_ = base(tmp += n);
++stride_count_;
++stride_displacement_;
return *this;
}
constexpr stride_counting_iterator& operator-=(difference_type const n)
requires std::random_access_iterator<It>
{
It tmp(base_);
base_ = base(tmp -= n);
++stride_count_;
--stride_displacement_;
return *this;
}
friend constexpr stride_counting_iterator operator+(stride_counting_iterator it, difference_type n)
requires std::random_access_iterator<It>
{
return it += n;
}
friend constexpr stride_counting_iterator operator+(difference_type n, stride_counting_iterator it)
requires std::random_access_iterator<It>
{
return it += n;
}
friend constexpr stride_counting_iterator operator-(stride_counting_iterator it, difference_type n)
requires std::random_access_iterator<It>
{
return it -= n;
}
friend constexpr difference_type operator-(stride_counting_iterator const& x, stride_counting_iterator const& y)
requires std::sized_sentinel_for<It, It>
{
return base(x) - base(y);
}
constexpr bool operator==(stride_counting_iterator const& other) const
requires std::sentinel_for<It, It>
{
return It(base_) == It(other.base_);
}
friend constexpr bool operator<(stride_counting_iterator const& x, stride_counting_iterator const& y)
requires std::random_access_iterator<It>
{
return It(x.base_) < It(y.base_);
}
friend constexpr bool operator>(stride_counting_iterator const& x, stride_counting_iterator const& y)
requires std::random_access_iterator<It>
{
return It(x.base_) > It(y.base_);
}
friend constexpr bool operator<=(stride_counting_iterator const& x, stride_counting_iterator const& y)
requires std::random_access_iterator<It>
{
return It(x.base_) <= It(y.base_);
}
friend constexpr bool operator>=(stride_counting_iterator const& x, stride_counting_iterator const& y)
requires std::random_access_iterator<It>
{
return It(x.base_) >= It(y.base_);
}
template <class T>
void operator,(T const &) = delete;
private:
decltype(base(std::declval<It>())) base_;
difference_type stride_count_ = 0;
difference_type stride_displacement_ = 0;
};
template <class It>
stride_counting_iterator(It) -> stride_counting_iterator<It>;
#endif // TEST_STD_VER > 17
#if TEST_STD_VER > 17
template <class It>
class sentinel_wrapper {
public:
explicit sentinel_wrapper() = default;
constexpr explicit sentinel_wrapper(const It& it) : base_(base(it)) {}
constexpr bool operator==(const It& other) const { return base_ == base(other); }
friend constexpr It base(const sentinel_wrapper& s) { return It(s.base_); }
private:
decltype(base(std::declval<It>())) base_;
};
template <class It>
sentinel_wrapper(It) -> sentinel_wrapper<It>;
template <class It>
class sized_sentinel {
public:
explicit sized_sentinel() = default;
constexpr explicit sized_sentinel(const It& it) : base_(base(it)) {}
constexpr bool operator==(const It& other) const { return base_ == base(other); }
friend constexpr auto operator-(const sized_sentinel& s, const It& i) { return s.base_ - base(i); }
friend constexpr auto operator-(const It& i, const sized_sentinel& s) { return base(i) - s.base_; }
friend constexpr It base(const sized_sentinel& s) { return It(s.base_); }
private:
decltype(base(std::declval<It>())) base_;
};
template <class It>
sized_sentinel(It) -> sized_sentinel<It>;
namespace adl {
class Iterator {
public:
using value_type = int;
using reference = int&;
using difference_type = ptrdiff_t;
private:
value_type* ptr_ = nullptr;
int* iter_moves_ = nullptr;
int* iter_swaps_ = nullptr;
constexpr Iterator(int* p, int* iter_moves, int* iter_swaps)
: ptr_(p)
, iter_moves_(iter_moves)
, iter_swaps_(iter_swaps) {}
public:
constexpr Iterator() = default;
static constexpr Iterator TrackMoves(int* p, int& iter_moves) {
return Iterator(p, &iter_moves, /*iter_swaps=*/nullptr);
}
static constexpr Iterator TrackSwaps(int& iter_swaps) {
return Iterator(/*p=*/nullptr, /*iter_moves=*/nullptr, &iter_swaps);
}
static constexpr Iterator TrackSwaps(int* p, int& iter_swaps) {
return Iterator(p, /*iter_moves=*/nullptr, &iter_swaps);
}
constexpr int iter_moves() const { assert(iter_moves_); return *iter_moves_; }
constexpr int iter_swaps() const { assert(iter_swaps_); return *iter_swaps_; }
constexpr value_type& operator*() const { return *ptr_; }
constexpr reference operator[](difference_type n) const { return ptr_[n]; }
friend constexpr Iterator operator+(Iterator i, difference_type n) {
return Iterator(i.ptr_ + n, i.iter_moves_, i.iter_swaps_);
}
friend constexpr Iterator operator+(difference_type n, Iterator i) {
return i + n;
}
constexpr Iterator operator-(difference_type n) const {
return Iterator(ptr_ - n, iter_moves_, iter_swaps_);
}
constexpr difference_type operator-(Iterator rhs) const {
return ptr_ - rhs.ptr_;
}
constexpr Iterator& operator+=(difference_type n) {
ptr_ += n;
return *this;
}
constexpr Iterator& operator-=(difference_type n) {
ptr_ -= n;
return *this;
}
constexpr Iterator& operator++() { ++ptr_; return *this; }
constexpr Iterator operator++(int) {
Iterator prev = *this;
++ptr_;
return prev;
}
constexpr Iterator& operator--() { --ptr_; return *this; }
constexpr Iterator operator--(int) {
Iterator prev = *this;
--ptr_;
return prev;
}
constexpr friend void iter_swap(Iterator a, Iterator b) {
std::swap(a.ptr_, b.ptr_);
if (a.iter_swaps_) {
++(*a.iter_swaps_);
}
}
constexpr friend value_type&& iter_move(Iterator iter) {
if (iter.iter_moves_) {
++(*iter.iter_moves_);
}
return std::move(*iter);
}
constexpr friend bool operator==(const Iterator& lhs, const Iterator& rhs) {
return lhs.ptr_ == rhs.ptr_;
}
constexpr friend auto operator<=>(const Iterator& lhs, const Iterator& rhs) {
return lhs.ptr_ <=> rhs.ptr_;
}
};
} // namespace adl
template <class T>
class rvalue_iterator {
public:
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::random_access_iterator_tag;
using difference_type = std::ptrdiff_t;
using reference = T&&;
using value_type = T;
rvalue_iterator() = default;
constexpr rvalue_iterator(T* it) : it_(it) {}
constexpr reference operator*() const { return std::move(*it_); }
constexpr rvalue_iterator& operator++() {
++it_;
return *this;
}
constexpr rvalue_iterator operator++(int) {
auto tmp = *this;
++it_;
return tmp;
}
constexpr rvalue_iterator& operator--() {
--it_;
return *this;
}
constexpr rvalue_iterator operator--(int) {
auto tmp = *this;
--it_;
return tmp;
}
constexpr rvalue_iterator operator+(difference_type n) const {
auto tmp = *this;
tmp.it += n;
return tmp;
}
constexpr friend rvalue_iterator operator+(difference_type n, rvalue_iterator iter) {
iter += n;
return iter;
}
constexpr rvalue_iterator operator-(difference_type n) const {
auto tmp = *this;
tmp.it -= n;
return tmp;
}
constexpr difference_type operator-(const rvalue_iterator& other) const { return it_ - other.it_; }
constexpr rvalue_iterator& operator+=(difference_type n) {
it_ += n;
return *this;
}
constexpr rvalue_iterator& operator-=(difference_type n) {
it_ -= n;
return *this;
}
constexpr reference operator[](difference_type n) const { return std::move(it_[n]); }
auto operator<=>(const rvalue_iterator&) const noexcept = default;
private:
T* it_;
};
template <class T>
rvalue_iterator(T*) -> rvalue_iterator<T>;
static_assert(std::random_access_iterator<rvalue_iterator<int*>>);
// Proxy
// ======================================================================
// Proxy that can wrap a value or a reference. It simulates C++23's tuple
// but simplified to just hold one argument.
// Note that unlike tuple, this class deliberately doesn't have special handling
// of swap to cause a compilation error if it's used in an algorithm that relies
// on plain swap instead of ranges::iter_swap.
// This class is useful for testing that if algorithms support proxy iterator
// properly, i.e. calling ranges::iter_swap and ranges::iter_move instead of
// plain swap and std::move.
template <class T>
struct Proxy;
template <class T>
inline constexpr bool IsProxy = false;
template <class T>
inline constexpr bool IsProxy<Proxy<T>> = true;
template <class T>
struct Proxy {
T data;
constexpr T& getData() & { return data; }
constexpr const T& getData() const& { return data; }
constexpr T&& getData() && { return static_cast<T&&>(data); }
constexpr const T&& getData() const&& { return static_cast<const T&&>(data); }
template <class U>
requires std::constructible_from<T, U&&>
constexpr Proxy(U&& u) : data{std::forward<U>(u)} {}
// This constructor covers conversion from cvref of Proxy<U>, including non-const/const versions of copy/move constructor
template <class Other>
requires(IsProxy<std::decay_t<Other>> && std::constructible_from<T, decltype(std::declval<Other>().getData())>)
constexpr Proxy(Other&& other) : data{std::forward<Other>(other).getData()} {}
template <class Other>
requires(IsProxy<std::decay_t<Other>> && std::assignable_from<T&, decltype(std::declval<Other>().getData())>)
constexpr Proxy& operator=(Other&& other) {
data = std::forward<Other>(other).getData();
return *this;
}
// const assignment required to make ProxyIterator model std::indirectly_writable
template <class Other>
requires(IsProxy<std::decay_t<Other>> && std::assignable_from<const T&, decltype(std::declval<Other>().getData())>)
constexpr const Proxy& operator=(Other&& other) const {
data = std::forward<Other>(other).getData();
return *this;
}
// If `T` is a reference type, the implicitly-generated assignment operator will be deleted (and would take precedence
// over the templated `operator=` above because it's a better match).
constexpr Proxy& operator=(const Proxy& rhs) {
data = rhs.data;
return *this;
}
// no specialised swap function that takes const Proxy& and no specialised const member swap
// Calling swap(Proxy<T>{}, Proxy<T>{}) would fail (pass prvalues)
// Compare operators are defined for the convenience of the tests
friend constexpr bool operator==(const Proxy&, const Proxy&)
requires (std::equality_comparable<T> && !std::is_reference_v<T>)
= default;
// Helps compare e.g. `Proxy<int>` and `Proxy<int&>`. Note that the default equality comparison operator is deleted
// when `T` is a reference type.
template <class U>
friend constexpr bool operator==(const Proxy& lhs, const Proxy<U>& rhs)
requires std::equality_comparable_with<std::decay_t<T>, std::decay_t<U>> {
return lhs.data == rhs.data;
}
friend constexpr auto operator<=>(const Proxy&, const Proxy&)
requires (std::three_way_comparable<T> && !std::is_reference_v<T>)
= default;
// Helps compare e.g. `Proxy<int>` and `Proxy<int&>`. Note that the default 3-way comparison operator is deleted when
// `T` is a reference type.
template <class U>
friend constexpr auto operator<=>(const Proxy& lhs, const Proxy<U>& rhs)
requires std::three_way_comparable_with<std::decay_t<T>, std::decay_t<U>> {
return lhs.data <=> rhs.data;
}
};
// This is to make ProxyIterator model `std::indirectly_readable`
template <class T, class U, template <class> class TQual, template <class> class UQual>
requires requires { typename std::common_reference_t<TQual<T>, UQual<U>>; }
struct std::basic_common_reference<Proxy<T>, Proxy<U>, TQual, UQual> {
using type = Proxy<std::common_reference_t<TQual<T>, UQual<U>>>;
};
template <class T, class U>
requires requires { typename std::common_type_t<T, U>; }
struct std::common_type<Proxy<T>, Proxy<U>> {
using type = Proxy<std::common_type_t<T, U>>;
};
// ProxyIterator
// ======================================================================
// It wraps `Base` iterator and when dereferenced it returns a Proxy<ref>
// It simulates C++23's zip_view::iterator but simplified to just wrap
// one base iterator.
// Note it forwards value_type, iter_move, iter_swap. e.g if the base
// iterator is int*,
// operator* -> Proxy<int&>
// iter_value_t -> Proxy<int>
// iter_move -> Proxy<int&&>
template <class Base>
struct ProxyIteratorBase {};
template <class Base>
requires std::derived_from<
typename std::iterator_traits<Base>::iterator_category,
std::input_iterator_tag>
struct ProxyIteratorBase<Base> {
using iterator_category = std::input_iterator_tag;
};
template <std::input_iterator Base>
consteval auto get_iterator_concept() {
if constexpr (std::random_access_iterator<Base>) {
return std::random_access_iterator_tag{};
} else if constexpr (std::bidirectional_iterator<Base>) {
return std::bidirectional_iterator_tag{};
} else if constexpr (std::forward_iterator<Base>) {
return std::forward_iterator_tag{};
} else {
return std::input_iterator_tag{};
}
}
template <std::input_iterator Base>
struct ProxyIterator : ProxyIteratorBase<Base> {
Base base_;
using iterator_concept = decltype(get_iterator_concept<Base>());
using value_type = Proxy<std::iter_value_t<Base>>;
using difference_type = std::iter_difference_t<Base>;
ProxyIterator()
requires std::default_initializable<Base>
= default;
constexpr ProxyIterator(Base base) : base_{std::move(base)} {}
template <class T>
requires std::constructible_from<Base, T&&>
constexpr ProxyIterator(T&& t) : base_{std::forward<T>(t)} {}
friend constexpr decltype(auto) base(const ProxyIterator& p) { return base(p.base_); }
// Specialization of iter_move
// If operator* returns Proxy<Foo&>, iter_move will return Proxy<Foo&&>
// Note std::move(*it) returns Proxy<Foo&>&&, which is not what we want as
// it will likely result in a copy rather than a move
friend constexpr Proxy<std::iter_rvalue_reference_t<Base>> iter_move(const ProxyIterator& p) noexcept {
return {std::ranges::iter_move(p.base_)};
}
// Specialization of iter_swap
// Note std::swap(*x, *y) would fail to compile as operator* returns prvalues
// and std::swap takes non-const lvalue references
friend constexpr void iter_swap(const ProxyIterator& x, const ProxyIterator& y) noexcept {
std::ranges::iter_swap(x.base_, y.base_);
}
// to satisfy input_iterator
constexpr Proxy<std::iter_reference_t<Base>> operator*() const { return {*base_}; }
constexpr ProxyIterator& operator++() {
++base_;
return *this;
}
constexpr void operator++(int) { ++*this; }
friend constexpr bool operator==(const ProxyIterator& x, const ProxyIterator& y)
requires std::equality_comparable<Base> {
return x.base_ == y.base_;
}
// to satisfy forward_iterator
constexpr ProxyIterator operator++(int)
requires std::forward_iterator<Base> {
auto tmp = *this;
++*this;
return tmp;
}
// to satisfy bidirectional_iterator
constexpr ProxyIterator& operator--()
requires std::bidirectional_iterator<Base> {
--base_;
return *this;
}
constexpr ProxyIterator operator--(int)
requires std::bidirectional_iterator<Base> {
auto tmp = *this;
--*this;
return tmp;
}
// to satisfy random_access_iterator
constexpr ProxyIterator& operator+=(difference_type n)
requires std::random_access_iterator<Base> {
base_ += n;
return *this;
}
constexpr ProxyIterator& operator-=(difference_type n)
requires std::random_access_iterator<Base> {
base_ -= n;
return *this;
}
constexpr Proxy<std::iter_reference_t<Base>> operator[](difference_type n) const
requires std::random_access_iterator<Base> {
return {base_[n]};
}
friend constexpr bool operator<(const ProxyIterator& x, const ProxyIterator& y)
requires std::random_access_iterator<Base> {
return x.base_ < y.base_;
}
friend constexpr bool operator>(const ProxyIterator& x, const ProxyIterator& y)
requires std::random_access_iterator<Base> {
return x.base_ > y.base_;
}
friend constexpr bool operator<=(const ProxyIterator& x, const ProxyIterator& y)
requires std::random_access_iterator<Base> {
return x.base_ <= y.base_;
}
friend constexpr bool operator>=(const ProxyIterator& x, const ProxyIterator& y)
requires std::random_access_iterator<Base> {
return x.base_ >= y.base_;
}
friend constexpr auto operator<=>(const ProxyIterator& x, const ProxyIterator& y)
requires(std::random_access_iterator<Base> && std::three_way_comparable<Base>) {
return x.base_ <=> y.base_;
}
friend constexpr ProxyIterator operator+(const ProxyIterator& x, difference_type n)
requires std::random_access_iterator<Base> {
return ProxyIterator{x.base_ + n};
}
friend constexpr ProxyIterator operator+(difference_type n, const ProxyIterator& x)
requires std::random_access_iterator<Base> {
return ProxyIterator{n + x.base_};
}
friend constexpr ProxyIterator operator-(const ProxyIterator& x, difference_type n)
requires std::random_access_iterator<Base> {
return ProxyIterator{x.base_ - n};
}
friend constexpr difference_type operator-(const ProxyIterator& x, const ProxyIterator& y)
requires std::random_access_iterator<Base> {
return x.base_ - y.base_;
}
};
template <class Base>
ProxyIterator(Base) -> ProxyIterator<Base>;
static_assert(std::indirectly_readable<ProxyIterator<int*>>);
static_assert(std::indirectly_writable<ProxyIterator<int*>, Proxy<int>>);
static_assert(std::indirectly_writable<ProxyIterator<int*>, Proxy<int&>>);
template <class Iter>
using Cpp20InputProxyIterator = ProxyIterator<cpp20_input_iterator<Iter>>;
template <class Iter>
using ForwardProxyIterator = ProxyIterator<forward_iterator<Iter>>;
template <class Iter>
using BidirectionalProxyIterator = ProxyIterator<bidirectional_iterator<Iter>>;
template <class Iter>
using RandomAccessProxyIterator = ProxyIterator<random_access_iterator<Iter>>;
template <class Iter>
using ContiguousProxyIterator = ProxyIterator<contiguous_iterator<Iter>>;
template <class BaseSent>
struct ProxySentinel {
BaseSent base_;
ProxySentinel() = default;
constexpr ProxySentinel(BaseSent base) : base_{std::move(base)} {}
template <class Base>
requires std::equality_comparable_with<Base, BaseSent>
friend constexpr bool operator==(const ProxyIterator<Base>& p, const ProxySentinel& sent) {
return p.base_ == sent.base_;
}
};
template <class BaseSent>
ProxySentinel(BaseSent) -> ProxySentinel<BaseSent>;
template <std::ranges::input_range Base>
requires std::ranges::view<Base>
struct ProxyRange {
Base base_;
constexpr auto begin() { return ProxyIterator{std::ranges::begin(base_)}; }
constexpr auto end() { return ProxySentinel{std::ranges::end(base_)}; }
constexpr auto begin() const
requires std::ranges::input_range<const Base> {
return ProxyIterator{std::ranges::begin(base_)};
}
constexpr auto end() const
requires std::ranges::input_range<const Base> {
return ProxySentinel{std::ranges::end(base_)};
}
};
template <std::ranges::input_range R>
requires std::ranges::viewable_range<R&&>
ProxyRange(R&&) -> ProxyRange<std::views::all_t<R&&>>;
namespace meta {
template <class Ptr>
using random_access_iterator_list = type_list<Ptr, contiguous_iterator<Ptr>, random_access_iterator<Ptr>>;
template <class Ptr>
using bidirectional_iterator_list =
concatenate_t<random_access_iterator_list<Ptr>, type_list<bidirectional_iterator<Ptr>>>;
template <class Ptr>
using forward_iterator_list = concatenate_t<bidirectional_iterator_list<Ptr>, type_list<forward_iterator<Ptr>>>;
template <class Ptr>
using cpp20_input_iterator_list =
concatenate_t<forward_iterator_list<Ptr>, type_list<cpp20_input_iterator<Ptr>, cpp17_input_iterator<Ptr>>>;
} // namespace meta
#endif // TEST_STD_VER > 17
#endif // SUPPORT_TEST_ITERATORS_H
|