diff --git a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.iterators/iterator_comparison.pass.cpp index 1975d0ed86cc8..d31daa84924fa 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.iterators/iterator_comparison.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.iterators/iterator_comparison.pass.cpp @@ -28,7 +28,6 @@ void test() { using Key = typename KeyContainer::value_type; using Value = typename ValueContainer::value_type; using M = std::flat_map, KeyContainer, ValueContainer>; - using KI = typename KeyContainer::iterator; using I = M::iterator; using CI = M::const_iterator; using RI = M::reverse_iterator; @@ -115,34 +114,32 @@ void test() { assert(cri2 >= cri2); assert(!(cri1 >= cri2)); - if constexpr (std::three_way_comparable) { - static_assert(std::three_way_comparable); // ...of course the wrapped iterators still support <=>. - static_assert(std::three_way_comparable); - static_assert(std::three_way_comparable); - static_assert(std::three_way_comparable); - static_assert(std::same_as I()), std::strong_ordering>); - static_assert(std::same_as CI()), std::strong_ordering>); - static_assert(std::same_as CI()), std::strong_ordering>); - static_assert(std::same_as RI()), std::strong_ordering>); - static_assert(std::same_as CRI()), std::strong_ordering>); - static_assert(std::same_as CRI()), std::strong_ordering>); - - assert(i1 <=> i1 == std::strong_ordering::equivalent); - assert(i1 <=> i2 == std::strong_ordering::less); - assert(i2 <=> i1 == std::strong_ordering::greater); - - assert(ci1 <=> ci1 == std::strong_ordering::equivalent); - assert(ci1 <=> ci2 == std::strong_ordering::less); - assert(ci2 <=> ci1 == std::strong_ordering::greater); - - assert(ri1 <=> ri1 == std::strong_ordering::equivalent); - assert(ri1 <=> ri2 == std::strong_ordering::less); - assert(ri2 <=> ri1 == std::strong_ordering::greater); - - assert(cri1 <=> cri1 == std::strong_ordering::equivalent); - assert(cri1 <=> cri2 == std::strong_ordering::less); - assert(cri2 <=> cri1 == std::strong_ordering::greater); - } + static_assert(std::three_way_comparable); // ...of course the wrapped iterators still support <=>. + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::same_as I()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as RI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + + assert(i1 <=> i1 == std::strong_ordering::equivalent); + assert(i1 <=> i2 == std::strong_ordering::less); + assert(i2 <=> i1 == std::strong_ordering::greater); + + assert(ci1 <=> ci1 == std::strong_ordering::equivalent); + assert(ci1 <=> ci2 == std::strong_ordering::less); + assert(ci2 <=> ci1 == std::strong_ordering::greater); + + assert(ri1 <=> ri1 == std::strong_ordering::equivalent); + assert(ri1 <=> ri2 == std::strong_ordering::less); + assert(ri2 <=> ri1 == std::strong_ordering::greater); + + assert(cri1 <=> cri1 == std::strong_ordering::equivalent); + assert(cri1 <=> cri2 == std::strong_ordering::less); + assert(cri2 <=> cri1 == std::strong_ordering::greater); } int main(int, char**) { diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator_comparison.pass.cpp index f1b2cad743e23..c2f4f608ba18a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator_comparison.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator_comparison.pass.cpp @@ -28,7 +28,6 @@ void test() { using Key = typename KeyContainer::value_type; using Value = typename ValueContainer::value_type; using M = std::flat_multimap, KeyContainer, ValueContainer>; - using KI = typename KeyContainer::iterator; using I = M::iterator; using CI = M::const_iterator; using RI = M::reverse_iterator; @@ -115,34 +114,32 @@ void test() { assert(cri2 >= cri2); assert(!(cri1 >= cri2)); - if constexpr (std::three_way_comparable) { - static_assert(std::three_way_comparable); // ...of course the wrapped iterators still support <=>. - static_assert(std::three_way_comparable); - static_assert(std::three_way_comparable); - static_assert(std::three_way_comparable); - static_assert(std::same_as I()), std::strong_ordering>); - static_assert(std::same_as CI()), std::strong_ordering>); - static_assert(std::same_as CI()), std::strong_ordering>); - static_assert(std::same_as RI()), std::strong_ordering>); - static_assert(std::same_as CRI()), std::strong_ordering>); - static_assert(std::same_as CRI()), std::strong_ordering>); - - assert(i1 <=> i1 == std::strong_ordering::equivalent); - assert(i1 <=> i2 == std::strong_ordering::less); - assert(i2 <=> i1 == std::strong_ordering::greater); - - assert(ci1 <=> ci1 == std::strong_ordering::equivalent); - assert(ci1 <=> ci2 == std::strong_ordering::less); - assert(ci2 <=> ci1 == std::strong_ordering::greater); - - assert(ri1 <=> ri1 == std::strong_ordering::equivalent); - assert(ri1 <=> ri2 == std::strong_ordering::less); - assert(ri2 <=> ri1 == std::strong_ordering::greater); - - assert(cri1 <=> cri1 == std::strong_ordering::equivalent); - assert(cri1 <=> cri2 == std::strong_ordering::less); - assert(cri2 <=> cri1 == std::strong_ordering::greater); - } + static_assert(std::three_way_comparable); // ...of course the wrapped iterators still support <=>. + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::same_as I()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as RI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + + assert(i1 <=> i1 == std::strong_ordering::equivalent); + assert(i1 <=> i2 == std::strong_ordering::less); + assert(i2 <=> i1 == std::strong_ordering::greater); + + assert(ci1 <=> ci1 == std::strong_ordering::equivalent); + assert(ci1 <=> ci2 == std::strong_ordering::less); + assert(ci2 <=> ci1 == std::strong_ordering::greater); + + assert(ri1 <=> ri1 == std::strong_ordering::equivalent); + assert(ri1 <=> ri2 == std::strong_ordering::less); + assert(ri2 <=> ri1 == std::strong_ordering::greater); + + assert(cri1 <=> cri1 == std::strong_ordering::equivalent); + assert(cri1 <=> cri2 == std::strong_ordering::less); + assert(cri2 <=> cri1 == std::strong_ordering::greater); } int main(int, char**) { diff --git a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.iterators/iterator_comparison.pass.cpp index d26e3446072ef..cbf69d6e04904 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.iterators/iterator_comparison.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.iterators/iterator_comparison.pass.cpp @@ -27,7 +27,6 @@ template void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_multiset, KeyContainer>; - using KI = typename KeyContainer::iterator; using I = M::iterator; using CI = M::const_iterator; using RI = M::reverse_iterator; @@ -114,34 +113,32 @@ void test_one() { assert(cri2 >= cri2); assert(!(cri1 >= cri2)); - if constexpr (std::three_way_comparable) { - static_assert(std::three_way_comparable); // ...of course the wrapped iterators still support <=>. - static_assert(std::three_way_comparable); - static_assert(std::three_way_comparable); - static_assert(std::three_way_comparable); - static_assert(std::same_as I()), std::strong_ordering>); - static_assert(std::same_as CI()), std::strong_ordering>); - static_assert(std::same_as CI()), std::strong_ordering>); - static_assert(std::same_as RI()), std::strong_ordering>); - static_assert(std::same_as CRI()), std::strong_ordering>); - static_assert(std::same_as CRI()), std::strong_ordering>); - - assert(i1 <=> i1 == std::strong_ordering::equivalent); - assert(i1 <=> i2 == std::strong_ordering::less); - assert(i2 <=> i1 == std::strong_ordering::greater); - - assert(ci1 <=> ci1 == std::strong_ordering::equivalent); - assert(ci1 <=> ci2 == std::strong_ordering::less); - assert(ci2 <=> ci1 == std::strong_ordering::greater); - - assert(ri1 <=> ri1 == std::strong_ordering::equivalent); - assert(ri1 <=> ri2 == std::strong_ordering::less); - assert(ri2 <=> ri1 == std::strong_ordering::greater); - - assert(cri1 <=> cri1 == std::strong_ordering::equivalent); - assert(cri1 <=> cri2 == std::strong_ordering::less); - assert(cri2 <=> cri1 == std::strong_ordering::greater); - } + static_assert(std::three_way_comparable); // ...of course the wrapped iterators still support <=>. + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::same_as I()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as RI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + + assert(i1 <=> i1 == std::strong_ordering::equivalent); + assert(i1 <=> i2 == std::strong_ordering::less); + assert(i2 <=> i1 == std::strong_ordering::greater); + + assert(ci1 <=> ci1 == std::strong_ordering::equivalent); + assert(ci1 <=> ci2 == std::strong_ordering::less); + assert(ci2 <=> ci1 == std::strong_ordering::greater); + + assert(ri1 <=> ri1 == std::strong_ordering::equivalent); + assert(ri1 <=> ri2 == std::strong_ordering::less); + assert(ri2 <=> ri1 == std::strong_ordering::greater); + + assert(cri1 <=> cri1 == std::strong_ordering::equivalent); + assert(cri1 <=> cri2 == std::strong_ordering::less); + assert(cri2 <=> cri1 == std::strong_ordering::greater); } void test() { diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp index 3027cdd4076ee..ad1bc8facc92e 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp @@ -27,7 +27,6 @@ template void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; - using KI = typename KeyContainer::iterator; using I = M::iterator; using CI = M::const_iterator; using RI = M::reverse_iterator; @@ -114,34 +113,32 @@ void test_one() { assert(cri2 >= cri2); assert(!(cri1 >= cri2)); - if constexpr (std::three_way_comparable) { - static_assert(std::three_way_comparable); // ...of course the wrapped iterators still support <=>. - static_assert(std::three_way_comparable); - static_assert(std::three_way_comparable); - static_assert(std::three_way_comparable); - static_assert(std::same_as I()), std::strong_ordering>); - static_assert(std::same_as CI()), std::strong_ordering>); - static_assert(std::same_as CI()), std::strong_ordering>); - static_assert(std::same_as RI()), std::strong_ordering>); - static_assert(std::same_as CRI()), std::strong_ordering>); - static_assert(std::same_as CRI()), std::strong_ordering>); - - assert(i1 <=> i1 == std::strong_ordering::equivalent); - assert(i1 <=> i2 == std::strong_ordering::less); - assert(i2 <=> i1 == std::strong_ordering::greater); - - assert(ci1 <=> ci1 == std::strong_ordering::equivalent); - assert(ci1 <=> ci2 == std::strong_ordering::less); - assert(ci2 <=> ci1 == std::strong_ordering::greater); - - assert(ri1 <=> ri1 == std::strong_ordering::equivalent); - assert(ri1 <=> ri2 == std::strong_ordering::less); - assert(ri2 <=> ri1 == std::strong_ordering::greater); - - assert(cri1 <=> cri1 == std::strong_ordering::equivalent); - assert(cri1 <=> cri2 == std::strong_ordering::less); - assert(cri2 <=> cri1 == std::strong_ordering::greater); - } + static_assert(std::three_way_comparable); // ...of course the wrapped iterators still support <=>. + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::same_as I()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as RI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + + assert(i1 <=> i1 == std::strong_ordering::equivalent); + assert(i1 <=> i2 == std::strong_ordering::less); + assert(i2 <=> i1 == std::strong_ordering::greater); + + assert(ci1 <=> ci1 == std::strong_ordering::equivalent); + assert(ci1 <=> ci2 == std::strong_ordering::less); + assert(ci2 <=> ci1 == std::strong_ordering::greater); + + assert(ri1 <=> ri1 == std::strong_ordering::equivalent); + assert(ri1 <=> ri2 == std::strong_ordering::less); + assert(ri2 <=> ri1 == std::strong_ordering::greater); + + assert(cri1 <=> cri1 == std::strong_ordering::equivalent); + assert(cri1 <=> cri2 == std::strong_ordering::less); + assert(cri2 <=> cri1 == std::strong_ordering::greater); } void test() { diff --git a/libcxx/test/support/MinSequenceContainer.h b/libcxx/test/support/MinSequenceContainer.h index 7fee4dd0fbdc1..6e61aff06344b 100644 --- a/libcxx/test/support/MinSequenceContainer.h +++ b/libcxx/test/support/MinSequenceContainer.h @@ -14,7 +14,9 @@ #include "test_iterators.h" -template , class ConstIterator = random_access_iterator> +template , + class ConstIterator = three_way_random_access_iterator> struct MinSequenceContainer { using value_type = T; using difference_type = int; diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h index 702b82b9e15a7..0335a4c561017 100644 --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -267,6 +267,135 @@ template random_access_iterator(It) -> random_access_iterator; #endif +// Since C++20, a container iterator type that is random access is also required to support three-way comparison. +// See C++20 [tab:container.req], C++23 [container.reqmts]/39 - /41. +template +class three_way_random_access_iterator { + It it_; + support::double_move_tracker tracker_; + + template + friend class three_way_random_access_iterator; + +public: + typedef std::random_access_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::reference reference; + + TEST_CONSTEXPR three_way_random_access_iterator() : it_() {} + TEST_CONSTEXPR explicit three_way_random_access_iterator(It it) : it_(it) {} + + template + TEST_CONSTEXPR three_way_random_access_iterator(const three_way_random_access_iterator& u) + : it_(u.it_), tracker_(u.tracker_) {} + + template ::value>::type> + TEST_CONSTEXPR_CXX14 three_way_random_access_iterator(three_way_random_access_iterator&& u) + : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) { + 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 three_way_random_access_iterator& operator++() { + ++it_; + return *this; + } + TEST_CONSTEXPR_CXX14 three_way_random_access_iterator& operator--() { + --it_; + return *this; + } + TEST_CONSTEXPR_CXX14 three_way_random_access_iterator operator++(int) { + return three_way_random_access_iterator(it_++); + } + TEST_CONSTEXPR_CXX14 three_way_random_access_iterator operator--(int) { + return three_way_random_access_iterator(it_--); + } + + TEST_CONSTEXPR_CXX14 three_way_random_access_iterator& operator+=(difference_type n) { + it_ += n; + return *this; + } + TEST_CONSTEXPR_CXX14 three_way_random_access_iterator& operator-=(difference_type n) { + it_ -= n; + return *this; + } + friend TEST_CONSTEXPR_CXX14 three_way_random_access_iterator + operator+(three_way_random_access_iterator x, difference_type n) { + x += n; + return x; + } + friend TEST_CONSTEXPR_CXX14 three_way_random_access_iterator + operator+(difference_type n, three_way_random_access_iterator x) { + x += n; + return x; + } + friend TEST_CONSTEXPR_CXX14 three_way_random_access_iterator + operator-(three_way_random_access_iterator x, difference_type n) { + x -= n; + return x; + } + friend TEST_CONSTEXPR difference_type + operator-(three_way_random_access_iterator x, three_way_random_access_iterator y) { + return x.it_ - y.it_; + } + + friend TEST_CONSTEXPR bool + operator==(const three_way_random_access_iterator& x, const three_way_random_access_iterator& y) { + return x.it_ == y.it_; + } +#if TEST_STD_VER < 20 + friend TEST_CONSTEXPR bool + operator!=(const three_way_random_access_iterator& x, const three_way_random_access_iterator& y) { + return x.it_ != y.it_; + } +#endif + friend TEST_CONSTEXPR bool + operator<(const three_way_random_access_iterator& x, const three_way_random_access_iterator& y) { + return x.it_ < y.it_; + } + friend TEST_CONSTEXPR bool + operator<=(const three_way_random_access_iterator& x, const three_way_random_access_iterator& y) { + return x.it_ <= y.it_; + } + friend TEST_CONSTEXPR bool + operator>(const three_way_random_access_iterator& x, const three_way_random_access_iterator& y) { + return x.it_ > y.it_; + } + friend TEST_CONSTEXPR bool + operator>=(const three_way_random_access_iterator& x, const three_way_random_access_iterator& y) { + return x.it_ >= y.it_; + } +#if TEST_STD_VER >= 20 + friend constexpr std::strong_ordering + operator<=>(const three_way_random_access_iterator& x, const three_way_random_access_iterator& y) { + if constexpr (std::three_way_comparable) { + return x.it_ <=> y.it_; + } else { + if (x.it_ < y.it_) { + return std::strong_ordering::less; + } else if (y.it_ < x.it_) { + return std::strong_ordering::greater; + } else { + return std::strong_ordering::equal; + } + } + } +#endif + + friend TEST_CONSTEXPR It base(const three_way_random_access_iterator& i) { return i.it_; } + + template + void operator,(T const&) = delete; +}; +#if TEST_STD_VER > 14 +template +three_way_random_access_iterator(It) -> three_way_random_access_iterator; +#endif + #if TEST_STD_VER > 17 template