From 1cb1ddd9b9ff85a0f453326b0700ef52e7ac71af Mon Sep 17 00:00:00 2001 From: Curtis Bezault Date: Thu, 23 Jul 2020 10:56:32 -0700 Subject: [PATCH 01/64] Spaceship for regex --- stl/inc/regex | 39 +++++++++++++ tests/std/tests/regex_spaceship/test.cpp | 71 ++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 tests/std/tests/regex_spaceship/test.cpp diff --git a/stl/inc/regex b/stl/inc/regex index 2cfb6d8de33..d078dc4b727 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -708,6 +708,13 @@ _NODISCARD bool operator==(const sub_match<_BidIt>& _Left, const sub_match<_BidI return _Left._Match_equal(_Right); } +#if _HAS_CXX20 +template +_NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { + return static_cast>>>( + _Left.compare(_Right) <=> 0); +} +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template _NODISCARD bool operator!=(const sub_match<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { return !(_Left == _Right); @@ -732,6 +739,7 @@ template _NODISCARD bool operator>=(const sub_match<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { return !(_Left < _Right); } +#endif // !_HAS_CXX20 // COMPARE sub_match AND NTBS template @@ -739,6 +747,13 @@ _NODISCARD bool operator==(const _Iter_value_t<_BidIt>* _Left, const sub_match<_ return _Right._Match_equal(_Left); } +#if _HAS_CXX20 +template +_NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left ,const _Iter_value_t<_BidIt>* _Right) { + return static_cast>>>( + _Left.compare(_Right) <=> 0); +} +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template _NODISCARD bool operator!=(const _Iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { return !(_Left == _Right); @@ -793,6 +808,7 @@ template _NODISCARD bool operator>=(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>* _Right) { return !(_Left < _Right); } +#endif // !_HAS_CXX20 // COMPARE sub_match AND ELEMENT template @@ -800,6 +816,13 @@ _NODISCARD bool operator==(const _Iter_value_t<_BidIt>& _Left, const sub_match<_ return _Right._Match_equal(_STD addressof(_Left), 1); } +#if _HAS_CXX20 +template +_NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { + return static_cast>>>( + _Left._Compare(_STD addressof(_Right), 1) <=> 0); +} +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template _NODISCARD bool operator!=(const _Iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { return !(_Left == _Right); @@ -854,6 +877,7 @@ template _NODISCARD bool operator>=(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { return !(_Left < _Right); } +#endif // !_HAS_CXX20 // COMPARE sub_match AND string template @@ -862,6 +886,14 @@ _NODISCARD bool operator==( return _Left._Match_equal(_Right.data(), _Right.size()); } +#if _HAS_CXX20 +template +_NODISCARD bool operator<=>( + const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { + return static_cast>>>( + _Left.compare(_Right) <=> 0); +} +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template _NODISCARD bool operator!=( const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { @@ -927,6 +959,7 @@ _NODISCARD bool operator>=( const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { return !(_Left < _Right); } +#endif // !_HAS_CXX20 // INSERT sub_match IN STREAM template @@ -1134,10 +1167,12 @@ _NODISCARD bool operator==(const match_results<_BidIt, _Alloc>& _Left, const mat } } +#if !_HAS_CXX20 template _NODISCARD bool operator!=(const match_results<_BidIt, _Alloc>& _Left, const match_results<_BidIt, _Alloc>& _Right) { return !(_Left == _Right); } +#endif // !_HAS_CXX20 // NFA PROPERTIES const unsigned int _BRE_MAX_GRP = 9U; @@ -2428,9 +2463,11 @@ public: && _MyVal._At(0) == _Right._MyVal._At(0); } +#if !_HAS_CXX20 _NODISCARD bool operator!=(const regex_iterator& _Right) const { return !(*this == _Right); } +#endif // !_HAS_CXX20 _NODISCARD const value_type& operator*() const { #if _ITERATOR_DEBUG_LEVEL != 0 @@ -2611,9 +2648,11 @@ public: return *_Res == *_Right._Res && _Pos == _Right._Pos && _Subs == _Right._Subs; } +#if !_HAS_CXX20 _NODISCARD bool operator!=(const regex_token_iterator& _Right) const { return !(*this == _Right); } +#endif // !_HAS_CXX20 _NODISCARD const value_type& operator*() const { #if _ITERATOR_DEBUG_LEVEL != 0 diff --git a/tests/std/tests/regex_spaceship/test.cpp b/tests/std/tests/regex_spaceship/test.cpp new file mode 100644 index 00000000000..41fd8733a1f --- /dev/null +++ b/tests/std/tests/regex_spaceship/test.cpp @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +struct partial_order_traits : public std::char_traits { + static constexpr bool eq(char c1, char c2) { + return c1 % 0x2A == c2 % 0x2A; + } + + static constexpr bool lt(char c1, char c2) { + return c1 % 0x2A < c2 % 0x2A; + } + + static constexpr int compare(const char* s1, const char* s2, std::size_t n) { + for(; n > 0; --n, ++s1, ++s2) + { + if (lt(*s1, *s2)) { + return -1; + } + + if (lt(*s2, *s1)) { + return 1; + } + } + + return 0; + } +}; + +template +void regex_test(const String& s1, const String& s2) { + const std::regex all(".*"); + std::match_results m1, m2; + + std::regex_match(s1, m1, all); + std::regex_match(s2, m2, all); + + std::sub_match sm1 = m1[0]; + std::sub_match sm2 = m2[0]; + + assert(sm1 > sm2); + assert(sm2 < sm1); + assert(sm1 >= sm2); + assert(sm2 <= sm1); + assert(sm1 == sm1); + assert(sm1 != sm2); + assert((sm1 <=> sm2) > 0); + assert((sm2 <=> sm1) < 0); + assert((sm1 <=> sm1) == 0); + static_assert(std::is_same_v sm1), std::compare_three_way_t); +} + +int main() { + { + const std::string s1 = "Meow"; + const std::string s2 = "meow"; + + regex_test(s1, s2); + } + + { + const std::basic_string s1 = "\x2A"; + const std::basic_string s2 = "\x2B"; + + regex_test(s1, s2); + } +} From fcb7824877b3a41cb45efb7293a0350fa607175f Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Fri, 31 Jul 2020 10:25:18 -0700 Subject: [PATCH 02/64] Merge into test from feature/spaceship --- stl/inc/regex | 29 ++-- tests/std/tests/P1614R2_spaceship/test.cpp | 153 +++++++++++++++++++-- tests/std/tests/regex_spaceship/test.cpp | 71 ---------- 3 files changed, 160 insertions(+), 93 deletions(-) delete mode 100644 tests/std/tests/regex_spaceship/test.cpp diff --git a/stl/inc/regex b/stl/inc/regex index d078dc4b727..b9d48011f5a 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -592,6 +593,18 @@ bool _Is_word(_Elem _Ch) { return _UCh <= static_cast<_UElem>('z') && _Is_word(static_cast(_UCh)); } +#if _HAS_CXX20 + template + struct _Get_comparison_category { + using type = weak_ordering; + }; + + template + struct _Get_comparison_category<_Ty, void_t> { + using type = typename _Ty::comparison_category; + }; +#endif // _HAS_CXX20 + // CLASS TEMPLATE sub_match template class sub_match : public pair<_BidIt, _BidIt> { // class to hold contents of a capture group @@ -606,6 +619,10 @@ public: // Note that _Size_type should always be std::size_t using _Size_type = typename string_type::size_type; +#if _HAS_CXX20 + using _Comparison_category = typename _Get_comparison_category<_Traits>::type; +#endif // _HAS_CXX20 + constexpr sub_match() : _Mybase(), matched(false) {} bool matched; @@ -711,8 +728,7 @@ _NODISCARD bool operator==(const sub_match<_BidIt>& _Left, const sub_match<_BidI #if _HAS_CXX20 template _NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { - return static_cast>>>( - _Left.compare(_Right) <=> 0); + return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template @@ -750,8 +766,7 @@ _NODISCARD bool operator==(const _Iter_value_t<_BidIt>* _Left, const sub_match<_ #if _HAS_CXX20 template _NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left ,const _Iter_value_t<_BidIt>* _Right) { - return static_cast>>>( - _Left.compare(_Right) <=> 0); + return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template @@ -819,8 +834,7 @@ _NODISCARD bool operator==(const _Iter_value_t<_BidIt>& _Left, const sub_match<_ #if _HAS_CXX20 template _NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { - return static_cast>>>( - _Left._Compare(_STD addressof(_Right), 1) <=> 0); + return static_cast::_Comparison_category>(_Left._Compare(_STD addressof(_Right), 1) <=> 0); } #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template @@ -890,8 +904,7 @@ _NODISCARD bool operator==( template _NODISCARD bool operator<=>( const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { - return static_cast>>>( - _Left.compare(_Right) <=> 0); + return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template diff --git a/tests/std/tests/P1614R2_spaceship/test.cpp b/tests/std/tests/P1614R2_spaceship/test.cpp index 5a215eac23b..bafca9d5eae 100644 --- a/tests/std/tests/P1614R2_spaceship/test.cpp +++ b/tests/std/tests/P1614R2_spaceship/test.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,9 @@ #include #include +template +using SpaceshipType = decltype(std::declval() <=> std::declval()); + using PartiallyOrdered = double; struct WeaklyOrdered { @@ -54,29 +58,126 @@ struct SynthOrdered { } }; -template -inline constexpr bool is_pair = false; -template -inline constexpr bool is_pair> = true; // TRANSITION, std::pair spaceship not yet implemented +struct OrderedChar { + OrderedChar() = default; + OrderedChar(const char c) : c(c) {}; -template -void ordered_containers_test(const Container& smaller, const Container& smaller_equal, const Container& larger) { + OrderedChar& operator=(const char& other) + { + this->c = other; + return *this; + } + + operator char() { return c; } + + char c; +}; + +auto operator<=>(const OrderedChar& left, const OrderedChar& right) +{ + return left.c <=> right.c; +} + +auto operator==(const OrderedChar& left, const OrderedChar& right) +{ + return left.c == right.c; +} + +struct WeaklyOrderedChar : public OrderedChar {}; +struct WeaklyOrderdByOmissionChar : public OrderedChar {}; +struct PartiallyOrderedChar : public OrderedChar {}; + +namespace std +{ + template <> + struct char_traits : public std::char_traits { + using char_type = WeaklyOrderedChar; + using comparison_category = std::weak_ordering; + + static int compare(const char_type* first1, const char_type* first2, size_t count) { + for (; 0 < count; --count, ++first1, ++first2) { + if (*first1 != *first2) { + return *first1 < *first2 ? -1 : +1; + } + } + + return 0; + } + + static bool eq(const char_type l, const char_type r) { return l.c == r.c; } + }; + + template <> + struct char_traits : public std::char_traits { + using char_type = WeaklyOrderdByOmissionChar; + + static int compare(const char_type* first1, const char_type* first2, size_t count) { + for (; 0 < count; --count, ++first1, ++first2) { + if (*first1 != *first2) { + return *first1 < *first2 ? -1 : +1; + } + } + + return 0; + } + + static bool eq(const char_type l, const char_type r) { return l.c == r.c; } + }; + + template <> + struct char_traits : public std::char_traits { + using char_type = PartiallyOrderedChar; + using comparison_category = std::partial_ordering; + + static int compare(const char_type* first1, const char_type* first2, size_t count) { + for (; 0 < count; --count, ++first1, ++first2) { + if (*first1 != *first2) { + return *first1 < *first2 ? -1 : +1; + } + } + + return 0; + } + + static bool eq(const char_type l, const char_type r) { return l.c == r.c; } + }; +} + +template +void spaceship_test(const SmallType& smaller, const EqualType& smaller_equal, const LargeType& larger) +{ + assert(smaller == smaller_equal); + assert(smaller != larger); assert(smaller < larger); - assert(smaller <= larger); assert(larger > smaller); + assert(smaller <= larger); assert(larger >= smaller); - assert(smaller == smaller_equal); - assert(smaller != larger); assert((smaller <=> larger) < 0); assert((larger <=> smaller) > 0); assert((smaller <=> smaller_equal) == 0); + static_assert(std::is_same_v larger), ReturnType>); +} + +template +void spaceship_test(const TestType& smaller, const TestType& smaller_equal, const TestType& larger) +{ + return spaceship_test(smaller, smaller_equal, larger); +} + +template +inline constexpr bool is_pair = false; +template +inline constexpr bool is_pair> = true; // TRANSITION, std::pair spaceship not yet implemented + +template +void ordered_containers_test(const Container& smaller, const Container& smaller_equal, const Container& larger) { using Elem = typename Container::value_type; if constexpr (is_pair // TRANSITION, std::pair spaceship not yet implemented || std::is_same_v) { - static_assert(std::is_same_v larger), std::weak_ordering>); + spaceship_test(smaller, smaller_equal, larger); } else { - static_assert(std::is_same_v larger), std::strong_ordering>); + spaceship_test(smaller, smaller_equal, larger); } } @@ -292,10 +393,34 @@ void ordering_test_cases() { std::stack b{std::deque{10, 20, 40}}; ordered_containers_test(a, a, b); } -} + { // sub_match + const std::string s1{"cats"}; + const std::string s2{"meow"}; + const std::regex all(".*"); + std::smatch m1, m2; -template -using SpaceshipType = decltype(std::declval() <=> std::declval()); + std::regex_match(s1, m1, all); + std::regex_match(s2, m2, all); + + std::ssub_match sm1 = m1[0]; + std::ssub_match sm1_equal = m1[0]; + std::ssub_match sm2 = m2[0]; + + // TRANSITION: std::char_traits doesn't define comparison_type + spaceship_test(sm1, sm1_equal, sm2); + + using StronglyOrderedMatch = std::ssub_match; + using WeaklyOrderedMatch = std::sub_match::const_iterator>; + using WeaklyOrderdByOmissionMatch = std::sub_match::const_iterator>; + using PartiallyOrderedMatch = std::sub_match::const_iterator>; + + // TRANSITION: std::char_traits doesn't define comparison_type + static_assert(std::is_same_v, std::weak_ordering>); + static_assert(std::is_same_v, std::weak_ordering>); + static_assert(std::is_same_v, std::weak_ordering>); + static_assert(std::is_same_v, std::partial_ordering>); + } +} template void test_element_ordering() { diff --git a/tests/std/tests/regex_spaceship/test.cpp b/tests/std/tests/regex_spaceship/test.cpp deleted file mode 100644 index 41fd8733a1f..00000000000 --- a/tests/std/tests/regex_spaceship/test.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include -#include -#include -#include - -struct partial_order_traits : public std::char_traits { - static constexpr bool eq(char c1, char c2) { - return c1 % 0x2A == c2 % 0x2A; - } - - static constexpr bool lt(char c1, char c2) { - return c1 % 0x2A < c2 % 0x2A; - } - - static constexpr int compare(const char* s1, const char* s2, std::size_t n) { - for(; n > 0; --n, ++s1, ++s2) - { - if (lt(*s1, *s2)) { - return -1; - } - - if (lt(*s2, *s1)) { - return 1; - } - } - - return 0; - } -}; - -template -void regex_test(const String& s1, const String& s2) { - const std::regex all(".*"); - std::match_results m1, m2; - - std::regex_match(s1, m1, all); - std::regex_match(s2, m2, all); - - std::sub_match sm1 = m1[0]; - std::sub_match sm2 = m2[0]; - - assert(sm1 > sm2); - assert(sm2 < sm1); - assert(sm1 >= sm2); - assert(sm2 <= sm1); - assert(sm1 == sm1); - assert(sm1 != sm2); - assert((sm1 <=> sm2) > 0); - assert((sm2 <=> sm1) < 0); - assert((sm1 <=> sm1) == 0); - static_assert(std::is_same_v sm1), std::compare_three_way_t); -} - -int main() { - { - const std::string s1 = "Meow"; - const std::string s2 = "meow"; - - regex_test(s1, s2); - } - - { - const std::basic_string s1 = "\x2A"; - const std::basic_string s2 = "\x2B"; - - regex_test(s1, s2); - } -} From 949fc53b65f96e6a9944599056449bc425d2a42d Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Fri, 31 Jul 2020 11:58:25 -0700 Subject: [PATCH 03/64] Remove old test files for merge --- .../tests/P0896R4_P1614R2_comparisons/env.lst | 4 - .../P0896R4_P1614R2_comparisons/test.cpp | 604 ------------------ 2 files changed, 608 deletions(-) delete mode 100644 tests/std/tests/P0896R4_P1614R2_comparisons/env.lst delete mode 100644 tests/std/tests/P0896R4_P1614R2_comparisons/test.cpp diff --git a/tests/std/tests/P0896R4_P1614R2_comparisons/env.lst b/tests/std/tests/P0896R4_P1614R2_comparisons/env.lst deleted file mode 100644 index f3ccc8613c6..00000000000 --- a/tests/std/tests/P0896R4_P1614R2_comparisons/env.lst +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_P1614R2_comparisons/test.cpp b/tests/std/tests/P0896R4_P1614R2_comparisons/test.cpp deleted file mode 100644 index ebf0022a565..00000000000 --- a/tests/std/tests/P0896R4_P1614R2_comparisons/test.cpp +++ /dev/null @@ -1,604 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -// Covers: -// * three_way_comparable and three_way_comparable_with -// * compare_three_way, compare_three_way_result, and compare_three_way_result_t -// * ranges::equal_to, ranges::not_equal_to, ranges::less, ranges::less_equal, -// ranges::greater, and ranges::greater_equal - -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wsign-compare" -#endif // __clang__ - -#include -#include -#include -#include -#include -#include -#include - -#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) - -namespace ranges = std::ranges; - -using std::common_comparison_category_t; -using std::compare_three_way, std::compare_three_way_result, std::compare_three_way_result_t; -using std::partial_ordering, std::weak_ordering, std::strong_ordering; -using std::same_as, std::convertible_to; -using std::three_way_comparable, std::three_way_comparable_with; - -template -constexpr bool is_one_of = (same_as || ...); - -struct common_comparable { - template - common_comparable(T&&); - - bool operator==(common_comparable const&) const; - strong_ordering operator<=>(common_comparable const&) const; -}; - -struct common_incomparable { - template - common_incomparable(T&&); -}; - -// Validate properties common to the concept-constrained comparison object types -template -constexpr bool is_trivially_constexpr() { - STATIC_ASSERT(std::semiregular); - - // Not required, but likely portable nonetheless: - STATIC_ASSERT(std::is_empty_v); - STATIC_ASSERT(std::is_trivial_v); - STATIC_ASSERT(std::is_trivially_copy_constructible_v); - STATIC_ASSERT(std::is_trivially_move_constructible_v); - STATIC_ASSERT(std::is_trivially_copy_assignable_v); - STATIC_ASSERT(std::is_trivially_move_assignable_v); - - // Not required to be constant expressions, but likely portable nonetheless: - T value_initialized{}; - T copy_constructed = value_initialized; - T move_constructed = std::move(copy_constructed); - copy_constructed = std::move(move_constructed); - move_constructed = copy_constructed; - - return true; -} - -STATIC_ASSERT(is_trivially_constexpr()); -STATIC_ASSERT(is_trivially_constexpr()); -STATIC_ASSERT(is_trivially_constexpr()); -STATIC_ASSERT(is_trivially_constexpr()); -STATIC_ASSERT(is_trivially_constexpr()); -STATIC_ASSERT(is_trivially_constexpr()); -STATIC_ASSERT(is_trivially_constexpr()); - -// Validate three_way_comparable -template -struct three_way_archetype { - three_way_archetype() = delete; - three_way_archetype(three_way_archetype const&) = delete; - three_way_archetype& operator=(three_way_archetype const&) = delete; - ~three_way_archetype() = delete; - // clang-format off - // 0: not equality_comparable - bool operator==(three_way_archetype const&) const requires (I == 0) = delete; - bool operator==(three_way_archetype const&) const requires (I != 0); - // 1: not totally_ordered - bool operator<(three_way_archetype const&) const requires (I == 1) = delete; - bool operator<(three_way_archetype const&) const requires (I != 1); - bool operator>(three_way_archetype const&) const requires (I != 1); - bool operator<=(three_way_archetype const&) const requires (I != 1); - bool operator>=(three_way_archetype const&) const requires (I != 1); - // 2: <=> isn't defined - Category operator<=>(three_way_archetype const&) const requires (I != 2 && I != 3); - // 3: <=> doesn't return a comparison category type - int operator<=>(three_way_archetype const&) const requires (I == 3); - // clang-format on -}; -constexpr int three_way_archetype_max = 4; - -template -constexpr bool test_three_way_comparable1() { - STATIC_ASSERT(is_one_of); - - STATIC_ASSERT(three_way_comparable == convertible_to); - STATIC_ASSERT(three_way_comparable == convertible_to); - STATIC_ASSERT(three_way_comparable == same_as); - - STATIC_ASSERT(three_way_comparable_with == convertible_to); - STATIC_ASSERT(three_way_comparable_with == convertible_to); - STATIC_ASSERT(three_way_comparable_with == same_as); - - return true; -} - -template -constexpr bool test_three_way_comparable(std::integer_sequence) { - (test_three_way_comparable1, void>(), ...); - (test_three_way_comparable1, void>(), ...); - (test_three_way_comparable1, void>(), ...); - STATIC_ASSERT( - test_three_way_comparable1, partial_ordering>()); - STATIC_ASSERT( - test_three_way_comparable1, weak_ordering>()); - STATIC_ASSERT( - test_three_way_comparable1, strong_ordering>()); - - return true; -} -STATIC_ASSERT(test_three_way_comparable(std::make_integer_sequence{})); - -// Validate three_way_comparable_with -// clang-format off - -// 4: not common_reference_with -// 5: common_reference_t is not three_way_comparable -template - requires ((I1 != I2 || !same_as) && I1 != 4 && I2 != 4) -struct std::common_type, three_way_archetype> { - using type = conditional_t; -}; - -// 6: not _Weakly_equality_comparable_with -template - requires ((I1 != I2 || !same_as) && (I1 == 6 || I2 == 6)) -bool operator==(three_way_archetype const&, three_way_archetype const&) = delete; -template - requires ((I1 != I2 || !same_as) && I1 != 6 && I2 != 6) -bool operator==(three_way_archetype const&, three_way_archetype const&); - -// 7: not _Partially_ordered_with -template - requires ((I1 != I2 || !same_as) && (I1 == 7 || I2 == 7)) -bool operator<(three_way_archetype const&, three_way_archetype const&) = delete; -template - requires ((I1 != I2 || !same_as) && I1 != 7 && I2 != 7) -bool operator<(three_way_archetype const&, three_way_archetype const&); -template - requires (I1 != I2 || !same_as) -bool operator>(three_way_archetype const&, three_way_archetype const&); -template - requires (I1 != I2 || !same_as) -bool operator<=(three_way_archetype const&, three_way_archetype const&); -template - requires (I1 != I2 || !same_as) -bool operator>=(three_way_archetype const&, three_way_archetype const&); - -// 8: <=> isn't defined -template - requires ((I1 != I2 || !same_as) && I1 != 8 && I1 != 9 && I2 != 8 && I2 != 9) -common_comparison_category_t operator<=>( - three_way_archetype const&, three_way_archetype const&); - -// 9: <=> returns a non-comparison category type -template - requires ((I1 != I2 || !same_as) && I1 == 9 && I2 == 9) -int operator<=>(three_way_archetype const&, three_way_archetype const&); - -// clang-format on - -constexpr int three_way_with_max = 10; - -template -constexpr bool test_three_way_comparable_with1() { - STATIC_ASSERT(is_one_of); - - // All specializations of three_way_archetype for which I >= three_way_with_max are "good"; we need such a - // specialization that is different from three_way_archetype to ensure we're fully testing - // the cross-type three_way_comparable_with concept. Why not three_way_with_max + 1? - constexpr int three_way_known_good = three_way_with_max + 1; - - using P = three_way_archetype; - using W = three_way_archetype; - using S = three_way_archetype; - - STATIC_ASSERT(three_way_comparable_with == convertible_to); - STATIC_ASSERT(three_way_comparable_with == convertible_to); - STATIC_ASSERT(three_way_comparable_with == same_as); - - return true; -} - -template -constexpr bool test_three_way_comparable_with(std::integer_sequence) { - (test_three_way_comparable_with1, void>(), ...); - (test_three_way_comparable_with1, void>(), ...); - (test_three_way_comparable_with1, void>(), ...); - STATIC_ASSERT( - test_three_way_comparable_with1, partial_ordering>()); - STATIC_ASSERT( - test_three_way_comparable_with1, weak_ordering>()); - STATIC_ASSERT( - test_three_way_comparable_with1, strong_ordering>()); - - return true; -} -STATIC_ASSERT(test_three_way_comparable_with(std::make_integer_sequence{})); - -// Validate static properties of compare_three_way, compare_three_way_result, and compare_three_way_result_t -template -concept is_trait = requires { - typename T::type; -}; - -template -concept can_three_way = requires(T const& t, U const& u) { - t <=> u; -}; - -template -constexpr bool test_compare_three_way() { - STATIC_ASSERT(same_as>); - STATIC_ASSERT(same_as>); - - STATIC_ASSERT(can_three_way == !std::is_void_v); - STATIC_ASSERT(can_three_way == !std::is_void_v); - if constexpr (can_three_way) { - STATIC_ASSERT(same_as() <=> std::declval()), Cat>); - STATIC_ASSERT(same_as() <=> std::declval()), Cat>); - STATIC_ASSERT(same_as, Cat>); - STATIC_ASSERT(same_as, Cat>); - STATIC_ASSERT(same_as::type, Cat>); - STATIC_ASSERT(same_as::type, Cat>); - STATIC_ASSERT(same_as(), std::declval())), Cat>); - STATIC_ASSERT(same_as(), std::declval())), Cat>); - } else { - STATIC_ASSERT(!is_trait>); - STATIC_ASSERT(!is_trait>); - } - - return true; -} - -enum class some_enum { value }; - -STATIC_ASSERT(test_compare_three_way()); -STATIC_ASSERT(test_compare_three_way()); -STATIC_ASSERT(test_compare_three_way()); -STATIC_ASSERT(test_compare_three_way()); -#if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-1044530 -STATIC_ASSERT(test_compare_three_way()); -#endif // TRANSITION, DevCom-1044530 -STATIC_ASSERT(test_compare_three_way()); - -STATIC_ASSERT(test_compare_three_way()); -STATIC_ASSERT(test_compare_three_way()); - -STATIC_ASSERT(test_compare_three_way()); -STATIC_ASSERT(test_compare_three_way()); - -STATIC_ASSERT(test_compare_three_way()); -STATIC_ASSERT(test_compare_three_way()); - -template -struct compares_as {}; -template -bool operator==(compares_as const&, compares_as const&); -template -common_comparison_category_t operator<=>(compares_as const&, compares_as const&); - -template -struct std::common_type, compares_as> { - using type = common_comparable; -}; - -STATIC_ASSERT(test_compare_three_way, compares_as, partial_ordering>()); -STATIC_ASSERT(test_compare_three_way, compares_as, partial_ordering>()); -STATIC_ASSERT(test_compare_three_way, compares_as, partial_ordering>()); -STATIC_ASSERT(test_compare_three_way, compares_as, weak_ordering>()); -STATIC_ASSERT(test_compare_three_way, compares_as, weak_ordering>()); -STATIC_ASSERT(test_compare_three_way, compares_as, strong_ordering>()); - -// Validate dynamic properties of compare_three_way, ranges::equal_to, ranges::not_equal_to, ranges::less, -// ranges::less_equal, ranges::greater, ranges::greater_equal -#define assert_three_way(t, u, result) assert(compare_three_way{}((t), (u)) == (result)) - -template -constexpr void test_equality_comparable(T const& t, U const& u, strong_ordering const o) { - assert(ranges::equal_to{}(t, t)); - assert(ranges::equal_to{}(u, u)); - assert(ranges::equal_to{}(t, u) == (o == strong_ordering::equal)); - assert(ranges::equal_to{}(u, t) == (o == strong_ordering::equal)); - - assert(!ranges::not_equal_to{}(t, t)); - assert(!ranges::not_equal_to{}(u, u)); - assert(ranges::not_equal_to{}(t, u) == !(o == strong_ordering::equal)); - assert(ranges::not_equal_to{}(u, t) == !(o == strong_ordering::equal)); -} - -template -constexpr void test_totally_ordered(T const& t, U const& u, strong_ordering const o) { - test_equality_comparable(t, u, o); - - assert(!ranges::less{}(t, t)); - assert(!ranges::less{}(u, u)); - assert(ranges::less{}(t, u) == (o == strong_ordering::less)); - assert(ranges::less{}(u, t) == (o == strong_ordering::greater)); - - assert(!ranges::greater{}(t, t)); - assert(!ranges::greater{}(u, u)); - assert(ranges::greater{}(t, u) == (o == strong_ordering::greater)); - assert(ranges::greater{}(u, t) == (o == strong_ordering::less)); - - assert(ranges::less_equal{}(t, t)); - assert(ranges::less_equal{}(u, u)); - assert(ranges::less_equal{}(t, u) == !(o == strong_ordering::greater)); - assert(ranges::less_equal{}(u, t) == !(o == strong_ordering::less)); - - assert(ranges::greater_equal{}(t, t)); - assert(ranges::greater_equal{}(u, u)); - assert(ranges::greater_equal{}(t, u) == !(o == strong_ordering::less)); - assert(ranges::greater_equal{}(u, t) == !(o == strong_ordering::greater)); -} - -template -constexpr void test_strongly_ordered(T const& t, U const& u) { - assert(t < u); - test_totally_ordered(t, u, strong_ordering::less); - - assert_three_way(t, t, strong_ordering::equal); - assert_three_way(u, u, strong_ordering::equal); - assert_three_way(t, u, strong_ordering::less); - assert_three_way(u, t, strong_ordering::greater); -} - -template -constexpr void test_weakly_ordered(T const& t, U const& u, weak_ordering const o) { - assert_three_way(t, u, o); - - strong_ordering test_as = strong_ordering::equal; - - if (o == weak_ordering::equivalent) { - assert_three_way(u, t, weak_ordering::equivalent); - test_as = strong_ordering::equal; - } else if (o == weak_ordering::less) { - assert_three_way(u, t, weak_ordering::greater); - test_as = strong_ordering::less; - } else { - assert(o == weak_ordering::greater); - assert_three_way(u, t, weak_ordering::less); - test_as = strong_ordering::greater; - } - - test_totally_ordered(t, u, test_as); -} - -template -constexpr void test_partially_ordered(T const& t, U const& u, partial_ordering const o) { - assert_three_way(t, u, o); - - strong_ordering test_as = strong_ordering::equal; - - if (o == partial_ordering::equivalent) { - assert_three_way(u, t, partial_ordering::equivalent); - test_as = strong_ordering::equal; - } else if (o == partial_ordering::less) { - assert_three_way(u, t, partial_ordering::greater); - test_as = strong_ordering::less; - } else if (o == partial_ordering::greater) { - assert_three_way(u, t, partial_ordering::less); - test_as = strong_ordering::greater; - } else { - assert(o == partial_ordering::unordered); - assert_three_way(u, t, partial_ordering::unordered); - return; - } - - test_totally_ordered(t, u, test_as); -} - -void f1() {} -void f2() {} - -struct base {}; -struct derived : base {}; - -enum unscoped : int {}; -enum class scoped {}; - -// TRANSITION, VSO-980378 (use numeric_limits::quiet_NaN) -constexpr auto NaN = __builtin_nan("0"); -constexpr auto NaNf = __builtin_nanf("0"); - -constexpr void ordering_test_cases() { - // Validate types strongly ordered by builtin <=> operators - test_strongly_ordered(false, true); // bool (but not with other integral types) - - test_strongly_ordered(13, 42); // integral types (but not mixed-sign) - test_strongly_ordered(13, 42L); - test_strongly_ordered(13L, 42); - test_strongly_ordered(13U, 42U); - test_strongly_ordered(13U, 42UL); - test_strongly_ordered(13UL, 42U); - test_strongly_ordered(13U, L'x'); -#ifdef __cpp_char8_t - test_strongly_ordered(13U, u8'x'); -#endif // __cpp_char8_t - test_strongly_ordered(13U, u'x'); -#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1062618 - test_strongly_ordered(13U, U'x'); -#endif // TRANSITION, VSO-1062618 - - test_strongly_ordered(scoped{13}, scoped{42}); - test_strongly_ordered(unscoped{13}, unscoped{42}); - - int const some_ints[] = {13, 42}; - test_strongly_ordered(&some_ints[0], &some_ints[1]); - std::pair const int_pair{13, 42}; - test_strongly_ordered(&int_pair.first, &int_pair.second); - - derived const some_deriveds[2] = {}; - test_strongly_ordered(&some_deriveds[0], &some_deriveds[1]); -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 - if (!std::is_constant_evaluated()) -#endif // TRANSITION, VSO-938163 - { - test_strongly_ordered(static_cast(&some_deriveds[0]), &some_deriveds[1]); - test_strongly_ordered(&some_deriveds[0], static_cast(&some_deriveds[1])); - } - - if (!std::is_constant_evaluated()) { - test_strongly_ordered(&some_ints[0], static_cast(&some_ints[1])); - test_strongly_ordered(static_cast(&some_ints[0]), &some_ints[1]); - - std::pair const int_long_pair{13, 42L}; - test_strongly_ordered(static_cast(&int_long_pair.first), &int_long_pair.second); - test_strongly_ordered(&int_long_pair.first, static_cast(&int_long_pair.second)); - } - - // Validate types partially ordered by builtin <=> operators - test_partially_ordered(1.414, 3.14, partial_ordering::less); - test_partially_ordered(1.414f, 3.14, partial_ordering::less); - test_partially_ordered(1.414, 3.14f, partial_ordering::less); - test_partially_ordered(31.625f, 31.625, partial_ordering::equivalent); -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-1062601 - if (!std::is_constant_evaluated()) -#endif // TRANSITION, VSO-1062601 - { - test_partially_ordered(3.14, NaN, partial_ordering::unordered); - test_partially_ordered(3.14f, NaN, partial_ordering::unordered); - test_partially_ordered(3.14, NaNf, partial_ordering::unordered); - } - - // Validate types with no builtin <=> operators that are nonetheless totally_ordered (within a - // limited domain) or equality_comparable -#ifndef __clang__ -#pragma warning(push) -#pragma warning(disable : 4018) // '%s': signed/unsigned mismatch -#pragma warning(disable : 4389) // '%s': signed/unsigned mismatch -#endif // !__clang__ - test_totally_ordered(13, 42u, strong_ordering::less); - test_totally_ordered(13u, 42, strong_ordering::less); -#ifndef __clang__ -#pragma warning(pop) -#endif // !__clang__ - - test_totally_ordered(3.14, 42, strong_ordering::less); - test_totally_ordered(1, 3.14f, strong_ordering::less); - - test_equality_comparable(&f1, &f2, strong_ordering::less); // This means "not equal" - - struct has_members { - int x; - const int y; - - int f() { - return 13; - } - int g() noexcept { - return 42; - } - }; - test_equality_comparable(&has_members::x, &has_members::y, strong_ordering::less); // Ditto "not equal" - test_equality_comparable(&has_members::f, &has_members::g, strong_ordering::less); // Ditto "not equal" - - test_equality_comparable(nullptr, nullptr, strong_ordering::equal); - - // Validate class types - struct partially_ordered_class { - int i; - - constexpr explicit partially_ordered_class(int x) noexcept : i{x} {} - - partially_ordered_class(partially_ordered_class const&) = delete; - partially_ordered_class& operator=(partially_ordered_class const&) = delete; - - constexpr bool operator==(partially_ordered_class const& that) const { - if (i == 42 || that.i == 42) { - return false; - } else { - return i == that.i; - } - } - constexpr partial_ordering operator<=>(partially_ordered_class const& that) const { - if (i == 42 || that.i == 42) { - return partial_ordering::unordered; - } else { - return i <=> that.i; - } - } - }; - struct weakly_ordered_class { - int i; - - constexpr explicit weakly_ordered_class(int x) noexcept : i{x} {} - - weakly_ordered_class(weakly_ordered_class const&) = delete; - weakly_ordered_class& operator=(weakly_ordered_class const&) = delete; - - constexpr bool operator==(weakly_ordered_class const& that) const { - return i / 2 == that.i / 2; - } - constexpr weak_ordering operator<=>(weakly_ordered_class const& that) const { - return i / 2 <=> that.i / 2; - } - }; - struct strongly_ordered_class { - int i; - - constexpr explicit strongly_ordered_class(int x) noexcept : i{x} {} - - strongly_ordered_class(strongly_ordered_class const&) = delete; - strongly_ordered_class& operator=(strongly_ordered_class const&) = delete; - - auto operator<=>(strongly_ordered_class const&) const = default; - }; - - struct equality_comparable_class { - int i; - - struct boolish { - bool b; - constexpr operator bool() const { - return b; - } - }; - - constexpr explicit equality_comparable_class(int x) noexcept : i{x} {} - - equality_comparable_class(equality_comparable_class const&) = delete; - equality_comparable_class& operator=(equality_comparable_class const&) = delete; - - constexpr boolish operator==(equality_comparable_class const& that) const { - return {i == that.i}; - } - constexpr boolish operator!=(equality_comparable_class const& that) const { - return {i != that.i}; - } - }; - - struct totally_ordered_class : equality_comparable_class { - using equality_comparable_class::equality_comparable_class; - - constexpr boolish operator<(totally_ordered_class const& that) const { - return {i < that.i}; - } - constexpr boolish operator>(totally_ordered_class const& that) const { - return {i > that.i}; - } - constexpr boolish operator<=(totally_ordered_class const& that) const { - return {i <= that.i}; - } - constexpr boolish operator>=(totally_ordered_class const& that) const { - return {i >= that.i}; - } - }; - - test_partially_ordered(partially_ordered_class{13}, partially_ordered_class{42}, partial_ordering::unordered); - test_partially_ordered(partially_ordered_class{13}, partially_ordered_class{29}, partial_ordering::less); - test_weakly_ordered(weakly_ordered_class{13}, weakly_ordered_class{42}, weak_ordering::less); - test_weakly_ordered(weakly_ordered_class{13}, weakly_ordered_class{12}, weak_ordering::equivalent); - test_strongly_ordered(strongly_ordered_class{13}, strongly_ordered_class{42}); - test_equality_comparable(equality_comparable_class{13}, equality_comparable_class{13}, strong_ordering::equal); - test_equality_comparable(equality_comparable_class{13}, equality_comparable_class{42}, strong_ordering::less); - test_totally_ordered(totally_ordered_class{13}, totally_ordered_class{42}, strong_ordering::less); -} - -int main() { - STATIC_ASSERT((ordering_test_cases(), true)); - ordering_test_cases(); -} From 326461799923c50dfa86593685106695421a54d2 Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Fri, 31 Jul 2020 15:59:36 -0700 Subject: [PATCH 04/64] Don't rely on comparison re-writes --- stl/inc/regex | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index b9d48011f5a..f32102b1373 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -730,7 +730,10 @@ template _NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } -#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +#endif // _HAS_CXX20 + +// TRANSITION, VSO-900973 +// Overload resolution prefers implicit conversions over re-writes template _NODISCARD bool operator!=(const sub_match<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { return !(_Left == _Right); @@ -755,7 +758,6 @@ template _NODISCARD bool operator>=(const sub_match<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { return !(_Left < _Right); } -#endif // !_HAS_CXX20 // COMPARE sub_match AND NTBS template @@ -768,7 +770,10 @@ template _NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left ,const _Iter_value_t<_BidIt>* _Right) { return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } -#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +#endif // _HAS_CXX20 + +// TRANSITION, VSO-900973 +// Overload resolution prefers implicit conversions over re-writes template _NODISCARD bool operator!=(const _Iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { return !(_Left == _Right); @@ -823,7 +828,6 @@ template _NODISCARD bool operator>=(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>* _Right) { return !(_Left < _Right); } -#endif // !_HAS_CXX20 // COMPARE sub_match AND ELEMENT template @@ -836,7 +840,10 @@ template _NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { return static_cast::_Comparison_category>(_Left._Compare(_STD addressof(_Right), 1) <=> 0); } -#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +#endif // _HAS_CXX20 + +// TRANSITION, VSO-900973 +// Overload resolution prefers implicit conversions over re-writes template _NODISCARD bool operator!=(const _Iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { return !(_Left == _Right); @@ -891,7 +898,6 @@ template _NODISCARD bool operator>=(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { return !(_Left < _Right); } -#endif // !_HAS_CXX20 // COMPARE sub_match AND string template @@ -906,7 +912,10 @@ _NODISCARD bool operator<=>( const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } -#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +#endif // _HAS_CXX20 + +// TRANSITION, VSO-900973 +// Overload resolution prefers implicit conversions over re-writes template _NODISCARD bool operator!=( const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { @@ -972,7 +981,6 @@ _NODISCARD bool operator>=( const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { return !(_Left < _Right); } -#endif // !_HAS_CXX20 // INSERT sub_match IN STREAM template From ec851f942178fd658eb3cd2164d853a3ea55eae4 Mon Sep 17 00:00:00 2001 From: Curtis Bezault Date: Tue, 4 Aug 2020 10:59:24 -0700 Subject: [PATCH 05/64] Test all the comparison ops. Add back != because of compiler bug --- stl/inc/regex | 8 ++-- tests/std/tests/P1614R2_spaceship/test.cpp | 47 ++++++++-------------- 2 files changed, 21 insertions(+), 34 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index f32102b1373..d36c04c2fb9 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1188,12 +1188,12 @@ _NODISCARD bool operator==(const match_results<_BidIt, _Alloc>& _Left, const mat } } -#if !_HAS_CXX20 +// TRANSITION, VSO-900973 +// Overload resolution prefers implicit conversions over re-writes template _NODISCARD bool operator!=(const match_results<_BidIt, _Alloc>& _Left, const match_results<_BidIt, _Alloc>& _Right) { return !(_Left == _Right); } -#endif // !_HAS_CXX20 // NFA PROPERTIES const unsigned int _BRE_MAX_GRP = 9U; @@ -2484,11 +2484,11 @@ public: && _MyVal._At(0) == _Right._MyVal._At(0); } -#if !_HAS_CXX20 +// TRANSITION, VSO-900973 +// Overload resolution prefers implicit conversions over re-writes _NODISCARD bool operator!=(const regex_iterator& _Right) const { return !(*this == _Right); } -#endif // !_HAS_CXX20 _NODISCARD const value_type& operator*() const { #if _ITERATOR_DEBUG_LEVEL != 0 diff --git a/tests/std/tests/P1614R2_spaceship/test.cpp b/tests/std/tests/P1614R2_spaceship/test.cpp index bafca9d5eae..e3e0374a2e6 100644 --- a/tests/std/tests/P1614R2_spaceship/test.cpp +++ b/tests/std/tests/P1614R2_spaceship/test.cpp @@ -90,9 +90,8 @@ struct PartiallyOrderedChar : public OrderedChar {}; namespace std { template <> - struct char_traits : public std::char_traits { - using char_type = WeaklyOrderedChar; - using comparison_category = std::weak_ordering; + struct char_traits : public std::char_traits { + using char_type = OrderedChar; static int compare(const char_type* first1, const char_type* first2, size_t count) { for (; 0 < count; --count, ++first1, ++first2) { @@ -108,38 +107,20 @@ namespace std }; template <> - struct char_traits : public std::char_traits { - using char_type = WeaklyOrderdByOmissionChar; - - static int compare(const char_type* first1, const char_type* first2, size_t count) { - for (; 0 < count; --count, ++first1, ++first2) { - if (*first1 != *first2) { - return *first1 < *first2 ? -1 : +1; - } - } - - return 0; - } + struct char_traits : public std::char_traits { + using char_type = WeaklyOrderedChar; + using comparison_category = std::weak_ordering; + }; - static bool eq(const char_type l, const char_type r) { return l.c == r.c; } + template <> + struct char_traits : public std::char_traits { + using char_type = WeaklyOrderdByOmissionChar; }; template <> - struct char_traits : public std::char_traits { + struct char_traits : public std::char_traits { using char_type = PartiallyOrderedChar; using comparison_category = std::partial_ordering; - - static int compare(const char_type* first1, const char_type* first2, size_t count) { - for (; 0 < count; --count, ++first1, ++first2) { - if (*first1 != *first2) { - return *first1 < *first2 ? -1 : +1; - } - } - - return 0; - } - - static bool eq(const char_type l, const char_type r) { return l.c == r.c; } }; } @@ -397,17 +378,23 @@ void ordering_test_cases() { const std::string s1{"cats"}; const std::string s2{"meow"}; const std::regex all(".*"); - std::smatch m1, m2; + const std::regex each("."); + std::smatch m1, m2, m3; std::regex_match(s1, m1, all); std::regex_match(s2, m2, all); + std::regex_search(s1, m3, each); std::ssub_match sm1 = m1[0]; std::ssub_match sm1_equal = m1[0]; std::ssub_match sm2 = m2[0]; + std::ssub_match sm3 = m3[0]; // TRANSITION: std::char_traits doesn't define comparison_type spaceship_test(sm1, sm1_equal, sm2); + spaceship_test(sm1, s1, s2); + spaceship_test(sm1, s1.c_str(), s2.c_str()); + spaceship_test(sm3, 'c', 'm'); using StronglyOrderedMatch = std::ssub_match; using WeaklyOrderedMatch = std::sub_match::const_iterator>; From 00638f6b488c3c1d4872f40aecfaf8012d562502 Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Tue, 4 Aug 2020 11:10:31 -0700 Subject: [PATCH 06/64] clang-format --- stl/inc/regex | 25 +++++------ tests/std/tests/P1614R2_spaceship/test.cpp | 49 +++++++++++----------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index d36c04c2fb9..25b34624930 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -594,15 +594,15 @@ bool _Is_word(_Elem _Ch) { } #if _HAS_CXX20 - template - struct _Get_comparison_category { - using type = weak_ordering; - }; +template +struct _Get_comparison_category { + using type = weak_ordering; +}; - template - struct _Get_comparison_category<_Ty, void_t> { - using type = typename _Ty::comparison_category; - }; +template +struct _Get_comparison_category<_Ty, void_t> { + using type = typename _Ty::comparison_category; +}; #endif // _HAS_CXX20 // CLASS TEMPLATE sub_match @@ -767,7 +767,7 @@ _NODISCARD bool operator==(const _Iter_value_t<_BidIt>* _Left, const sub_match<_ #if _HAS_CXX20 template -_NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left ,const _Iter_value_t<_BidIt>* _Right) { +_NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>* _Right) { return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } #endif // _HAS_CXX20 @@ -838,7 +838,8 @@ _NODISCARD bool operator==(const _Iter_value_t<_BidIt>& _Left, const sub_match<_ #if _HAS_CXX20 template _NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { - return static_cast::_Comparison_category>(_Left._Compare(_STD addressof(_Right), 1) <=> 0); + return static_cast::_Comparison_category>( + _Left._Compare(_STD addressof(_Right), 1) <=> 0); } #endif // _HAS_CXX20 @@ -2484,8 +2485,8 @@ public: && _MyVal._At(0) == _Right._MyVal._At(0); } -// TRANSITION, VSO-900973 -// Overload resolution prefers implicit conversions over re-writes + // TRANSITION, VSO-900973 + // Overload resolution prefers implicit conversions over re-writes _NODISCARD bool operator!=(const regex_iterator& _Right) const { return !(*this == _Right); } diff --git a/tests/std/tests/P1614R2_spaceship/test.cpp b/tests/std/tests/P1614R2_spaceship/test.cpp index e3e0374a2e6..0c91afc2a47 100644 --- a/tests/std/tests/P1614R2_spaceship/test.cpp +++ b/tests/std/tests/P1614R2_spaceship/test.cpp @@ -60,26 +60,25 @@ struct SynthOrdered { struct OrderedChar { OrderedChar() = default; - OrderedChar(const char c) : c(c) {}; + OrderedChar(const char c) : c(c){}; - OrderedChar& operator=(const char& other) - { + OrderedChar& operator=(const char& other) { this->c = other; return *this; } - operator char() { return c; } + operator char() { + return c; + } char c; }; -auto operator<=>(const OrderedChar& left, const OrderedChar& right) -{ +auto operator<=>(const OrderedChar& left, const OrderedChar& right) { return left.c <=> right.c; } -auto operator==(const OrderedChar& left, const OrderedChar& right) -{ +auto operator==(const OrderedChar& left, const OrderedChar& right) { return left.c == right.c; } @@ -87,8 +86,7 @@ struct WeaklyOrderedChar : public OrderedChar {}; struct WeaklyOrderdByOmissionChar : public OrderedChar {}; struct PartiallyOrderedChar : public OrderedChar {}; -namespace std -{ +namespace std { template <> struct char_traits : public std::char_traits { using char_type = OrderedChar; @@ -103,12 +101,14 @@ namespace std return 0; } - static bool eq(const char_type l, const char_type r) { return l.c == r.c; } + static bool eq(const char_type l, const char_type r) { + return l.c == r.c; + } }; template <> struct char_traits : public std::char_traits { - using char_type = WeaklyOrderedChar; + using char_type = WeaklyOrderedChar; using comparison_category = std::weak_ordering; }; @@ -119,14 +119,13 @@ namespace std template <> struct char_traits : public std::char_traits { - using char_type = PartiallyOrderedChar; + using char_type = PartiallyOrderedChar; using comparison_category = std::partial_ordering; }; -} +} // namespace std -template -void spaceship_test(const SmallType& smaller, const EqualType& smaller_equal, const LargeType& larger) -{ +template +void spaceship_test(const SmallType& smaller, const EqualType& smaller_equal, const LargeType& larger) { assert(smaller == smaller_equal); assert(smaller != larger); assert(smaller < larger); @@ -140,9 +139,8 @@ void spaceship_test(const SmallType& smaller, const EqualType& smaller_equal, co static_assert(std::is_same_v larger), ReturnType>); } -template -void spaceship_test(const TestType& smaller, const TestType& smaller_equal, const TestType& larger) -{ +template +void spaceship_test(const TestType& smaller, const TestType& smaller_equal, const TestType& larger) { return spaceship_test(smaller, smaller_equal, larger); } @@ -385,10 +383,10 @@ void ordering_test_cases() { std::regex_match(s2, m2, all); std::regex_search(s1, m3, each); - std::ssub_match sm1 = m1[0]; + std::ssub_match sm1 = m1[0]; std::ssub_match sm1_equal = m1[0]; - std::ssub_match sm2 = m2[0]; - std::ssub_match sm3 = m3[0]; + std::ssub_match sm2 = m2[0]; + std::ssub_match sm3 = m3[0]; // TRANSITION: std::char_traits doesn't define comparison_type spaceship_test(sm1, sm1_equal, sm2); @@ -397,8 +395,9 @@ void ordering_test_cases() { spaceship_test(sm3, 'c', 'm'); using StronglyOrderedMatch = std::ssub_match; - using WeaklyOrderedMatch = std::sub_match::const_iterator>; - using WeaklyOrderdByOmissionMatch = std::sub_match::const_iterator>; + using WeaklyOrderedMatch = std::sub_match::const_iterator>; + using WeaklyOrderdByOmissionMatch = + std::sub_match::const_iterator>; using PartiallyOrderedMatch = std::sub_match::const_iterator>; // TRANSITION: std::char_traits doesn't define comparison_type From f50220b2471e7289e18064a58e4350a5df77d2c1 Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Tue, 4 Aug 2020 13:27:17 -0700 Subject: [PATCH 07/64] Fix compilation error in regex spaceship tests. Fix bug uncovered by fixed tests. --- stl/inc/regex | 2 +- tests/std/tests/P1614R2_spaceship/test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index 25b34624930..78e8756b53f 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -909,7 +909,7 @@ _NODISCARD bool operator==( #if _HAS_CXX20 template -_NODISCARD bool operator<=>( +_NODISCARD auto operator<=>( const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } diff --git a/tests/std/tests/P1614R2_spaceship/test.cpp b/tests/std/tests/P1614R2_spaceship/test.cpp index 0c91afc2a47..a6cf486ee44 100644 --- a/tests/std/tests/P1614R2_spaceship/test.cpp +++ b/tests/std/tests/P1614R2_spaceship/test.cpp @@ -390,7 +390,7 @@ void ordering_test_cases() { // TRANSITION: std::char_traits doesn't define comparison_type spaceship_test(sm1, sm1_equal, sm2); - spaceship_test(sm1, s1, s2); + spaceship_test(sm1, s1, s2); spaceship_test(sm1, s1.c_str(), s2.c_str()); spaceship_test(sm3, 'c', 'm'); From 460440f9c8f5b7e60a7e1c185ac7a597f48d5a7c Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Thu, 6 Aug 2020 15:28:50 -0700 Subject: [PATCH 08/64] Resolve Casey's comments --- stl/inc/regex | 300 +++++++-- .../tests/P0896R4_P1614R2_comparisons/env.lst | 4 + .../P0896R4_P1614R2_comparisons/test.cpp | 604 ++++++++++++++++++ tests/std/tests/P1614R2_spaceship/test.cpp | 56 +- 4 files changed, 899 insertions(+), 65 deletions(-) create mode 100644 tests/std/tests/P0896R4_P1614R2_comparisons/env.lst create mode 100644 tests/std/tests/P0896R4_P1614R2_comparisons/test.cpp diff --git a/stl/inc/regex b/stl/inc/regex index 78e8756b53f..7ef4e498940 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -595,12 +594,12 @@ bool _Is_word(_Elem _Ch) { #if _HAS_CXX20 template -struct _Get_comparison_category { +struct _Get_member_comparison_category { using type = weak_ordering; }; template -struct _Get_comparison_category<_Ty, void_t> { +struct _Get_member_comparison_category<_Ty, void_t> { using type = typename _Ty::comparison_category; }; #endif // _HAS_CXX20 @@ -620,7 +619,7 @@ public: using _Size_type = typename string_type::size_type; #if _HAS_CXX20 - using _Comparison_category = typename _Get_comparison_category<_Traits>::type; + using _Comparison_category = typename _Get_member_comparison_category<_Traits>::type; #endif // _HAS_CXX20 constexpr sub_match() : _Mybase(), matched(false) {} @@ -730,10 +729,36 @@ template _NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } -#endif // _HAS_CXX20 -// TRANSITION, VSO-900973 -// Overload resolution prefers implicit conversions over re-writes +#if 1 // TRANSITION, VSO-900973 +// Overload resolution prefers implicit conversions over re-writes. +// In C++20 mode the only required comparison operators should be == and <=>. +template +_NODISCARD bool operator!=(const sub_match<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { + return !(_Left == _Right); +} + +template +_NODISCARD bool operator<(const sub_match<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) < 0; +} + +template +_NODISCARD bool operator>(const sub_match<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) > 0; +} + +template +_NODISCARD bool operator<=(const sub_match<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) <= 0; +} + +template +_NODISCARD bool operator>=(const sub_match<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) >= 0; +} +#endif // TRANSITION, VSO-900973 +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template _NODISCARD bool operator!=(const sub_match<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { return !(_Left == _Right); @@ -758,22 +783,89 @@ template _NODISCARD bool operator>=(const sub_match<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { return !(_Left < _Right); } +#endif // !_HAS_CXX20 // COMPARE sub_match AND NTBS template -_NODISCARD bool operator==(const _Iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { - return _Right._Match_equal(_Left); +_NODISCARD bool operator==(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>* _Right) { + return _Left._Match_equal(_Right); } #if _HAS_CXX20 template -_NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>* _Right) { +_NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>* _Right) { return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } -#endif // _HAS_CXX20 -// TRANSITION, VSO-900973 -// Overload resolution prefers implicit conversions over re-writes +#if 1 // TRANSITION, VSO-900973 +// Overload resolution prefers implicit conversions over re-writes. +// In C++20 mode the only required comparison operators should be == and <=>. +template +_NODISCARD auto operator<=>(const iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { + return static_cast::_Comparison_category>(0 <=> (_Right <=>_Left)); +} + +template +_NODISCARD bool operator==(const iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { + return _Right._Match_equal(_Left); +} + +template +_NODISCARD bool operator!=(const iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { + return !(_Left == _Right); +} + +template +_NODISCARD bool operator<(const iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) < 0; +} + +template +_NODISCARD bool operator>(const iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) > 0; +} + +template +_NODISCARD bool operator<=(const iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) <= 0; +} + +template +_NODISCARD bool operator>=(const iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) >= 0; +} + +template +_NODISCARD bool operator!=(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>* _Right) { + return !(_Left == _Right); +} + +template +_NODISCARD bool operator<(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>* _Right) { + return (_Left <=> _Right) < 0; +} + +template +_NODISCARD bool operator>(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>* _Right) { + return (_Left <=> _Right) > 0; +} + +template +_NODISCARD bool operator<=(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>* _Right) { + return (_Left <=> _Right) <= 0; +} + +template +_NODISCARD bool operator>=(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>* _Right) { + return (_Left <=> _Right) >= 0; +} +#endif // TRANSTITION, VSO-900973 +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +template +_NODISCARD bool operator==(const _Iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { + return _Right._Match_equal(_Left); +} + template _NODISCARD bool operator!=(const _Iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { return !(_Left == _Right); @@ -799,11 +891,6 @@ _NODISCARD bool operator>=(const _Iter_value_t<_BidIt>* _Left, const sub_match<_ return !(_Left < _Right); } -template -_NODISCARD bool operator==(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>* _Right) { - return _Left._Match_equal(_Right); -} - template _NODISCARD bool operator!=(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>* _Right) { return !(_Left == _Right); @@ -828,25 +915,92 @@ template _NODISCARD bool operator>=(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>* _Right) { return !(_Left < _Right); } +#endif // !_HAS_CXX20 // COMPARE sub_match AND ELEMENT template -_NODISCARD bool operator==(const _Iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { - return _Right._Match_equal(_STD addressof(_Left), 1); +_NODISCARD bool operator==(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { + return _Left._Match_equal(_STD addressof(_Right), 1); } #if _HAS_CXX20 template -_NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { +_NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>& _Right) { return static_cast::_Comparison_category>( _Left._Compare(_STD addressof(_Right), 1) <=> 0); } -#endif // _HAS_CXX20 -// TRANSITION, VSO-900973 -// Overload resolution prefers implicit conversions over re-writes +#if 1 // TRANSITION, VSO-900973 +// Overload resolution prefers implicit conversions over re-writes. +// In C++20 mode the only required comparison operators should be == and <=>. +template +_NODISCARD auto operator<=>(const iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { + return static_cast::_Comparison_category>(0 <=> (_Right <=> _Left)); +} + template -_NODISCARD bool operator!=(const _Iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { +_NODISCARD bool operator==(const iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { + return _Right._Match_equal(_STD addressof(_Left), 1); +} + +template +_NODISCARD bool operator!=(const iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { + return !(_Left == _Right); +} + +template +_NODISCARD bool operator<(const iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) < 0; +} + +template +_NODISCARD bool operator>(const iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) > 0; +} + +template +_NODISCARD bool operator<=(const iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) <= 0; +} + +template +_NODISCARD bool operator>=(const iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) >= 0; +} + +template +_NODISCARD bool operator!=(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>& _Right) { + return !(_Left == _Right); +} + +template +_NODISCARD bool operator<(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>& _Right) { + return (_Left <=> _Right) < 0; +} + +template +_NODISCARD bool operator>(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>& _Right) { + return (_Left <=> _Right) > 0; +} + +template +_NODISCARD bool operator<=(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>& _Right) { + return (_Left <=> _Right) <= 0; +} + +template +_NODISCARD bool operator>=(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>& _Right) { + return (_Left <=> _Right) >= 0; +} +#endif // TRANSITION, VSO-900973 +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +template +_NODISCARD bool operator==(const _Iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { + return _Right._Match_equal(_STD addressof(_Left), 1); +} + +template +_NODISCARD bool operator!=(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { return !(_Left == _Right); } @@ -870,11 +1024,6 @@ _NODISCARD bool operator>=(const _Iter_value_t<_BidIt>& _Left, const sub_match<_ return !(_Left < _Right); } -template -_NODISCARD bool operator==(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { - return _Left._Match_equal(_STD addressof(_Right), 1); -} - template _NODISCARD bool operator!=(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { return !(_Left == _Right); @@ -899,6 +1048,7 @@ template _NODISCARD bool operator>=(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { return !(_Left < _Right); } +#endif // !_HAS_CXX20 // COMPARE sub_match AND string template @@ -910,13 +1060,86 @@ _NODISCARD bool operator==( #if _HAS_CXX20 template _NODISCARD auto operator<=>( - const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { + const sub_match<_BidIt>& _Left, const basic_string, _Traits, _Alloc>& _Right) { return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } -#endif // _HAS_CXX20 -// TRANSITION, VSO-900973 -// Overload resolution prefers implicit conversions over re-writes +#if 1 // TRANSITION, VSO-900973 +// Overload resolution prefers implicit conversions over re-writes. +// In C++20 mode the only required comparison operators should be == and <=>. +template +_NODISCARD auto operator<=>( + const basic_string, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + return static_cast::_Comparison_category>(0 <=> (_Right <=> _Left)); +} + +template +_NODISCARD bool operator!=( + const sub_match<_BidIt>& _Left, const basic_string, _Traits, _Alloc>& _Right) { + return !(_Left == _Right); +} + +template +_NODISCARD bool operator<( + const sub_match<_BidIt>& _Left, const basic_string, _Traits, _Alloc>& _Right) { + return (_Left <=> _Right) < 0; +} + +template +_NODISCARD bool operator>( + const sub_match<_BidIt>& _Left, const basic_string, _Traits, _Alloc>& _Right) { + return (_Left <=> _Right) > 0; +} + +template +_NODISCARD bool operator<=( + const sub_match<_BidIt>& _Left, const basic_string, _Traits, _Alloc>& _Right) { + return (_Left <=> _Right) <= 0; +} + +template +_NODISCARD bool operator>=( + const sub_match<_BidIt>& _Left, const basic_string, _Traits, _Alloc>& _Right) { + return (_Left <=> _Right) >= 0; +} + +template +_NODISCARD bool operator==( + const basic_string, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + return _Right._Match_equal(_Left.data(), _Left.size()); +} + +template +_NODISCARD bool operator!=( + const basic_string, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + return !(_Left == _Right); +} + +template +_NODISCARD bool operator<( + const basic_string, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) < 0; +} + +template +_NODISCARD bool operator>( + const basic_string, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) > 0; +} + +template +_NODISCARD bool operator<=( + const basic_string, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) <= 0; +} + +template +_NODISCARD bool operator>=( + const basic_string, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) >= 0; +} +#endif // TRANSITION, VSO-900973 +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template _NODISCARD bool operator!=( const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { @@ -982,6 +1205,7 @@ _NODISCARD bool operator>=( const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { return !(_Left < _Right); } +#endif // !_HAS_CXX20 // INSERT sub_match IN STREAM template @@ -1189,12 +1413,12 @@ _NODISCARD bool operator==(const match_results<_BidIt, _Alloc>& _Left, const mat } } -// TRANSITION, VSO-900973 -// Overload resolution prefers implicit conversions over re-writes +#if !_HAS_CXX20 template _NODISCARD bool operator!=(const match_results<_BidIt, _Alloc>& _Left, const match_results<_BidIt, _Alloc>& _Right) { return !(_Left == _Right); } +#endif // NFA PROPERTIES const unsigned int _BRE_MAX_GRP = 9U; @@ -2485,11 +2709,11 @@ public: && _MyVal._At(0) == _Right._MyVal._At(0); } - // TRANSITION, VSO-900973 - // Overload resolution prefers implicit conversions over re-writes +#if !_HAS_CXX20 _NODISCARD bool operator!=(const regex_iterator& _Right) const { return !(*this == _Right); } +#endif // !_HAS_CXX20 _NODISCARD const value_type& operator*() const { #if _ITERATOR_DEBUG_LEVEL != 0 diff --git a/tests/std/tests/P0896R4_P1614R2_comparisons/env.lst b/tests/std/tests/P0896R4_P1614R2_comparisons/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_P1614R2_comparisons/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_P1614R2_comparisons/test.cpp b/tests/std/tests/P0896R4_P1614R2_comparisons/test.cpp new file mode 100644 index 00000000000..ebf0022a565 --- /dev/null +++ b/tests/std/tests/P0896R4_P1614R2_comparisons/test.cpp @@ -0,0 +1,604 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// Covers: +// * three_way_comparable and three_way_comparable_with +// * compare_three_way, compare_three_way_result, and compare_three_way_result_t +// * ranges::equal_to, ranges::not_equal_to, ranges::less, ranges::less_equal, +// ranges::greater, and ranges::greater_equal + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wsign-compare" +#endif // __clang__ + +#include +#include +#include +#include +#include +#include +#include + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +namespace ranges = std::ranges; + +using std::common_comparison_category_t; +using std::compare_three_way, std::compare_three_way_result, std::compare_three_way_result_t; +using std::partial_ordering, std::weak_ordering, std::strong_ordering; +using std::same_as, std::convertible_to; +using std::three_way_comparable, std::three_way_comparable_with; + +template +constexpr bool is_one_of = (same_as || ...); + +struct common_comparable { + template + common_comparable(T&&); + + bool operator==(common_comparable const&) const; + strong_ordering operator<=>(common_comparable const&) const; +}; + +struct common_incomparable { + template + common_incomparable(T&&); +}; + +// Validate properties common to the concept-constrained comparison object types +template +constexpr bool is_trivially_constexpr() { + STATIC_ASSERT(std::semiregular); + + // Not required, but likely portable nonetheless: + STATIC_ASSERT(std::is_empty_v); + STATIC_ASSERT(std::is_trivial_v); + STATIC_ASSERT(std::is_trivially_copy_constructible_v); + STATIC_ASSERT(std::is_trivially_move_constructible_v); + STATIC_ASSERT(std::is_trivially_copy_assignable_v); + STATIC_ASSERT(std::is_trivially_move_assignable_v); + + // Not required to be constant expressions, but likely portable nonetheless: + T value_initialized{}; + T copy_constructed = value_initialized; + T move_constructed = std::move(copy_constructed); + copy_constructed = std::move(move_constructed); + move_constructed = copy_constructed; + + return true; +} + +STATIC_ASSERT(is_trivially_constexpr()); +STATIC_ASSERT(is_trivially_constexpr()); +STATIC_ASSERT(is_trivially_constexpr()); +STATIC_ASSERT(is_trivially_constexpr()); +STATIC_ASSERT(is_trivially_constexpr()); +STATIC_ASSERT(is_trivially_constexpr()); +STATIC_ASSERT(is_trivially_constexpr()); + +// Validate three_way_comparable +template +struct three_way_archetype { + three_way_archetype() = delete; + three_way_archetype(three_way_archetype const&) = delete; + three_way_archetype& operator=(three_way_archetype const&) = delete; + ~three_way_archetype() = delete; + // clang-format off + // 0: not equality_comparable + bool operator==(three_way_archetype const&) const requires (I == 0) = delete; + bool operator==(three_way_archetype const&) const requires (I != 0); + // 1: not totally_ordered + bool operator<(three_way_archetype const&) const requires (I == 1) = delete; + bool operator<(three_way_archetype const&) const requires (I != 1); + bool operator>(three_way_archetype const&) const requires (I != 1); + bool operator<=(three_way_archetype const&) const requires (I != 1); + bool operator>=(three_way_archetype const&) const requires (I != 1); + // 2: <=> isn't defined + Category operator<=>(three_way_archetype const&) const requires (I != 2 && I != 3); + // 3: <=> doesn't return a comparison category type + int operator<=>(three_way_archetype const&) const requires (I == 3); + // clang-format on +}; +constexpr int three_way_archetype_max = 4; + +template +constexpr bool test_three_way_comparable1() { + STATIC_ASSERT(is_one_of); + + STATIC_ASSERT(three_way_comparable == convertible_to); + STATIC_ASSERT(three_way_comparable == convertible_to); + STATIC_ASSERT(three_way_comparable == same_as); + + STATIC_ASSERT(three_way_comparable_with == convertible_to); + STATIC_ASSERT(three_way_comparable_with == convertible_to); + STATIC_ASSERT(three_way_comparable_with == same_as); + + return true; +} + +template +constexpr bool test_three_way_comparable(std::integer_sequence) { + (test_three_way_comparable1, void>(), ...); + (test_three_way_comparable1, void>(), ...); + (test_three_way_comparable1, void>(), ...); + STATIC_ASSERT( + test_three_way_comparable1, partial_ordering>()); + STATIC_ASSERT( + test_three_way_comparable1, weak_ordering>()); + STATIC_ASSERT( + test_three_way_comparable1, strong_ordering>()); + + return true; +} +STATIC_ASSERT(test_three_way_comparable(std::make_integer_sequence{})); + +// Validate three_way_comparable_with +// clang-format off + +// 4: not common_reference_with +// 5: common_reference_t is not three_way_comparable +template + requires ((I1 != I2 || !same_as) && I1 != 4 && I2 != 4) +struct std::common_type, three_way_archetype> { + using type = conditional_t; +}; + +// 6: not _Weakly_equality_comparable_with +template + requires ((I1 != I2 || !same_as) && (I1 == 6 || I2 == 6)) +bool operator==(three_way_archetype const&, three_way_archetype const&) = delete; +template + requires ((I1 != I2 || !same_as) && I1 != 6 && I2 != 6) +bool operator==(three_way_archetype const&, three_way_archetype const&); + +// 7: not _Partially_ordered_with +template + requires ((I1 != I2 || !same_as) && (I1 == 7 || I2 == 7)) +bool operator<(three_way_archetype const&, three_way_archetype const&) = delete; +template + requires ((I1 != I2 || !same_as) && I1 != 7 && I2 != 7) +bool operator<(three_way_archetype const&, three_way_archetype const&); +template + requires (I1 != I2 || !same_as) +bool operator>(three_way_archetype const&, three_way_archetype const&); +template + requires (I1 != I2 || !same_as) +bool operator<=(three_way_archetype const&, three_way_archetype const&); +template + requires (I1 != I2 || !same_as) +bool operator>=(three_way_archetype const&, three_way_archetype const&); + +// 8: <=> isn't defined +template + requires ((I1 != I2 || !same_as) && I1 != 8 && I1 != 9 && I2 != 8 && I2 != 9) +common_comparison_category_t operator<=>( + three_way_archetype const&, three_way_archetype const&); + +// 9: <=> returns a non-comparison category type +template + requires ((I1 != I2 || !same_as) && I1 == 9 && I2 == 9) +int operator<=>(three_way_archetype const&, three_way_archetype const&); + +// clang-format on + +constexpr int three_way_with_max = 10; + +template +constexpr bool test_three_way_comparable_with1() { + STATIC_ASSERT(is_one_of); + + // All specializations of three_way_archetype for which I >= three_way_with_max are "good"; we need such a + // specialization that is different from three_way_archetype to ensure we're fully testing + // the cross-type three_way_comparable_with concept. Why not three_way_with_max + 1? + constexpr int three_way_known_good = three_way_with_max + 1; + + using P = three_way_archetype; + using W = three_way_archetype; + using S = three_way_archetype; + + STATIC_ASSERT(three_way_comparable_with == convertible_to); + STATIC_ASSERT(three_way_comparable_with == convertible_to); + STATIC_ASSERT(three_way_comparable_with == same_as); + + return true; +} + +template +constexpr bool test_three_way_comparable_with(std::integer_sequence) { + (test_three_way_comparable_with1, void>(), ...); + (test_three_way_comparable_with1, void>(), ...); + (test_three_way_comparable_with1, void>(), ...); + STATIC_ASSERT( + test_three_way_comparable_with1, partial_ordering>()); + STATIC_ASSERT( + test_three_way_comparable_with1, weak_ordering>()); + STATIC_ASSERT( + test_three_way_comparable_with1, strong_ordering>()); + + return true; +} +STATIC_ASSERT(test_three_way_comparable_with(std::make_integer_sequence{})); + +// Validate static properties of compare_three_way, compare_three_way_result, and compare_three_way_result_t +template +concept is_trait = requires { + typename T::type; +}; + +template +concept can_three_way = requires(T const& t, U const& u) { + t <=> u; +}; + +template +constexpr bool test_compare_three_way() { + STATIC_ASSERT(same_as>); + STATIC_ASSERT(same_as>); + + STATIC_ASSERT(can_three_way == !std::is_void_v); + STATIC_ASSERT(can_three_way == !std::is_void_v); + if constexpr (can_three_way) { + STATIC_ASSERT(same_as() <=> std::declval()), Cat>); + STATIC_ASSERT(same_as() <=> std::declval()), Cat>); + STATIC_ASSERT(same_as, Cat>); + STATIC_ASSERT(same_as, Cat>); + STATIC_ASSERT(same_as::type, Cat>); + STATIC_ASSERT(same_as::type, Cat>); + STATIC_ASSERT(same_as(), std::declval())), Cat>); + STATIC_ASSERT(same_as(), std::declval())), Cat>); + } else { + STATIC_ASSERT(!is_trait>); + STATIC_ASSERT(!is_trait>); + } + + return true; +} + +enum class some_enum { value }; + +STATIC_ASSERT(test_compare_three_way()); +STATIC_ASSERT(test_compare_three_way()); +STATIC_ASSERT(test_compare_three_way()); +STATIC_ASSERT(test_compare_three_way()); +#if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-1044530 +STATIC_ASSERT(test_compare_three_way()); +#endif // TRANSITION, DevCom-1044530 +STATIC_ASSERT(test_compare_three_way()); + +STATIC_ASSERT(test_compare_three_way()); +STATIC_ASSERT(test_compare_three_way()); + +STATIC_ASSERT(test_compare_three_way()); +STATIC_ASSERT(test_compare_three_way()); + +STATIC_ASSERT(test_compare_three_way()); +STATIC_ASSERT(test_compare_three_way()); + +template +struct compares_as {}; +template +bool operator==(compares_as const&, compares_as const&); +template +common_comparison_category_t operator<=>(compares_as const&, compares_as const&); + +template +struct std::common_type, compares_as> { + using type = common_comparable; +}; + +STATIC_ASSERT(test_compare_three_way, compares_as, partial_ordering>()); +STATIC_ASSERT(test_compare_three_way, compares_as, partial_ordering>()); +STATIC_ASSERT(test_compare_three_way, compares_as, partial_ordering>()); +STATIC_ASSERT(test_compare_three_way, compares_as, weak_ordering>()); +STATIC_ASSERT(test_compare_three_way, compares_as, weak_ordering>()); +STATIC_ASSERT(test_compare_three_way, compares_as, strong_ordering>()); + +// Validate dynamic properties of compare_three_way, ranges::equal_to, ranges::not_equal_to, ranges::less, +// ranges::less_equal, ranges::greater, ranges::greater_equal +#define assert_three_way(t, u, result) assert(compare_three_way{}((t), (u)) == (result)) + +template +constexpr void test_equality_comparable(T const& t, U const& u, strong_ordering const o) { + assert(ranges::equal_to{}(t, t)); + assert(ranges::equal_to{}(u, u)); + assert(ranges::equal_to{}(t, u) == (o == strong_ordering::equal)); + assert(ranges::equal_to{}(u, t) == (o == strong_ordering::equal)); + + assert(!ranges::not_equal_to{}(t, t)); + assert(!ranges::not_equal_to{}(u, u)); + assert(ranges::not_equal_to{}(t, u) == !(o == strong_ordering::equal)); + assert(ranges::not_equal_to{}(u, t) == !(o == strong_ordering::equal)); +} + +template +constexpr void test_totally_ordered(T const& t, U const& u, strong_ordering const o) { + test_equality_comparable(t, u, o); + + assert(!ranges::less{}(t, t)); + assert(!ranges::less{}(u, u)); + assert(ranges::less{}(t, u) == (o == strong_ordering::less)); + assert(ranges::less{}(u, t) == (o == strong_ordering::greater)); + + assert(!ranges::greater{}(t, t)); + assert(!ranges::greater{}(u, u)); + assert(ranges::greater{}(t, u) == (o == strong_ordering::greater)); + assert(ranges::greater{}(u, t) == (o == strong_ordering::less)); + + assert(ranges::less_equal{}(t, t)); + assert(ranges::less_equal{}(u, u)); + assert(ranges::less_equal{}(t, u) == !(o == strong_ordering::greater)); + assert(ranges::less_equal{}(u, t) == !(o == strong_ordering::less)); + + assert(ranges::greater_equal{}(t, t)); + assert(ranges::greater_equal{}(u, u)); + assert(ranges::greater_equal{}(t, u) == !(o == strong_ordering::less)); + assert(ranges::greater_equal{}(u, t) == !(o == strong_ordering::greater)); +} + +template +constexpr void test_strongly_ordered(T const& t, U const& u) { + assert(t < u); + test_totally_ordered(t, u, strong_ordering::less); + + assert_three_way(t, t, strong_ordering::equal); + assert_three_way(u, u, strong_ordering::equal); + assert_three_way(t, u, strong_ordering::less); + assert_three_way(u, t, strong_ordering::greater); +} + +template +constexpr void test_weakly_ordered(T const& t, U const& u, weak_ordering const o) { + assert_three_way(t, u, o); + + strong_ordering test_as = strong_ordering::equal; + + if (o == weak_ordering::equivalent) { + assert_three_way(u, t, weak_ordering::equivalent); + test_as = strong_ordering::equal; + } else if (o == weak_ordering::less) { + assert_three_way(u, t, weak_ordering::greater); + test_as = strong_ordering::less; + } else { + assert(o == weak_ordering::greater); + assert_three_way(u, t, weak_ordering::less); + test_as = strong_ordering::greater; + } + + test_totally_ordered(t, u, test_as); +} + +template +constexpr void test_partially_ordered(T const& t, U const& u, partial_ordering const o) { + assert_three_way(t, u, o); + + strong_ordering test_as = strong_ordering::equal; + + if (o == partial_ordering::equivalent) { + assert_three_way(u, t, partial_ordering::equivalent); + test_as = strong_ordering::equal; + } else if (o == partial_ordering::less) { + assert_three_way(u, t, partial_ordering::greater); + test_as = strong_ordering::less; + } else if (o == partial_ordering::greater) { + assert_three_way(u, t, partial_ordering::less); + test_as = strong_ordering::greater; + } else { + assert(o == partial_ordering::unordered); + assert_three_way(u, t, partial_ordering::unordered); + return; + } + + test_totally_ordered(t, u, test_as); +} + +void f1() {} +void f2() {} + +struct base {}; +struct derived : base {}; + +enum unscoped : int {}; +enum class scoped {}; + +// TRANSITION, VSO-980378 (use numeric_limits::quiet_NaN) +constexpr auto NaN = __builtin_nan("0"); +constexpr auto NaNf = __builtin_nanf("0"); + +constexpr void ordering_test_cases() { + // Validate types strongly ordered by builtin <=> operators + test_strongly_ordered(false, true); // bool (but not with other integral types) + + test_strongly_ordered(13, 42); // integral types (but not mixed-sign) + test_strongly_ordered(13, 42L); + test_strongly_ordered(13L, 42); + test_strongly_ordered(13U, 42U); + test_strongly_ordered(13U, 42UL); + test_strongly_ordered(13UL, 42U); + test_strongly_ordered(13U, L'x'); +#ifdef __cpp_char8_t + test_strongly_ordered(13U, u8'x'); +#endif // __cpp_char8_t + test_strongly_ordered(13U, u'x'); +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1062618 + test_strongly_ordered(13U, U'x'); +#endif // TRANSITION, VSO-1062618 + + test_strongly_ordered(scoped{13}, scoped{42}); + test_strongly_ordered(unscoped{13}, unscoped{42}); + + int const some_ints[] = {13, 42}; + test_strongly_ordered(&some_ints[0], &some_ints[1]); + std::pair const int_pair{13, 42}; + test_strongly_ordered(&int_pair.first, &int_pair.second); + + derived const some_deriveds[2] = {}; + test_strongly_ordered(&some_deriveds[0], &some_deriveds[1]); +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 + if (!std::is_constant_evaluated()) +#endif // TRANSITION, VSO-938163 + { + test_strongly_ordered(static_cast(&some_deriveds[0]), &some_deriveds[1]); + test_strongly_ordered(&some_deriveds[0], static_cast(&some_deriveds[1])); + } + + if (!std::is_constant_evaluated()) { + test_strongly_ordered(&some_ints[0], static_cast(&some_ints[1])); + test_strongly_ordered(static_cast(&some_ints[0]), &some_ints[1]); + + std::pair const int_long_pair{13, 42L}; + test_strongly_ordered(static_cast(&int_long_pair.first), &int_long_pair.second); + test_strongly_ordered(&int_long_pair.first, static_cast(&int_long_pair.second)); + } + + // Validate types partially ordered by builtin <=> operators + test_partially_ordered(1.414, 3.14, partial_ordering::less); + test_partially_ordered(1.414f, 3.14, partial_ordering::less); + test_partially_ordered(1.414, 3.14f, partial_ordering::less); + test_partially_ordered(31.625f, 31.625, partial_ordering::equivalent); +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-1062601 + if (!std::is_constant_evaluated()) +#endif // TRANSITION, VSO-1062601 + { + test_partially_ordered(3.14, NaN, partial_ordering::unordered); + test_partially_ordered(3.14f, NaN, partial_ordering::unordered); + test_partially_ordered(3.14, NaNf, partial_ordering::unordered); + } + + // Validate types with no builtin <=> operators that are nonetheless totally_ordered (within a + // limited domain) or equality_comparable +#ifndef __clang__ +#pragma warning(push) +#pragma warning(disable : 4018) // '%s': signed/unsigned mismatch +#pragma warning(disable : 4389) // '%s': signed/unsigned mismatch +#endif // !__clang__ + test_totally_ordered(13, 42u, strong_ordering::less); + test_totally_ordered(13u, 42, strong_ordering::less); +#ifndef __clang__ +#pragma warning(pop) +#endif // !__clang__ + + test_totally_ordered(3.14, 42, strong_ordering::less); + test_totally_ordered(1, 3.14f, strong_ordering::less); + + test_equality_comparable(&f1, &f2, strong_ordering::less); // This means "not equal" + + struct has_members { + int x; + const int y; + + int f() { + return 13; + } + int g() noexcept { + return 42; + } + }; + test_equality_comparable(&has_members::x, &has_members::y, strong_ordering::less); // Ditto "not equal" + test_equality_comparable(&has_members::f, &has_members::g, strong_ordering::less); // Ditto "not equal" + + test_equality_comparable(nullptr, nullptr, strong_ordering::equal); + + // Validate class types + struct partially_ordered_class { + int i; + + constexpr explicit partially_ordered_class(int x) noexcept : i{x} {} + + partially_ordered_class(partially_ordered_class const&) = delete; + partially_ordered_class& operator=(partially_ordered_class const&) = delete; + + constexpr bool operator==(partially_ordered_class const& that) const { + if (i == 42 || that.i == 42) { + return false; + } else { + return i == that.i; + } + } + constexpr partial_ordering operator<=>(partially_ordered_class const& that) const { + if (i == 42 || that.i == 42) { + return partial_ordering::unordered; + } else { + return i <=> that.i; + } + } + }; + struct weakly_ordered_class { + int i; + + constexpr explicit weakly_ordered_class(int x) noexcept : i{x} {} + + weakly_ordered_class(weakly_ordered_class const&) = delete; + weakly_ordered_class& operator=(weakly_ordered_class const&) = delete; + + constexpr bool operator==(weakly_ordered_class const& that) const { + return i / 2 == that.i / 2; + } + constexpr weak_ordering operator<=>(weakly_ordered_class const& that) const { + return i / 2 <=> that.i / 2; + } + }; + struct strongly_ordered_class { + int i; + + constexpr explicit strongly_ordered_class(int x) noexcept : i{x} {} + + strongly_ordered_class(strongly_ordered_class const&) = delete; + strongly_ordered_class& operator=(strongly_ordered_class const&) = delete; + + auto operator<=>(strongly_ordered_class const&) const = default; + }; + + struct equality_comparable_class { + int i; + + struct boolish { + bool b; + constexpr operator bool() const { + return b; + } + }; + + constexpr explicit equality_comparable_class(int x) noexcept : i{x} {} + + equality_comparable_class(equality_comparable_class const&) = delete; + equality_comparable_class& operator=(equality_comparable_class const&) = delete; + + constexpr boolish operator==(equality_comparable_class const& that) const { + return {i == that.i}; + } + constexpr boolish operator!=(equality_comparable_class const& that) const { + return {i != that.i}; + } + }; + + struct totally_ordered_class : equality_comparable_class { + using equality_comparable_class::equality_comparable_class; + + constexpr boolish operator<(totally_ordered_class const& that) const { + return {i < that.i}; + } + constexpr boolish operator>(totally_ordered_class const& that) const { + return {i > that.i}; + } + constexpr boolish operator<=(totally_ordered_class const& that) const { + return {i <= that.i}; + } + constexpr boolish operator>=(totally_ordered_class const& that) const { + return {i >= that.i}; + } + }; + + test_partially_ordered(partially_ordered_class{13}, partially_ordered_class{42}, partial_ordering::unordered); + test_partially_ordered(partially_ordered_class{13}, partially_ordered_class{29}, partial_ordering::less); + test_weakly_ordered(weakly_ordered_class{13}, weakly_ordered_class{42}, weak_ordering::less); + test_weakly_ordered(weakly_ordered_class{13}, weakly_ordered_class{12}, weak_ordering::equivalent); + test_strongly_ordered(strongly_ordered_class{13}, strongly_ordered_class{42}); + test_equality_comparable(equality_comparable_class{13}, equality_comparable_class{13}, strong_ordering::equal); + test_equality_comparable(equality_comparable_class{13}, equality_comparable_class{42}, strong_ordering::less); + test_totally_ordered(totally_ordered_class{13}, totally_ordered_class{42}, strong_ordering::less); +} + +int main() { + STATIC_ASSERT((ordering_test_cases(), true)); + ordering_test_cases(); +} diff --git a/tests/std/tests/P1614R2_spaceship/test.cpp b/tests/std/tests/P1614R2_spaceship/test.cpp index a6cf486ee44..a66a05609e1 100644 --- a/tests/std/tests/P1614R2_spaceship/test.cpp +++ b/tests/std/tests/P1614R2_spaceship/test.cpp @@ -60,14 +60,14 @@ struct SynthOrdered { struct OrderedChar { OrderedChar() = default; - OrderedChar(const char c) : c(c){}; + OrderedChar(const char c) : c(c) {}; OrderedChar& operator=(const char& other) { - this->c = other; + c = other; return *this; } - operator char() { + operator char() const { return c; } @@ -82,13 +82,13 @@ auto operator==(const OrderedChar& left, const OrderedChar& right) { return left.c == right.c; } -struct WeaklyOrderedChar : public OrderedChar {}; -struct WeaklyOrderdByOmissionChar : public OrderedChar {}; -struct PartiallyOrderedChar : public OrderedChar {}; +struct WeaklyOrderedChar : OrderedChar {}; +struct WeaklyOrderdByOmissionChar : OrderedChar {}; +struct PartiallyOrderedChar : OrderedChar {}; namespace std { template <> - struct char_traits : public std::char_traits { + struct char_traits : public char_traits { using char_type = OrderedChar; static int compare(const char_type* first1, const char_type* first2, size_t count) { @@ -107,27 +107,29 @@ namespace std { }; template <> - struct char_traits : public std::char_traits { + struct char_traits : public char_traits { using char_type = WeaklyOrderedChar; - using comparison_category = std::weak_ordering; + using comparison_category = weak_ordering; }; template <> - struct char_traits : public std::char_traits { + struct char_traits : public char_traits { using char_type = WeaklyOrderdByOmissionChar; }; template <> - struct char_traits : public std::char_traits { + struct char_traits : public char_traits { using char_type = PartiallyOrderedChar; - using comparison_category = std::partial_ordering; + using comparison_category = partial_ordering; }; } // namespace std -template +template void spaceship_test(const SmallType& smaller, const EqualType& smaller_equal, const LargeType& larger) { assert(smaller == smaller_equal); + assert(smaller_equal == smaller); assert(smaller != larger); + assert(larger != smaller); assert(smaller < larger); assert(larger > smaller); assert(smaller <= larger); @@ -139,11 +141,6 @@ void spaceship_test(const SmallType& smaller, const EqualType& smaller_equal, co static_assert(std::is_same_v larger), ReturnType>); } -template -void spaceship_test(const TestType& smaller, const TestType& smaller_equal, const TestType& larger) { - return spaceship_test(smaller, smaller_equal, larger); -} - template inline constexpr bool is_pair = false; template @@ -154,9 +151,9 @@ void ordered_containers_test(const Container& smaller, const Container& smaller_ using Elem = typename Container::value_type; if constexpr (is_pair // TRANSITION, std::pair spaceship not yet implemented || std::is_same_v) { - spaceship_test(smaller, smaller_equal, larger); + spaceship_test(smaller, smaller_equal, larger); } else { - spaceship_test(smaller, smaller_equal, larger); + spaceship_test(smaller, smaller_equal, larger); } } @@ -377,22 +374,27 @@ void ordering_test_cases() { const std::string s2{"meow"}; const std::regex all(".*"); const std::regex each("."); - std::smatch m1, m2, m3; + std::smatch m1, m2, m3, m4; std::regex_match(s1, m1, all); std::regex_match(s2, m2, all); std::regex_search(s1, m3, each); + std::regex_search(s2, m4, each); std::ssub_match sm1 = m1[0]; std::ssub_match sm1_equal = m1[0]; std::ssub_match sm2 = m2[0]; std::ssub_match sm3 = m3[0]; + std::ssub_match sm4 = m4[0]; - // TRANSITION: std::char_traits doesn't define comparison_type - spaceship_test(sm1, sm1_equal, sm2); - spaceship_test(sm1, s1, s2); - spaceship_test(sm1, s1.c_str(), s2.c_str()); - spaceship_test(sm3, 'c', 'm'); + // TRANSITION, std::char_traits doesn't define comparison_type + spaceship_test(sm1, sm1_equal, sm2); + spaceship_test(sm1, s1, s2); + spaceship_test(sm1, s1.c_str(), s2.c_str()); + spaceship_test(sm3, 'c', 'm'); + spaceship_test(s1, sm1, sm2); + spaceship_test(s1.c_str(), sm1, sm2); + spaceship_test('c', sm3, sm4); using StronglyOrderedMatch = std::ssub_match; using WeaklyOrderedMatch = std::sub_match::const_iterator>; @@ -400,7 +402,7 @@ void ordering_test_cases() { std::sub_match::const_iterator>; using PartiallyOrderedMatch = std::sub_match::const_iterator>; - // TRANSITION: std::char_traits doesn't define comparison_type + // TRANSITION, std::char_traits doesn't define comparison_type static_assert(std::is_same_v, std::weak_ordering>); static_assert(std::is_same_v, std::weak_ordering>); static_assert(std::is_same_v, std::weak_ordering>); From ac1a54cc4b383ccf3f18bd2311919004cfb8a3af Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Thu, 6 Aug 2020 15:37:00 -0700 Subject: [PATCH 09/64] clang format --- stl/inc/regex | 4 ++-- tests/std/tests/P1614R2_spaceship/test.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index 7ef4e498940..1d4dcf3d68d 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -787,7 +787,7 @@ _NODISCARD bool operator>=(const sub_match<_BidIt>& _Left, const sub_match<_BidI // COMPARE sub_match AND NTBS template -_NODISCARD bool operator==(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>* _Right) { +_NODISCARD bool operator==(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>* _Right) { return _Left._Match_equal(_Right); } @@ -802,7 +802,7 @@ _NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const iter_value_t<_ // In C++20 mode the only required comparison operators should be == and <=>. template _NODISCARD auto operator<=>(const iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { - return static_cast::_Comparison_category>(0 <=> (_Right <=>_Left)); + return static_cast::_Comparison_category>(0 <=> (_Right <=> _Left)); } template diff --git a/tests/std/tests/P1614R2_spaceship/test.cpp b/tests/std/tests/P1614R2_spaceship/test.cpp index a66a05609e1..e589cedafc3 100644 --- a/tests/std/tests/P1614R2_spaceship/test.cpp +++ b/tests/std/tests/P1614R2_spaceship/test.cpp @@ -60,7 +60,7 @@ struct SynthOrdered { struct OrderedChar { OrderedChar() = default; - OrderedChar(const char c) : c(c) {}; + OrderedChar(const char c) : c(c){}; OrderedChar& operator=(const char& other) { c = other; From df0cbc3af7d9a7101ab0276ac4619cae89d08b7d Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Thu, 6 Aug 2020 17:00:58 -0700 Subject: [PATCH 10/64] Fix redefinition of != --- stl/inc/regex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/regex b/stl/inc/regex index 1d4dcf3d68d..7b75336bafc 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1000,7 +1000,7 @@ _NODISCARD bool operator==(const _Iter_value_t<_BidIt>& _Left, const sub_match<_ } template -_NODISCARD bool operator!=(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { +_NODISCARD bool operator!=(const _Iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { return !(_Left == _Right); } From 4065715767db7bbcd921d5561b4b53ef121981bf Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Thu, 6 Aug 2020 20:26:25 -0700 Subject: [PATCH 11/64] EDG doesn't have iter_value_t yet --- stl/inc/regex | 78 +++++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index 7b75336bafc..b78e1df1d6c 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -793,7 +793,7 @@ _NODISCARD bool operator==(const sub_match<_BidIt>& _Left, const _Iter_value_t<_ #if _HAS_CXX20 template -_NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>* _Right) { +_NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>* _Right) { return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } @@ -801,62 +801,62 @@ _NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const iter_value_t<_ // Overload resolution prefers implicit conversions over re-writes. // In C++20 mode the only required comparison operators should be == and <=>. template -_NODISCARD auto operator<=>(const iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { +_NODISCARD auto operator<=>(const _Iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { return static_cast::_Comparison_category>(0 <=> (_Right <=> _Left)); } template -_NODISCARD bool operator==(const iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { +_NODISCARD bool operator==(const _Iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { return _Right._Match_equal(_Left); } template -_NODISCARD bool operator!=(const iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { +_NODISCARD bool operator!=(const _Iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { return !(_Left == _Right); } template -_NODISCARD bool operator<(const iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { +_NODISCARD bool operator<(const _Iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { return (_Left <=> _Right) < 0; } template -_NODISCARD bool operator>(const iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { +_NODISCARD bool operator>(const _Iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { return (_Left <=> _Right) > 0; } template -_NODISCARD bool operator<=(const iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { +_NODISCARD bool operator<=(const _Iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { return (_Left <=> _Right) <= 0; } template -_NODISCARD bool operator>=(const iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { +_NODISCARD bool operator>=(const _Iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { return (_Left <=> _Right) >= 0; } template -_NODISCARD bool operator!=(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>* _Right) { +_NODISCARD bool operator!=(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>* _Right) { return !(_Left == _Right); } template -_NODISCARD bool operator<(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>* _Right) { +_NODISCARD bool operator<(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>* _Right) { return (_Left <=> _Right) < 0; } template -_NODISCARD bool operator>(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>* _Right) { +_NODISCARD bool operator>(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>* _Right) { return (_Left <=> _Right) > 0; } template -_NODISCARD bool operator<=(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>* _Right) { +_NODISCARD bool operator<=(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>* _Right) { return (_Left <=> _Right) <= 0; } template -_NODISCARD bool operator>=(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>* _Right) { +_NODISCARD bool operator>=(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>* _Right) { return (_Left <=> _Right) >= 0; } #endif // TRANSTITION, VSO-900973 @@ -925,7 +925,7 @@ _NODISCARD bool operator==(const sub_match<_BidIt>& _Left, const _Iter_value_t<_ #if _HAS_CXX20 template -_NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>& _Right) { +_NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { return static_cast::_Comparison_category>( _Left._Compare(_STD addressof(_Right), 1) <=> 0); } @@ -934,62 +934,62 @@ _NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const iter_value_t<_ // Overload resolution prefers implicit conversions over re-writes. // In C++20 mode the only required comparison operators should be == and <=>. template -_NODISCARD auto operator<=>(const iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { +_NODISCARD auto operator<=>(const _Iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { return static_cast::_Comparison_category>(0 <=> (_Right <=> _Left)); } template -_NODISCARD bool operator==(const iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { +_NODISCARD bool operator==(const _Iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { return _Right._Match_equal(_STD addressof(_Left), 1); } template -_NODISCARD bool operator!=(const iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { +_NODISCARD bool operator!=(const _Iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { return !(_Left == _Right); } template -_NODISCARD bool operator<(const iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { +_NODISCARD bool operator<(const _Iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { return (_Left <=> _Right) < 0; } template -_NODISCARD bool operator>(const iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { +_NODISCARD bool operator>(const _Iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { return (_Left <=> _Right) > 0; } template -_NODISCARD bool operator<=(const iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { +_NODISCARD bool operator<=(const _Iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { return (_Left <=> _Right) <= 0; } template -_NODISCARD bool operator>=(const iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { +_NODISCARD bool operator>=(const _Iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { return (_Left <=> _Right) >= 0; } template -_NODISCARD bool operator!=(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>& _Right) { +_NODISCARD bool operator!=(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { return !(_Left == _Right); } template -_NODISCARD bool operator<(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>& _Right) { +_NODISCARD bool operator<(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { return (_Left <=> _Right) < 0; } template -_NODISCARD bool operator>(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>& _Right) { +_NODISCARD bool operator>(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { return (_Left <=> _Right) > 0; } template -_NODISCARD bool operator<=(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>& _Right) { +_NODISCARD bool operator<=(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { return (_Left <=> _Right) <= 0; } template -_NODISCARD bool operator>=(const sub_match<_BidIt>& _Left, const iter_value_t<_BidIt>& _Right) { +_NODISCARD bool operator>=(const sub_match<_BidIt>& _Left, const _Iter_value_t<_BidIt>& _Right) { return (_Left <=> _Right) >= 0; } #endif // TRANSITION, VSO-900973 @@ -1060,7 +1060,7 @@ _NODISCARD bool operator==( #if _HAS_CXX20 template _NODISCARD auto operator<=>( - const sub_match<_BidIt>& _Left, const basic_string, _Traits, _Alloc>& _Right) { + const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } @@ -1069,73 +1069,73 @@ _NODISCARD auto operator<=>( // In C++20 mode the only required comparison operators should be == and <=>. template _NODISCARD auto operator<=>( - const basic_string, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { return static_cast::_Comparison_category>(0 <=> (_Right <=> _Left)); } template _NODISCARD bool operator!=( - const sub_match<_BidIt>& _Left, const basic_string, _Traits, _Alloc>& _Right) { + const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { return !(_Left == _Right); } template _NODISCARD bool operator<( - const sub_match<_BidIt>& _Left, const basic_string, _Traits, _Alloc>& _Right) { + const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { return (_Left <=> _Right) < 0; } template _NODISCARD bool operator>( - const sub_match<_BidIt>& _Left, const basic_string, _Traits, _Alloc>& _Right) { + const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { return (_Left <=> _Right) > 0; } template _NODISCARD bool operator<=( - const sub_match<_BidIt>& _Left, const basic_string, _Traits, _Alloc>& _Right) { + const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { return (_Left <=> _Right) <= 0; } template _NODISCARD bool operator>=( - const sub_match<_BidIt>& _Left, const basic_string, _Traits, _Alloc>& _Right) { + const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { return (_Left <=> _Right) >= 0; } template _NODISCARD bool operator==( - const basic_string, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { return _Right._Match_equal(_Left.data(), _Left.size()); } template _NODISCARD bool operator!=( - const basic_string, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { return !(_Left == _Right); } template _NODISCARD bool operator<( - const basic_string, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { return (_Left <=> _Right) < 0; } template _NODISCARD bool operator>( - const basic_string, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { return (_Left <=> _Right) > 0; } template _NODISCARD bool operator<=( - const basic_string, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { return (_Left <=> _Right) <= 0; } template _NODISCARD bool operator>=( - const basic_string, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { return (_Left <=> _Right) >= 0; } #endif // TRANSITION, VSO-900973 From 11f7fb672e94360ea3bfa7e6a8b3afad09cf0e01 Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Mon, 10 Aug 2020 09:24:49 -0700 Subject: [PATCH 12/64] Resolve @CaseyCarter's review suggestions Co-authored-by: Casey Carter --- tests/std/tests/P1614R2_spaceship/test.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tests/std/tests/P1614R2_spaceship/test.cpp b/tests/std/tests/P1614R2_spaceship/test.cpp index e589cedafc3..c960ca95103 100644 --- a/tests/std/tests/P1614R2_spaceship/test.cpp +++ b/tests/std/tests/P1614R2_spaceship/test.cpp @@ -60,13 +60,15 @@ struct SynthOrdered { struct OrderedChar { OrderedChar() = default; - OrderedChar(const char c) : c(c){}; + OrderedChar(const char c) : c(c) {} OrderedChar& operator=(const char& other) { c = other; return *this; } + auto operator<=>(const OrderedChar&) const = default; + operator char() const { return c; } @@ -74,14 +76,6 @@ struct OrderedChar { char c; }; -auto operator<=>(const OrderedChar& left, const OrderedChar& right) { - return left.c <=> right.c; -} - -auto operator==(const OrderedChar& left, const OrderedChar& right) { - return left.c == right.c; -} - struct WeaklyOrderedChar : OrderedChar {}; struct WeaklyOrderdByOmissionChar : OrderedChar {}; struct PartiallyOrderedChar : OrderedChar {}; From 8033dc113a07544d78ade71ea56b05c60ad8c1da Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Tue, 18 Aug 2020 10:39:11 -0700 Subject: [PATCH 13/64] Resolve @StephanTLavavej's PR comments --- stl/inc/regex | 86 +++++++++++++++------- tests/std/tests/P1614R2_spaceship/test.cpp | 32 +++++--- 2 files changed, 80 insertions(+), 38 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index b78e1df1d6c..d9cbdc7df62 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -730,8 +730,8 @@ _NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const sub_match<_Bid return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } -#if 1 // TRANSITION, VSO-900973 -// Overload resolution prefers implicit conversions over re-writes. +#ifdef _MSC_VER // TRANSITION, VSO-900973 +// The compiler incorrectly performs overload resolution by preferring implicit conversions over rewrites. // In C++20 mode the only required comparison operators should be == and <=>. template _NODISCARD bool operator!=(const sub_match<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { @@ -797,8 +797,8 @@ _NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const _Iter_value_t< return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } -#if 1 // TRANSITION, VSO-900973 -// Overload resolution prefers implicit conversions over re-writes. +#ifdef _MSC_VER // TRANSITION, VSO-900973 +// The compiler incorrectly performs overload resolution by preferring implicit conversions over rewrites. // In C++20 mode the only required comparison operators should be == and <=>. template _NODISCARD auto operator<=>(const _Iter_value_t<_BidIt>* _Left, const sub_match<_BidIt>& _Right) { @@ -930,8 +930,8 @@ _NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const _Iter_value_t< _Left._Compare(_STD addressof(_Right), 1) <=> 0); } -#if 1 // TRANSITION, VSO-900973 -// Overload resolution prefers implicit conversions over re-writes. +#ifdef _MSC_VER // TRANSITION, VSO-900973 +// The compiler incorrectly performs overload resolution by preferring implicit conversions over rewrites. // In C++20 mode the only required comparison operators should be == and <=>. template _NODISCARD auto operator<=>(const _Iter_value_t<_BidIt>& _Left, const sub_match<_BidIt>& _Right) { @@ -1064,8 +1064,8 @@ _NODISCARD auto operator<=>( return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } -#if 1 // TRANSITION, VSO-900973 -// Overload resolution prefers implicit conversions over re-writes. +#ifdef _MSC_VER // TRANSITION, VSO-900973 +// The compiler incorrectly performs overload resolution by preferring implicit conversions over rewrites. // In C++20 mode the only required comparison operators should be == and <=>. template _NODISCARD auto operator<=>( @@ -1073,6 +1073,42 @@ _NODISCARD auto operator<=>( return static_cast::_Comparison_category>(0 <=> (_Right <=> _Left)); } +template +_NODISCARD bool operator==( + const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + return _Right._Match_equal(_Left.data(), _Left.size()); +} + +template +_NODISCARD bool operator!=( + const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + return !(_Left == _Right); +} + +template +_NODISCARD bool operator<( + const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) < 0; +} + +template +_NODISCARD bool operator>( + const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) > 0; +} + +template +_NODISCARD bool operator<=( + const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) <= 0; +} + +template +_NODISCARD bool operator>=( + const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + return (_Left <=> _Right) >= 0; +} + template _NODISCARD bool operator!=( const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { @@ -1102,7 +1138,8 @@ _NODISCARD bool operator>=( const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { return (_Left <=> _Right) >= 0; } - +#endif // TRANSITION, VSO-900973 +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template _NODISCARD bool operator==( const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { @@ -1118,28 +1155,27 @@ _NODISCARD bool operator!=( template _NODISCARD bool operator<( const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { - return (_Left <=> _Right) < 0; + return _Right._Greater(_Left.data(), _Left.size()); } template _NODISCARD bool operator>( const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { - return (_Left <=> _Right) > 0; + return _Right < _Left; } template _NODISCARD bool operator<=( const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { - return (_Left <=> _Right) <= 0; + return !(_Right < _Left); } template _NODISCARD bool operator>=( const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { - return (_Left <=> _Right) >= 0; + return !(_Left < _Right); } -#endif // TRANSITION, VSO-900973 -#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv + template _NODISCARD bool operator!=( const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { @@ -1170,41 +1206,37 @@ _NODISCARD bool operator>=( return !(_Left < _Right); } -template -_NODISCARD bool operator==( - const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { - return _Right._Match_equal(_Left.data(), _Left.size()); -} template _NODISCARD bool operator!=( - const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { return !(_Left == _Right); } template _NODISCARD bool operator<( - const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { - return _Right._Greater(_Left.data(), _Left.size()); + const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { + return _Left._Less(_Right.data(), _Right.size()); } template _NODISCARD bool operator>( - const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { return _Right < _Left; } template _NODISCARD bool operator<=( - const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { return !(_Right < _Left); } template _NODISCARD bool operator>=( - const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Left, const sub_match<_BidIt>& _Right) { + const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { return !(_Left < _Right); } + #endif // !_HAS_CXX20 // INSERT sub_match IN STREAM @@ -1418,7 +1450,7 @@ template _NODISCARD bool operator!=(const match_results<_BidIt, _Alloc>& _Left, const match_results<_BidIt, _Alloc>& _Right) { return !(_Left == _Right); } -#endif +#endif // !_HAS_CXX20 // NFA PROPERTIES const unsigned int _BRE_MAX_GRP = 9U; diff --git a/tests/std/tests/P1614R2_spaceship/test.cpp b/tests/std/tests/P1614R2_spaceship/test.cpp index c960ca95103..7c76cee6b79 100644 --- a/tests/std/tests/P1614R2_spaceship/test.cpp +++ b/tests/std/tests/P1614R2_spaceship/test.cpp @@ -60,7 +60,7 @@ struct SynthOrdered { struct OrderedChar { OrderedChar() = default; - OrderedChar(const char c) : c(c) {} + OrderedChar(const char other) : c(other) {} OrderedChar& operator=(const char& other) { c = other; @@ -77,12 +77,12 @@ struct OrderedChar { }; struct WeaklyOrderedChar : OrderedChar {}; -struct WeaklyOrderdByOmissionChar : OrderedChar {}; +struct WeaklyOrderedByOmissionChar : OrderedChar {}; struct PartiallyOrderedChar : OrderedChar {}; namespace std { template <> - struct char_traits : public char_traits { + struct char_traits : char_traits { using char_type = OrderedChar; static int compare(const char_type* first1, const char_type* first2, size_t count) { @@ -101,18 +101,21 @@ namespace std { }; template <> - struct char_traits : public char_traits { + struct char_traits : char_traits { using char_type = WeaklyOrderedChar; using comparison_category = weak_ordering; }; template <> - struct char_traits : public char_traits { - using char_type = WeaklyOrderdByOmissionChar; + struct char_traits : char_traits { + using char_type = WeaklyOrderedByOmissionChar; + + private: + using comparison_category = strong_ordering; }; template <> - struct char_traits : public char_traits { + struct char_traits : char_traits { using char_type = PartiallyOrderedChar; using comparison_category = partial_ordering; }; @@ -125,9 +128,13 @@ void spaceship_test(const SmallType& smaller, const EqualType& smaller_equal, co assert(smaller != larger); assert(larger != smaller); assert(smaller < larger); + assert(!(larger < smaller)); assert(larger > smaller); + assert(!(smaller > larger)); assert(smaller <= larger); + assert(!(larger <= smaller)); assert(larger >= smaller); + assert(!(smaller >= larger)); assert((smaller <=> larger) < 0); assert((larger <=> smaller) > 0); assert((smaller <=> smaller_equal) == 0); @@ -368,7 +375,10 @@ void ordering_test_cases() { const std::string s2{"meow"}; const std::regex all(".*"); const std::regex each("."); - std::smatch m1, m2, m3, m4; + std::smatch m1; + std::smatch m2; + std::smatch m3; + std::smatch m4; std::regex_match(s1, m1, all); std::regex_match(s2, m2, all); @@ -381,7 +391,7 @@ void ordering_test_cases() { std::ssub_match sm3 = m3[0]; std::ssub_match sm4 = m4[0]; - // TRANSITION, std::char_traits doesn't define comparison_type + // TRANSITION, std::char_traits doesn't define comparison_category spaceship_test(sm1, sm1_equal, sm2); spaceship_test(sm1, s1, s2); spaceship_test(sm1, s1.c_str(), s2.c_str()); @@ -393,10 +403,10 @@ void ordering_test_cases() { using StronglyOrderedMatch = std::ssub_match; using WeaklyOrderedMatch = std::sub_match::const_iterator>; using WeaklyOrderdByOmissionMatch = - std::sub_match::const_iterator>; + std::sub_match::const_iterator>; using PartiallyOrderedMatch = std::sub_match::const_iterator>; - // TRANSITION, std::char_traits doesn't define comparison_type + // TRANSITION, std::char_traits doesn't define comparison_category static_assert(std::is_same_v, std::weak_ordering>); static_assert(std::is_same_v, std::weak_ordering>); static_assert(std::is_same_v, std::weak_ordering>); From 66bf777d0cf869cb1138a261db066eb588a584d2 Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Tue, 18 Aug 2020 14:24:49 -0700 Subject: [PATCH 14/64] Don't use _MSC_VER to check for C1XX --- stl/inc/regex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index d9cbdc7df62..dff865f0f9f 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -730,7 +730,7 @@ _NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const sub_match<_Bid return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } -#ifdef _MSC_VER // TRANSITION, VSO-900973 +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-900973 // The compiler incorrectly performs overload resolution by preferring implicit conversions over rewrites. // In C++20 mode the only required comparison operators should be == and <=>. template @@ -797,7 +797,7 @@ _NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const _Iter_value_t< return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } -#ifdef _MSC_VER // TRANSITION, VSO-900973 +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-900973 // The compiler incorrectly performs overload resolution by preferring implicit conversions over rewrites. // In C++20 mode the only required comparison operators should be == and <=>. template @@ -930,7 +930,7 @@ _NODISCARD auto operator<=>(const sub_match<_BidIt>& _Left, const _Iter_value_t< _Left._Compare(_STD addressof(_Right), 1) <=> 0); } -#ifdef _MSC_VER // TRANSITION, VSO-900973 +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-900973 // The compiler incorrectly performs overload resolution by preferring implicit conversions over rewrites. // In C++20 mode the only required comparison operators should be == and <=>. template @@ -1064,7 +1064,7 @@ _NODISCARD auto operator<=>( return static_cast::_Comparison_category>(_Left.compare(_Right) <=> 0); } -#ifdef _MSC_VER // TRANSITION, VSO-900973 +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-900973 // The compiler incorrectly performs overload resolution by preferring implicit conversions over rewrites. // In C++20 mode the only required comparison operators should be == and <=>. template From 665e8ad9f583062530adcf359104f47eaa5052cf Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Wed, 19 Aug 2020 11:39:41 -0700 Subject: [PATCH 15/64] Fix copy-pasta error --- stl/inc/regex | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index dff865f0f9f..048e2e8b351 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1205,38 +1205,6 @@ _NODISCARD bool operator>=( const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { return !(_Left < _Right); } - - -template -_NODISCARD bool operator!=( - const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { - return !(_Left == _Right); -} - -template -_NODISCARD bool operator<( - const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { - return _Left._Less(_Right.data(), _Right.size()); -} - -template -_NODISCARD bool operator>( - const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { - return _Right < _Left; -} - -template -_NODISCARD bool operator<=( - const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { - return !(_Right < _Left); -} - -template -_NODISCARD bool operator>=( - const sub_match<_BidIt>& _Left, const basic_string<_Iter_value_t<_BidIt>, _Traits, _Alloc>& _Right) { - return !(_Left < _Right); -} - #endif // !_HAS_CXX20 // INSERT sub_match IN STREAM From 0403d0c7de022483e3eb1fff72341b4206f0777a Mon Sep 17 00:00:00 2001 From: Ahana Mukhopadhyay Date: Tue, 21 Jul 2020 11:29:47 -0400 Subject: [PATCH 16/64] initial diagnostics product code --- stl/inc/system_error | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/stl/inc/system_error b/stl/inc/system_error index 4121c5766d9..6b19f22fa7d 100644 --- a/stl/inc/system_error +++ b/stl/inc/system_error @@ -16,6 +16,7 @@ #include #ifndef _M_CEE_PURE #include +#include #endif #pragma pack(push, _CRT_PACKING) @@ -90,14 +91,22 @@ public: return _Addr == _Right._Addr; } +#if !_HAS_CXX20 _NODISCARD bool operator!=(const error_category& _Right) const noexcept { return !(*this == _Right); } +#endif // !_HAS_CXX20 +#ifdef __cpp_lib_concepts _NODISCARD bool operator<(const error_category& _Right) const noexcept { return _Addr < _Right._Addr; } + _NODISCARD strong_ordering operator<=>(const error_category& _Right) const noexcept { + return compare_three_way()(this, &_Right); + } +#endif // __cpp_lib_concepts + error_category(const error_category&) = delete; error_category& operator=(const error_category&) = delete; @@ -173,6 +182,7 @@ public: return _System_error_equal(_Left, _Right); } +#if !_HAS_CXX20 _NODISCARD friend bool operator==(const error_condition& _Left, const error_code& _Right) noexcept { return _System_error_equal(_Right, _Left); } @@ -193,6 +203,16 @@ public: return _Left.category() < _Right.category() || (_Left.category() == _Right.category() && _Left.value() < _Right.value()); } +#endif // !_HAS_CXX20 + +#ifdef __cpp_lib_concepts + _NODISCARD friend strong_ordering operator<=>(const error_code& _Left, const error_code& _Right) noexcept { + if (auto _Result = _Left.category() <=> _Right.category(); _Result != 0) { + return _Result; + } + return _Left.value() <=> _Right.value(); + } +#endif // __cpp_lib_concepts #endif // _STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS private: @@ -249,6 +269,7 @@ public: return _Left.category() == _Right.category() && _Left.value() == _Right.value(); } +#if !_HAS_CXX20 _NODISCARD friend bool operator!=(const error_condition& _Left, const error_condition& _Right) noexcept { return !(_Left == _Right); } @@ -257,14 +278,27 @@ public: return _Left.category() < _Right.category() || (_Left.category() == _Right.category() && _Left.value() < _Right.value()); } +#endif // !_HAS_CXX20 + +#ifdef __cpp_lib_concepts + _NODISCARD friend strong_ordering operator<=>( + const error_condition& _Left, const error_condition& _Right) noexcept { + if (auto _Result = _Left.category() <=> _Right.category(); _Result != 0) { + return _Result; + } + return _Left.value() <=> _Right.value(); + } +#endif // __cpp_lib_concepts // We grant friendship to the operators from error_code here to allow is_error_code_enum_v but not // is_error_condition_enum_v enums to be compared directly with error_condition; for example: // io_errc::stream == make_error_condition(errc::out_of_memory) friend bool operator==(const error_code& _Left, const error_condition& _Right) noexcept; friend bool operator==(const error_condition& _Left, const error_code& _Right) noexcept; +#if !_HAS_CXX20 friend bool operator!=(const error_code& _Left, const error_condition& _Right) noexcept; friend bool operator!=(const error_condition& _Left, const error_code& _Right) noexcept; +#endif // !_HAS_CXX20 #endif // _STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS private: From 92149a4f92c22ef431c7282baf597af1a0c8e953 Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Mon, 10 Aug 2020 09:19:45 -0700 Subject: [PATCH 17/64] Add diagnostics tests --- stl/inc/system_error | 65 +++++++++++----------- tests/std/tests/P1614R2_spaceship/test.cpp | 51 +++++++++++++++++ 2 files changed, 84 insertions(+), 32 deletions(-) diff --git a/stl/inc/system_error b/stl/inc/system_error index 6b19f22fa7d..451d6230f09 100644 --- a/stl/inc/system_error +++ b/stl/inc/system_error @@ -97,15 +97,16 @@ public: } #endif // !_HAS_CXX20 +// TRANSITION, GH-489 #ifdef __cpp_lib_concepts - _NODISCARD bool operator<(const error_category& _Right) const noexcept { - return _Addr < _Right._Addr; - } - _NODISCARD strong_ordering operator<=>(const error_category& _Right) const noexcept { return compare_three_way()(this, &_Right); } -#endif // __cpp_lib_concepts +#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv + _NODISCARD bool operator<(const error_category& _Right) const noexcept { + return _Addr < _Right._Addr; + } +#endif // !defined(__cpp_lib_concepts) error_category(const error_category&) = delete; error_category& operator=(const error_category&) = delete; @@ -182,6 +183,20 @@ public: return _System_error_equal(_Left, _Right); } +// TRANSITION, GH-489 +#ifdef __cpp_lib_concepts + _NODISCARD friend strong_ordering operator<=>(const error_code& _Left, const error_code& _Right) noexcept { + if (auto _Result = _Left.category() <=> _Right.category(); _Result != 0) { + return _Result; + } + return _Left.value() <=> _Right.value(); + } +#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv + _NODISCARD friend bool operator<(const error_code& _Left, const error_code& _Right) noexcept { + return _Left.category() < _Right.category() + || (_Left.category() == _Right.category() && _Left.value() < _Right.value()); + } +#endif // !defined(__cpp_lib_concepts) #if !_HAS_CXX20 _NODISCARD friend bool operator==(const error_condition& _Left, const error_code& _Right) noexcept { return _System_error_equal(_Right, _Left); @@ -198,21 +213,7 @@ public: _NODISCARD friend bool operator!=(const error_condition& _Left, const error_code& _Right) noexcept { return !_System_error_equal(_Right, _Left); } - - _NODISCARD friend bool operator<(const error_code& _Left, const error_code& _Right) noexcept { - return _Left.category() < _Right.category() - || (_Left.category() == _Right.category() && _Left.value() < _Right.value()); - } #endif // !_HAS_CXX20 - -#ifdef __cpp_lib_concepts - _NODISCARD friend strong_ordering operator<=>(const error_code& _Left, const error_code& _Right) noexcept { - if (auto _Result = _Left.category() <=> _Right.category(); _Result != 0) { - return _Result; - } - return _Left.value() <=> _Right.value(); - } -#endif // __cpp_lib_concepts #endif // _STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS private: @@ -269,17 +270,7 @@ public: return _Left.category() == _Right.category() && _Left.value() == _Right.value(); } -#if !_HAS_CXX20 - _NODISCARD friend bool operator!=(const error_condition& _Left, const error_condition& _Right) noexcept { - return !(_Left == _Right); - } - - _NODISCARD friend bool operator<(const error_condition& _Left, const error_condition& _Right) noexcept { - return _Left.category() < _Right.category() - || (_Left.category() == _Right.category() && _Left.value() < _Right.value()); - } -#endif // !_HAS_CXX20 - +// TRANSITION, GH-489 #ifdef __cpp_lib_concepts _NODISCARD friend strong_ordering operator<=>( const error_condition& _Left, const error_condition& _Right) noexcept { @@ -288,14 +279,24 @@ public: } return _Left.value() <=> _Right.value(); } -#endif // __cpp_lib_concepts +#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv + _NODISCARD friend bool operator<(const error_condition& _Left, const error_condition& _Right) noexcept { + return _Left.category() < _Right.category() + || (_Left.category() == _Right.category() && _Left.value() < _Right.value()); + } +#endif // !defined(__cpp_lib_concepts) +#if !_HAS_CXX20 + _NODISCARD friend bool operator!=(const error_condition& _Left, const error_condition& _Right) noexcept { + return !(_Left == _Right); + } +#endif // !_HAS_CXX20 // We grant friendship to the operators from error_code here to allow is_error_code_enum_v but not // is_error_condition_enum_v enums to be compared directly with error_condition; for example: // io_errc::stream == make_error_condition(errc::out_of_memory) friend bool operator==(const error_code& _Left, const error_condition& _Right) noexcept; - friend bool operator==(const error_condition& _Left, const error_code& _Right) noexcept; #if !_HAS_CXX20 + friend bool operator==(const error_condition& _Left, const error_code& _Right) noexcept; friend bool operator!=(const error_code& _Left, const error_condition& _Right) noexcept; friend bool operator!=(const error_condition& _Left, const error_code& _Right) noexcept; #endif // !_HAS_CXX20 diff --git a/tests/std/tests/P1614R2_spaceship/test.cpp b/tests/std/tests/P1614R2_spaceship/test.cpp index 7c76cee6b79..039cd4e3b17 100644 --- a/tests/std/tests/P1614R2_spaceship/test.cpp +++ b/tests/std/tests/P1614R2_spaceship/test.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -121,6 +122,12 @@ namespace std { }; } // namespace std +struct dummy_diagnostic : std::error_category +{ + const char* name() const noexcept { return "dummy"; } + std::string message(int) const { return ""; } +}; + template void spaceship_test(const SmallType& smaller, const EqualType& smaller_equal, const LargeType& larger) { assert(smaller == smaller_equal); @@ -165,6 +172,20 @@ void unordered_containers_test( assert(something != different); } +template +void test_diagnostics_type() +{ + dummy_diagnostic* c_mem = new dummy_diagnostic[2]; + + ErrorType e_smaller(0, c_mem[0]); + ErrorType e_equal(0, c_mem[0]); + ErrorType e_larger(1, c_mem[1]); + + spaceship_test(e_smaller, e_equal, e_larger); + + delete[] c_mem; +} + void ordering_test_cases() { { // constexpr array constexpr std::array a0{{2, 8, 9, 1, 9}}; @@ -412,6 +433,36 @@ void ordering_test_cases() { static_assert(std::is_same_v, std::weak_ordering>); static_assert(std::is_same_v, std::partial_ordering>); } + { // Diagnostics Library + test_diagnostics_type(); + test_diagnostics_type(); + + dummy_diagnostic* c_mem = new dummy_diagnostic[2]; + { + std::error_code e1(0, c_mem[0]); + std::error_condition e2(0, c_mem[0]); + + assert(e1 == e2); + assert(e2 == e1); + } + { + std::error_code e1(0, c_mem[0]); + std::error_condition e2(0, c_mem[1]); + + assert(e1 != e2); + assert(e2 != e1); + } + { + std::error_code e1(1, c_mem[0]); + std::error_condition e2(0, c_mem[0]); + + assert(e1 != e2); + assert(e2 != e1); + } + + spaceship_test(c_mem[0], c_mem[0], c_mem[1]); + delete[] c_mem; + } } template From b82c9dc0399e03a08321f89964d08815e7aa35dd Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Mon, 10 Aug 2020 09:40:27 -0700 Subject: [PATCH 18/64] clang-format --- tests/std/tests/P1614R2_spaceship/test.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/std/tests/P1614R2_spaceship/test.cpp b/tests/std/tests/P1614R2_spaceship/test.cpp index 039cd4e3b17..1b16afc7c09 100644 --- a/tests/std/tests/P1614R2_spaceship/test.cpp +++ b/tests/std/tests/P1614R2_spaceship/test.cpp @@ -122,10 +122,13 @@ namespace std { }; } // namespace std -struct dummy_diagnostic : std::error_category -{ - const char* name() const noexcept { return "dummy"; } - std::string message(int) const { return ""; } +struct dummy_diagnostic : std::error_category { + const char* name() const noexcept { + return "dummy"; + } + std::string message(int) const { + return ""; + } }; template @@ -172,9 +175,8 @@ void unordered_containers_test( assert(something != different); } -template -void test_diagnostics_type() -{ +template +void test_diagnostics_type() { dummy_diagnostic* c_mem = new dummy_diagnostic[2]; ErrorType e_smaller(0, c_mem[0]); From df07d1b4275d364fbdd3ddf4507ade531727acee Mon Sep 17 00:00:00 2001 From: Curtis J Bezault Date: Tue, 18 Aug 2020 14:39:32 -0700 Subject: [PATCH 19/64] Apply suggestions from code review Co-authored-by: Stephan T. Lavavej --- stl/inc/system_error | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/system_error b/stl/inc/system_error index 451d6230f09..f8bc71f1460 100644 --- a/stl/inc/system_error +++ b/stl/inc/system_error @@ -17,7 +17,7 @@ #ifndef _M_CEE_PURE #include #include -#endif +#endif // _M_CEE_PURE #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) @@ -100,7 +100,7 @@ public: // TRANSITION, GH-489 #ifdef __cpp_lib_concepts _NODISCARD strong_ordering operator<=>(const error_category& _Right) const noexcept { - return compare_three_way()(this, &_Right); + return compare_three_way{}(_Addr, _Right._Addr); } #else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv _NODISCARD bool operator<(const error_category& _Right) const noexcept { @@ -186,7 +186,7 @@ public: // TRANSITION, GH-489 #ifdef __cpp_lib_concepts _NODISCARD friend strong_ordering operator<=>(const error_code& _Left, const error_code& _Right) noexcept { - if (auto _Result = _Left.category() <=> _Right.category(); _Result != 0) { + if (const auto _Result = _Left.category() <=> _Right.category(); _Result != 0) { return _Result; } return _Left.value() <=> _Right.value(); @@ -274,7 +274,7 @@ public: #ifdef __cpp_lib_concepts _NODISCARD friend strong_ordering operator<=>( const error_condition& _Left, const error_condition& _Right) noexcept { - if (auto _Result = _Left.category() <=> _Right.category(); _Result != 0) { + if (const auto _Result = _Left.category() <=> _Right.category(); _Result != 0) { return _Result; } return _Left.value() <=> _Right.value(); From a119d4b90977f85f395f1cc16ba90fa220bdae59 Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Wed, 19 Aug 2020 14:50:15 -0700 Subject: [PATCH 20/64] Fix @StephanTLavavej's comment --- stl/inc/system_error | 48 +++++++++++++++------- tests/std/tests/P1614R2_spaceship/env.lst | 3 ++ tests/std/tests/P1614R2_spaceship/test.cpp | 42 +++++++++++++------ 3 files changed, 66 insertions(+), 27 deletions(-) diff --git a/stl/inc/system_error b/stl/inc/system_error index f8bc71f1460..4d9664d685f 100644 --- a/stl/inc/system_error +++ b/stl/inc/system_error @@ -320,14 +320,43 @@ _NODISCARD inline bool operator==(const error_code& _Left, const error_condition return _Left.category().equivalent(_Left.value(), _Right) || _Right.category().equivalent(_Left, _Right.value()); } -_NODISCARD inline bool operator==(const error_condition& _Left, const error_code& _Right) noexcept { - return _Right.category().equivalent(_Right.value(), _Left) || _Left.category().equivalent(_Right, _Left.value()); -} - _NODISCARD inline bool operator==(const error_condition& _Left, const error_condition& _Right) noexcept { return _Left.category() == _Right.category() && _Left.value() == _Right.value(); } +// TRANSITION, GH-489 +#ifdef __cpp_lib_concepts + _NODISCARD inline strong_ordering operator<=>(const error_code& _Left, const error_code& _Right) noexcept { + if (const auto _Result = _Left.category() <=> _Right.category(); _Result != 0) { + return _Result; + } + return _Left.value() <=> _Right.value(); + } + + _NODISCARD inline strong_ordering operator<=>( + const error_condition& _Left, const error_condition& _Right) noexcept { + if (const auto _Result = _Left.category() <=> _Right.category(); _Result != 0) { + return _Result; + } + return _Left.value() <=> _Right.value(); + } +#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv +_NODISCARD inline bool operator<(const error_code& _Left, const error_code& _Right) noexcept { + return _Left.category() < _Right.category() + || (_Left.category() == _Right.category() && _Left.value() < _Right.value()); +} + +_NODISCARD inline bool operator<(const error_condition& _Left, const error_condition& _Right) noexcept { + return _Left.category() < _Right.category() + || (_Left.category() == _Right.category() && _Left.value() < _Right.value()); +} +#endif // !defined(__cpp_lib_concepts) + +#if !_HAS_CXX20 +_NODISCARD inline bool operator==(const error_condition& _Left, const error_code& _Right) noexcept { + return _Right.category().equivalent(_Right.value(), _Left) || _Left.category().equivalent(_Right, _Left.value()); +} + _NODISCARD inline bool operator!=(const error_code& _Left, const error_code& _Right) noexcept { return !(_Left == _Right); } @@ -343,16 +372,7 @@ _NODISCARD inline bool operator!=(const error_condition& _Left, const error_code _NODISCARD inline bool operator!=(const error_condition& _Left, const error_condition& _Right) noexcept { return !(_Left == _Right); } - -_NODISCARD inline bool operator<(const error_code& _Left, const error_code& _Right) noexcept { - return _Left.category() < _Right.category() - || (_Left.category() == _Right.category() && _Left.value() < _Right.value()); -} - -_NODISCARD inline bool operator<(const error_condition& _Left, const error_condition& _Right) noexcept { - return _Left.category() < _Right.category() - || (_Left.category() == _Right.category() && _Left.value() < _Right.value()); -} +#endif // !_HAS_CXX20 #endif // _STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS // VIRTUALS FOR error_category diff --git a/tests/std/tests/P1614R2_spaceship/env.lst b/tests/std/tests/P1614R2_spaceship/env.lst index f3ccc8613c6..20ea5fe3426 100644 --- a/tests/std/tests/P1614R2_spaceship/env.lst +++ b/tests/std/tests/P1614R2_spaceship/env.lst @@ -2,3 +2,6 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception RUNALL_INCLUDE ..\concepts_matrix.lst +RUNALL_CROSSLIST +PM_CL="/D_STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS=0" +PM_CL="/D_STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS=1" diff --git a/tests/std/tests/P1614R2_spaceship/test.cpp b/tests/std/tests/P1614R2_spaceship/test.cpp index 1b16afc7c09..84160c9ece7 100644 --- a/tests/std/tests/P1614R2_spaceship/test.cpp +++ b/tests/std/tests/P1614R2_spaceship/test.cpp @@ -123,10 +123,10 @@ namespace std { } // namespace std struct dummy_diagnostic : std::error_category { - const char* name() const noexcept { + const char* name() const noexcept override { return "dummy"; } - std::string message(int) const { + std::string message(int) const override { return ""; } }; @@ -176,16 +176,33 @@ void unordered_containers_test( } template -void test_diagnostics_type() { - dummy_diagnostic* c_mem = new dummy_diagnostic[2]; +void diagnostics_test() { + dummy_diagnostic c_mem[2]; + { + ErrorType e_smaller(0, c_mem[0]); + ErrorType e_equal(0, c_mem[0]); + ErrorType e_larger(1, c_mem[1]); - ErrorType e_smaller(0, c_mem[0]); - ErrorType e_equal(0, c_mem[0]); - ErrorType e_larger(1, c_mem[1]); + spaceship_test(e_smaller, e_equal, e_larger); + } + { + ErrorType e_smaller(0, c_mem[0]); + ErrorType e_larger(0, c_mem[1]); - spaceship_test(e_smaller, e_equal, e_larger); + assert(e_smaller < e_larger); + assert(!(e_larger < e_smaller)); + assert((e_smaller <=> e_larger) < 0); + assert((e_larger <=> e_smaller) > 0); + } + { + ErrorType e_smaller(0, c_mem[0]); + ErrorType e_larger(1, c_mem[0]); - delete[] c_mem; + assert(e_smaller < e_larger); + assert(!(e_larger < e_smaller)); + assert((e_smaller <=> e_larger) < 0); + assert((e_larger <=> e_smaller) > 0); + } } void ordering_test_cases() { @@ -436,10 +453,10 @@ void ordering_test_cases() { static_assert(std::is_same_v, std::partial_ordering>); } { // Diagnostics Library - test_diagnostics_type(); - test_diagnostics_type(); + diagnostics_test(); + diagnostics_test(); - dummy_diagnostic* c_mem = new dummy_diagnostic[2]; + dummy_diagnostic c_mem[2]; { std::error_code e1(0, c_mem[0]); std::error_condition e2(0, c_mem[0]); @@ -463,7 +480,6 @@ void ordering_test_cases() { } spaceship_test(c_mem[0], c_mem[0], c_mem[1]); - delete[] c_mem; } } From 844f5bf176cb1295951ace2ce83c95ed22db2f86 Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Wed, 19 Aug 2020 14:54:29 -0700 Subject: [PATCH 21/64] clang-format --- stl/inc/system_error | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/stl/inc/system_error b/stl/inc/system_error index 4d9664d685f..c7d07962d1a 100644 --- a/stl/inc/system_error +++ b/stl/inc/system_error @@ -326,20 +326,19 @@ _NODISCARD inline bool operator==(const error_condition& _Left, const error_cond // TRANSITION, GH-489 #ifdef __cpp_lib_concepts - _NODISCARD inline strong_ordering operator<=>(const error_code& _Left, const error_code& _Right) noexcept { - if (const auto _Result = _Left.category() <=> _Right.category(); _Result != 0) { - return _Result; - } - return _Left.value() <=> _Right.value(); +_NODISCARD inline strong_ordering operator<=>(const error_code& _Left, const error_code& _Right) noexcept { + if (const auto _Result = _Left.category() <=> _Right.category(); _Result != 0) { + return _Result; } + return _Left.value() <=> _Right.value(); +} - _NODISCARD inline strong_ordering operator<=>( - const error_condition& _Left, const error_condition& _Right) noexcept { - if (const auto _Result = _Left.category() <=> _Right.category(); _Result != 0) { - return _Result; - } - return _Left.value() <=> _Right.value(); +_NODISCARD inline strong_ordering operator<=>(const error_condition& _Left, const error_condition& _Right) noexcept { + if (const auto _Result = _Left.category() <=> _Right.category(); _Result != 0) { + return _Result; } + return _Left.value() <=> _Right.value(); +} #else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv _NODISCARD inline bool operator<(const error_code& _Left, const error_code& _Right) noexcept { return _Left.category() < _Right.category() From 469a43b324f99730d47c85ff901938b1b143b1f0 Mon Sep 17 00:00:00 2001 From: Ahana Mukhopadhyay Date: Thu, 23 Jul 2020 16:47:56 -0400 Subject: [PATCH 22/64] initial commit --- stl/inc/utility | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/stl/inc/utility b/stl/inc/utility index 73d0c260f5d..ef831746be0 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -123,6 +123,36 @@ _INLINE_VAR constexpr piecewise_construct_t piecewise_construct{}; template class tuple; +#ifdef __cpp_lib_concepts +// STRUCT SYNTH_THREE_WAY +struct _Synth_three_way { + // clang-format off + template + _NODISCARD constexpr auto operator()(const _Ty1& _Left, const _Ty2& _Right) const requires requires { + { _Left < _Right } -> _Boolean_testable; + { _Right < _Left } -> _Boolean_testable; + } + // clang-format on + { + if constexpr (three_way_comparable_with<_Ty1, _Ty2>) { + return _Left <=> _Right; + } else { + if (_Left < _Right) { + return weak_ordering::less; + } else if (_Right < _Left) { + return weak_ordering::greater; + } else { + return weak_ordering::equivalent; + } + } + } +}; + +// ALIAS TEMPLATE _Synth_three_way_result +template +using _Synth_three_way_result = decltype(_Synth_three_way{}(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())); +#endif // __cpp_lib_concepts + template struct pair { // store a pair of values using first_type = _Ty1; @@ -325,6 +355,21 @@ struct pair { // store a pair of values _Ty1 first; // the first stored value _Ty2 second; // the second stored value + +#ifdef __cpp_lib_concepts + friend constexpr bool operator==(const pair&, const pair&) = default; + friend constexpr bool operator==(const pair& _Left, const pair& _Right) requires( + is_reference_v<_Ty1> || is_reference_v<_Ty2>) { + return _Left.first == _Right.first && _Left.second == _Right.second; + } + friend constexpr common_comparison_category_t<_Synth_three_way_result<_Ty1>, _Synth_three_way_result<_Ty2>> + operator<=>(const pair& _Left, const pair& _Right) { + if (auto _Result = _Synth_three_way()(_Left.first, _Right.first); _Result != 0) { + return _Result; + } + return _Synth_three_way()(_Left.second, _Right.second); + } +#endif // __cpp_lib_concepts }; #if _HAS_CXX17 @@ -337,6 +382,7 @@ _CONSTEXPR20 void swap(pair<_Ty1, _Ty2>& _Left, pair<_Ty1, _Ty2>& _Right) noexce _Left.swap(_Right); } +#if !_HAS_CXX20 template _NODISCARD constexpr bool operator==(const pair<_Ty1, _Ty2>& _Left, const pair<_Ty1, _Ty2>& _Right) { return _Left.first == _Right.first && _Left.second == _Right.second; @@ -366,6 +412,7 @@ template _NODISCARD constexpr bool operator>=(const pair<_Ty1, _Ty2>& _Left, const pair<_Ty1, _Ty2>& _Right) { return !(_Left < _Right); } +#endif // !_HAS_CXX20 // ALIAS TEMPLATE _Unrefwrap_t template From a00f59d4a4d5c4172cd38dd40d31e8f82e7560df Mon Sep 17 00:00:00 2001 From: Ahana Mukhopadhyay Date: Wed, 5 Aug 2020 14:17:57 -0400 Subject: [PATCH 23/64] tuple and pair --- stl/inc/tuple | 10 ++++++++++ stl/inc/utility | 32 +++++++++++++++++--------------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/stl/inc/tuple b/stl/inc/tuple index 8cbc90d9e4d..360107b8b5b 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -724,6 +724,7 @@ _NODISCARD constexpr bool operator==(const tuple<_Types1...>& _Left, const tuple return _Left._Equals(_Right); } +#if !_HAS_CXX20 template _NODISCARD constexpr bool operator!=(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { return !(_Left == _Right); @@ -749,6 +750,15 @@ template _NODISCARD constexpr bool operator<=(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { return !(_Right < _Left); } +#endif // !_HAS_CXX20 + +#ifdef __cpp_lib_concepts +template +_NODISCARD constexpr common_comparison_category_t<_Synth_three_way_result<_Types1, _Types2>...> operator<=>( + const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { + if (auto _Result =) +} +#endif // __cpp_lib_concepts template ...>, int> = 0> _CONSTEXPR20 void swap(tuple<_Types...>& _Left, tuple<_Types...>& _Right) noexcept(noexcept(_Left.swap(_Right))) { diff --git a/stl/inc/utility b/stl/inc/utility index ef831746be0..36b4da5ff7a 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -355,21 +355,6 @@ struct pair { // store a pair of values _Ty1 first; // the first stored value _Ty2 second; // the second stored value - -#ifdef __cpp_lib_concepts - friend constexpr bool operator==(const pair&, const pair&) = default; - friend constexpr bool operator==(const pair& _Left, const pair& _Right) requires( - is_reference_v<_Ty1> || is_reference_v<_Ty2>) { - return _Left.first == _Right.first && _Left.second == _Right.second; - } - friend constexpr common_comparison_category_t<_Synth_three_way_result<_Ty1>, _Synth_three_way_result<_Ty2>> - operator<=>(const pair& _Left, const pair& _Right) { - if (auto _Result = _Synth_three_way()(_Left.first, _Right.first); _Result != 0) { - return _Result; - } - return _Synth_three_way()(_Left.second, _Right.second); - } -#endif // __cpp_lib_concepts }; #if _HAS_CXX17 @@ -414,6 +399,23 @@ _NODISCARD constexpr bool operator>=(const pair<_Ty1, _Ty2>& _Left, const pair<_ } #endif // !_HAS_CXX20 +#ifdef __cpp_lib_concepts +template +_NODISCARD constexpr bool operator==(const pair<_Ty1, _Ty2>& _Left, const pair<_Ty1, _Ty2>& _Right) requires( + is_reference_v<_Ty1> || is_reference_v<_Ty2>) { + return _Left.first == _Right.first && _Left.second == _Right.second; +} + +template +_NODISCARD constexpr common_comparison_category_t<_Synth_three_way_result<_Ty1>, _Synth_three_way_result<_Ty2>> + operator<=>(const pair<_Ty1, _Ty2>& _Left, const pair<_Ty1, _Ty2>& _Right) { + if (auto _Result = _Synth_three_way()(_Left.first, _Right.first); _Result != 0) { + return _Result; + } + return _Synth_three_way()(_Left.second, _Right.second); +} +#endif // __cpp_lib_concepts + // ALIAS TEMPLATE _Unrefwrap_t template struct _Unrefwrap_helper { // leave unchanged if not a reference_wrapper From 4a9a96b885491386a1490af5584013e8dfd50a5d Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Mon, 10 Aug 2020 15:49:28 -0700 Subject: [PATCH 24/64] Finish pair and tuple --- stl/inc/tuple | 61 ++++++++++++++++++++++++++----- stl/inc/utility | 93 +++++++----------------------------------------- stl/inc/xutility | 27 ++++++++++++++ 3 files changed, 92 insertions(+), 89 deletions(-) diff --git a/stl/inc/tuple b/stl/inc/tuple index 360107b8b5b..a0a35c2685c 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -8,6 +8,9 @@ #define _TUPLE_ #include #if _STL_COMPILER_PREPROCESSOR +#if __cpp_lib_concepts +#include compare +#endif #include #include #include @@ -232,6 +235,12 @@ public: constexpr bool _Less(const tuple&) const noexcept { return false; } + +#ifdef __cpp_lib_concepts + constexpr strong_ordering _Three_way_compare(const tuple&) const noexcept { + return strong_ordering::equal; + } +#endif // __cpp_lib_concepts }; template @@ -673,6 +682,19 @@ public: || (!(_Right._Myfirst._Val < _Myfirst._Val) && _Mybase::_Less(_Right._Get_rest())); } +#ifdef __cpp_lib_concepts + template + constexpr common_comparison_category_t<_Synth_three_way_result<_This, _Other_first>, + decltype(declval>()._Three_way_compare(declval>()))> + _Three_way_compare(const tuple<_Other_first, _Other_rest...>& _Right) const { + if (auto _Result = _Synth_three_way()(_Myfirst._Val, _Right._Myfirst._Val); _Result != 0) + { + return _Result; + } + return _Mybase::_Three_way_compare(_Right._Get_rest()); + } +#endif // __cpp_lib_concepts + template friend constexpr tuple_element_t<_Index, tuple<_Types...>>& get(tuple<_Types...>& _Tuple) noexcept; @@ -724,11 +746,40 @@ _NODISCARD constexpr bool operator==(const tuple<_Types1...>& _Left, const tuple return _Left._Equals(_Right); } +#ifdef __cpp_lib_concepts +template +_NODISCARD constexpr auto operator<=>( + const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { + static_assert(sizeof...(_Types1) == sizeof...(_Types2), "cannot compare tuples of different sizes"); + return _Left._Three_way_compare(_Right); +} + +template +_NODISCARD constexpr bool operator<(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { + return (_Left <=> _Right) < 0; +} + +template +_NODISCARD constexpr bool operator>=(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { + return (_Left <=> _Right) >= 0; +} + +template +_NODISCARD constexpr bool operator>(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { + return (_Left <=> Right) > 0; +} + +template +_NODISCARD constexpr bool operator<=(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { + return (_Left <=> _Right) <= 0; +} +#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv #if !_HAS_CXX20 template _NODISCARD constexpr bool operator!=(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { return !(_Left == _Right); } +#endif // !_HAS_CXX20 template _NODISCARD constexpr bool operator<(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { @@ -750,15 +801,7 @@ template _NODISCARD constexpr bool operator<=(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { return !(_Right < _Left); } -#endif // !_HAS_CXX20 - -#ifdef __cpp_lib_concepts -template -_NODISCARD constexpr common_comparison_category_t<_Synth_three_way_result<_Types1, _Types2>...> operator<=>( - const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { - if (auto _Result =) -} -#endif // __cpp_lib_concepts +#endif // !defined(__cpp_lib_concepts) template ...>, int> = 0> _CONSTEXPR20 void swap(tuple<_Types...>& _Left, tuple<_Types...>& _Right) noexcept(noexcept(_Left.swap(_Right))) { diff --git a/stl/inc/utility b/stl/inc/utility index 36b4da5ff7a..ec613d04a40 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -123,36 +123,6 @@ _INLINE_VAR constexpr piecewise_construct_t piecewise_construct{}; template class tuple; -#ifdef __cpp_lib_concepts -// STRUCT SYNTH_THREE_WAY -struct _Synth_three_way { - // clang-format off - template - _NODISCARD constexpr auto operator()(const _Ty1& _Left, const _Ty2& _Right) const requires requires { - { _Left < _Right } -> _Boolean_testable; - { _Right < _Left } -> _Boolean_testable; - } - // clang-format on - { - if constexpr (three_way_comparable_with<_Ty1, _Ty2>) { - return _Left <=> _Right; - } else { - if (_Left < _Right) { - return weak_ordering::less; - } else if (_Right < _Left) { - return weak_ordering::greater; - } else { - return weak_ordering::equivalent; - } - } - } -}; - -// ALIAS TEMPLATE _Synth_three_way_result -template -using _Synth_three_way_result = decltype(_Synth_three_way{}(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())); -#endif // __cpp_lib_concepts - template struct pair { // store a pair of values using first_type = _Ty1; @@ -367,16 +337,27 @@ _CONSTEXPR20 void swap(pair<_Ty1, _Ty2>& _Left, pair<_Ty1, _Ty2>& _Right) noexce _Left.swap(_Right); } -#if !_HAS_CXX20 template _NODISCARD constexpr bool operator==(const pair<_Ty1, _Ty2>& _Left, const pair<_Ty1, _Ty2>& _Right) { return _Left.first == _Right.first && _Left.second == _Right.second; } +#ifdef __cpp_lib_concepts +template +_NODISCARD constexpr common_comparison_category_t<_Synth_three_way_result<_Ty1>, _Synth_three_way_result<_Ty2>> + operator<=>(const pair<_Ty1, _Ty2>& _Left, const pair<_Ty1, _Ty2>& _Right) { + if (auto _Result = _Synth_three_way()(_Left.first, _Right.first); _Result != 0) { + return _Result; + } + return _Synth_three_way()(_Left.second, _Right.second); +} +#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv +#if !_HAS_CXX20 template _NODISCARD constexpr bool operator!=(const pair<_Ty1, _Ty2>& _Left, const pair<_Ty1, _Ty2>& _Right) { return !(_Left == _Right); } +#endif // !_HAS_CXX20 template _NODISCARD constexpr bool operator<(const pair<_Ty1, _Ty2>& _Left, const pair<_Ty1, _Ty2>& _Right) { @@ -397,24 +378,7 @@ template _NODISCARD constexpr bool operator>=(const pair<_Ty1, _Ty2>& _Left, const pair<_Ty1, _Ty2>& _Right) { return !(_Left < _Right); } -#endif // !_HAS_CXX20 - -#ifdef __cpp_lib_concepts -template -_NODISCARD constexpr bool operator==(const pair<_Ty1, _Ty2>& _Left, const pair<_Ty1, _Ty2>& _Right) requires( - is_reference_v<_Ty1> || is_reference_v<_Ty2>) { - return _Left.first == _Right.first && _Left.second == _Right.second; -} - -template -_NODISCARD constexpr common_comparison_category_t<_Synth_three_way_result<_Ty1>, _Synth_three_way_result<_Ty2>> - operator<=>(const pair<_Ty1, _Ty2>& _Left, const pair<_Ty1, _Ty2>& _Right) { - if (auto _Result = _Synth_three_way()(_Left.first, _Right.first); _Result != 0) { - return _Result; - } - return _Synth_three_way()(_Left.second, _Right.second); -} -#endif // __cpp_lib_concepts +#endif // !defined(__cpp_lib_concepts) // ALIAS TEMPLATE _Unrefwrap_t template @@ -744,37 +708,6 @@ _NODISCARD constexpr bool cmp_greater_equal(const _Ty1 _Left, const _Ty2 _Right) return !_STD cmp_less(_Left, _Right); } -#ifdef __cpp_lib_concepts -// STRUCT _Synth_three_way -struct _Synth_three_way { - // clang-format off - template - _NODISCARD constexpr auto operator()(const _Ty1& _Left, const _Ty2& _Right) const - requires requires { - { _Left < _Right } -> _Boolean_testable; - { _Right < _Left } -> _Boolean_testable; - } - // clang-format on - { - if constexpr (three_way_comparable_with<_Ty1, _Ty2>) { - return _Left <=> _Right; - } else { - if (_Left < _Right) { - return weak_ordering::less; - } else if (_Right < _Left) { - return weak_ordering::greater; - } else { - return weak_ordering::equivalent; - } - } - } -}; - -// ALIAS TEMPLATE _Synth_three_way_result -template -using _Synth_three_way_result = decltype(_Synth_three_way{}(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())); -#endif // __cpp_lib_concepts - // FUNCTION TEMPLATE in_range template _NODISCARD constexpr _Ty _Min_limit() noexcept { // same as (numeric_limits<_Ty>::min)(), less throughput cost diff --git a/stl/inc/xutility b/stl/inc/xutility index f80ed07fa86..259aeb2775b 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -1124,6 +1124,33 @@ using _Iter_value_t = iter_value_t<_Iter>; template using _Iter_diff_t = iter_difference_t<_Iter>; +// STRUCT SYNTH_THREE_WAY +struct _Synth_three_way { + // clang-format off + template + _NODISCARD constexpr auto operator()(const _Ty1& _Left, const _Ty2& _Right) const requires requires { + { _Left < _Right } -> _Boolean_testable; + { _Right < _Left } -> _Boolean_testable; + } + // clang-format on + { + if constexpr (three_way_comparable_with<_Ty1, _Ty2>) { + return _Left <=> _Right; + } else { + if (_Left < _Right) { + return weak_ordering::less; + } else if (_Right < _Left) { + return weak_ordering::greater; + } else { + return weak_ordering::equivalent; + } + } + } +}; + +// ALIAS TEMPLATE _Synth_three_way_result +template +using _Synth_three_way_result = decltype(_Synth_three_way{}(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())); #else // ^^^ __cpp_lib_concepts / !__cpp_lib_concepts vvv // STRUCT TEMPLATE iterator_traits template From e7cf24db927c54c941655c2e122b39d6e74b72d9 Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Mon, 10 Aug 2020 16:11:24 -0700 Subject: [PATCH 25/64] Some more tuple cleanup --- stl/inc/tuple | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/stl/inc/tuple b/stl/inc/tuple index a0a35c2685c..4d13651cc4a 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -232,15 +232,15 @@ public: return true; } - constexpr bool _Less(const tuple&) const noexcept { - return false; - } - #ifdef __cpp_lib_concepts constexpr strong_ordering _Three_way_compare(const tuple&) const noexcept { return strong_ordering::equal; } -#endif // __cpp_lib_concepts +#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv + constexpr bool _Less(const tuple&) const noexcept { + return false; + } +#endif }; template @@ -676,12 +676,6 @@ public: return _Myfirst._Val == _Right._Myfirst._Val && _Mybase::_Equals(_Right._Get_rest()); } - template - constexpr bool _Less(const tuple<_Other...>& _Right) const { - return _Myfirst._Val < _Right._Myfirst._Val - || (!(_Right._Myfirst._Val < _Myfirst._Val) && _Mybase::_Less(_Right._Get_rest())); - } - #ifdef __cpp_lib_concepts template constexpr common_comparison_category_t<_Synth_three_way_result<_This, _Other_first>, @@ -693,7 +687,13 @@ public: } return _Mybase::_Three_way_compare(_Right._Get_rest()); } -#endif // __cpp_lib_concepts +#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv + template + constexpr bool _Less(const tuple<_Other...>& _Right) const { + return _Myfirst._Val < _Right._Myfirst._Val + || (!(_Right._Myfirst._Val < _Myfirst._Val) && _Mybase::_Less(_Right._Get_rest())); + } +#endif template friend constexpr tuple_element_t<_Index, tuple<_Types...>>& get(tuple<_Types...>& _Tuple) noexcept; @@ -754,6 +754,14 @@ _NODISCARD constexpr auto operator<=>( return _Left._Three_way_compare(_Right); } +#if 1 // TRANSITION, VSO-900973 +// Overload resolution prefers implicit conversions over re-writes. +// In C++20 mode the only required comparison operators should be == and <=>. +template +_NODISCARD constexpr bool operator!=(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { + return !(_Left == _Right); +} + template _NODISCARD constexpr bool operator<(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { return (_Left <=> _Right) < 0; @@ -773,13 +781,12 @@ template _NODISCARD constexpr bool operator<=(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { return (_Left <=> _Right) <= 0; } +#endif // TRANSITION, VSO-900973 #else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv -#if !_HAS_CXX20 template _NODISCARD constexpr bool operator!=(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { return !(_Left == _Right); } -#endif // !_HAS_CXX20 template _NODISCARD constexpr bool operator<(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { From 3bc1990b806ab4bbf6819a0cf7c18d37521fe90c Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Mon, 10 Aug 2020 16:31:29 -0700 Subject: [PATCH 26/64] implement optional --- stl/inc/optional | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/stl/inc/optional b/stl/inc/optional index 968f45f6854..a1f3db58f42 100644 --- a/stl/inc/optional +++ b/stl/inc/optional @@ -11,6 +11,9 @@ #if !_HAS_CXX17 #pragma message("The contents of are available only with C++17 or later.") #else // ^^^ !_HAS_CXX17 / _HAS_CXX17 vvv +#if _HAS_CXX20 +#include +#endif // _HAS_CXX20 #include #include #include @@ -443,11 +446,26 @@ _NODISCARD constexpr bool operator==(const optional<_Ty1>& _Left, const optional return _Left_has_value == _Right.has_value() && (!_Left_has_value || *_Left == *_Right); } +#ifdef __cpp_lib_concepts +template +_NODISCARD constexpr compare_three_way_result_t<_Ty1, _Ty2> +operator<=>(const optional<_Ty1>& _Left, const optional<_Ty2>& _Right) +{ + if (_Left && _Right) + { + return *_Left <=> *_Right; + } + + return bool(_Left) <=> bool(_Right); +} +#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv +#if !_HAS_CXX20 template _NODISCARD constexpr bool operator!=(const optional<_Ty1>& _Left, const optional<_Ty2>& _Right) { const bool _Left_has_value = _Left.has_value(); return _Left_has_value != _Right.has_value() || (_Left_has_value && *_Left != *_Right); } +#endif // !_HAS_CXX20 template _NODISCARD constexpr bool operator<(const optional<_Ty1>& _Left, const optional<_Ty2>& _Right) { @@ -468,12 +486,20 @@ template _NODISCARD constexpr bool operator>=(const optional<_Ty1>& _Left, const optional<_Ty2>& _Right) { return !_Right.has_value() || (_Left.has_value() && *_Left >= *_Right); } +#endif // !defined(__cpp_lib_concepts) // COMPARISONS WITH nullopt [optional.nullops] template _NODISCARD constexpr bool operator==(const optional<_Ty>& _Left, nullopt_t) noexcept { return !_Left.has_value(); } + +#if _HAS_CXX20 +template +_NODISCARD constexpr strong_ordering operator<=>(const optional<_Ty>& _Left, nullopt_t) noexcept { + return bool(_Left) <=> false; +} +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template _NODISCARD constexpr bool operator==(nullopt_t, const optional<_Ty>& _Right) noexcept { return !_Right.has_value(); @@ -523,6 +549,7 @@ template _NODISCARD constexpr bool operator>=(nullopt_t, const optional<_Ty>& _Right) noexcept { return !_Right.has_value(); } +#endif // !_HAS_CXX20 // COMPARISONS WITH T [optional.comp_with_t] template @@ -556,6 +583,19 @@ template = _NODISCARD constexpr bool operator==(const optional<_Ty1>& _Left, const _Ty2& _Right) { return _Left ? *_Left == _Right : false; } + +#ifdef __cpp_lib_concepts +template _Ty2> +constexpr compare_three_way_result_t<_Ty1, _Ty2> operator<=>(const optional<_Ty1>& _Left, const _Ty2& _Right) { + if (_Left) + { + return *_Left <=> _Right; + } + + return strong_ordering::less; +} +#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv +#if !_HAS_CXX20 template = 0> _NODISCARD constexpr bool operator==(const _Ty1& _Left, const optional<_Ty2>& _Right) { return _Right ? _Left == *_Right : false; @@ -569,6 +609,7 @@ template & _Right) { return _Right ? _Left != *_Right : true; } +#endif // !_HAS_CXX20 template = 0> _NODISCARD constexpr bool operator<(const optional<_Ty1>& _Left, const _Ty2& _Right) { @@ -605,6 +646,7 @@ template =(const _Ty1& _Left, const optional<_Ty2>& _Right) { return _Right ? _Left >= *_Right : true; } +#endif // !defined(__cpp_lib_concepts) // FUNCTION TEMPLATE swap [optional.specalg] template && is_swappable_v<_Ty>, int> = 0> From 8d5706450b5c455b5ffff5952c24cdb68e3f634d Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Tue, 11 Aug 2020 15:31:50 -0700 Subject: [PATCH 27/64] Intermediate push --- stl/inc/compare | 28 ++++++++++++++++++++++++ stl/inc/optional | 56 ++++++++++++++++++++++-------------------------- stl/inc/tuple | 4 ++-- stl/inc/xutility | 27 ----------------------- 4 files changed, 56 insertions(+), 59 deletions(-) diff --git a/stl/inc/compare b/stl/inc/compare index 717e7b4b789..f9fd870942b 100644 --- a/stl/inc/compare +++ b/stl/inc/compare @@ -363,6 +363,34 @@ struct compare_three_way { using is_transparent = int; }; // clang-format on + +// STRUCT SYNTH_THREE_WAY +struct _Synth_three_way { + // clang-format off + template + _NODISCARD constexpr auto operator()(const _Ty1& _Left, const _Ty2& _Right) const requires requires { + { _Left < _Right } -> _Boolean_testable; + { _Right < _Left } -> _Boolean_testable; + } + // clang-format on + { + if constexpr (three_way_comparable_with<_Ty1, _Ty2>) { + return _Left <=> _Right; + } else { + if (_Left < _Right) { + return weak_ordering::less; + } else if (_Right < _Left) { + return weak_ordering::greater; + } else { + return weak_ordering::equivalent; + } + } + } +}; + +// ALIAS TEMPLATE _Synth_three_way_result +template +using _Synth_three_way_result = decltype(_Synth_three_way{}(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())); #endif // __cpp_lib_concepts // Other components not yet implemented diff --git a/stl/inc/optional b/stl/inc/optional index a1f3db58f42..a87921aef33 100644 --- a/stl/inc/optional +++ b/stl/inc/optional @@ -446,26 +446,11 @@ _NODISCARD constexpr bool operator==(const optional<_Ty1>& _Left, const optional return _Left_has_value == _Right.has_value() && (!_Left_has_value || *_Left == *_Right); } -#ifdef __cpp_lib_concepts -template -_NODISCARD constexpr compare_three_way_result_t<_Ty1, _Ty2> -operator<=>(const optional<_Ty1>& _Left, const optional<_Ty2>& _Right) -{ - if (_Left && _Right) - { - return *_Left <=> *_Right; - } - - return bool(_Left) <=> bool(_Right); -} -#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv -#if !_HAS_CXX20 template _NODISCARD constexpr bool operator!=(const optional<_Ty1>& _Left, const optional<_Ty2>& _Right) { const bool _Left_has_value = _Left.has_value(); return _Left_has_value != _Right.has_value() || (_Left_has_value && *_Left != *_Right); } -#endif // !_HAS_CXX20 template _NODISCARD constexpr bool operator<(const optional<_Ty1>& _Left, const optional<_Ty2>& _Right) { @@ -486,7 +471,20 @@ template _NODISCARD constexpr bool operator>=(const optional<_Ty1>& _Left, const optional<_Ty2>& _Right) { return !_Right.has_value() || (_Left.has_value() && *_Left >= *_Right); } -#endif // !defined(__cpp_lib_concepts) + +#ifdef __cpp_lib_concepts +template _Ty2> +_NODISCARD constexpr compare_three_way_result_t<_Ty1, _Ty2> +operator<=>(const optional<_Ty1>& _Left, const optional<_Ty2>& _Right) +{ + if (_Left && _Right) + { + return *_Left <=> *_Right; + } + + return bool(_Left) <=> bool(_Right); +} +#endif // __cpp_lib_concepts // COMPARISONS WITH nullopt [optional.nullops] template @@ -584,18 +582,6 @@ _NODISCARD constexpr bool operator==(const optional<_Ty1>& _Left, const _Ty2& _R return _Left ? *_Left == _Right : false; } -#ifdef __cpp_lib_concepts -template _Ty2> -constexpr compare_three_way_result_t<_Ty1, _Ty2> operator<=>(const optional<_Ty1>& _Left, const _Ty2& _Right) { - if (_Left) - { - return *_Left <=> _Right; - } - - return strong_ordering::less; -} -#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv -#if !_HAS_CXX20 template = 0> _NODISCARD constexpr bool operator==(const _Ty1& _Left, const optional<_Ty2>& _Right) { return _Right ? _Left == *_Right : false; @@ -609,7 +595,6 @@ template & _Right) { return _Right ? _Left != *_Right : true; } -#endif // !_HAS_CXX20 template = 0> _NODISCARD constexpr bool operator<(const optional<_Ty1>& _Left, const _Ty2& _Right) { @@ -646,7 +631,18 @@ template =(const _Ty1& _Left, const optional<_Ty2>& _Right) { return _Right ? _Left >= *_Right : true; } -#endif // !defined(__cpp_lib_concepts) + +#ifdef __cpp_lib_concepts +template _Ty2> +constexpr compare_three_way_result_t<_Ty1, _Ty2> operator<=>(const optional<_Ty1>& _Left, const _Ty2& _Right) { + if (_Left) + { + return *_Left <=> _Right; + } + + return strong_ordering::less; +} +#endif // __cpp_lib_concepts // FUNCTION TEMPLATE swap [optional.specalg] template && is_swappable_v<_Ty>, int> = 0> diff --git a/stl/inc/tuple b/stl/inc/tuple index 4d13651cc4a..a1d007bf4c8 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -9,7 +9,7 @@ #include #if _STL_COMPILER_PREPROCESSOR #if __cpp_lib_concepts -#include compare +#include #endif #include #include @@ -774,7 +774,7 @@ _NODISCARD constexpr bool operator>=(const tuple<_Types1...>& _Left, const tuple template _NODISCARD constexpr bool operator>(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { - return (_Left <=> Right) > 0; + return (_Left <=> _Right) > 0; } template diff --git a/stl/inc/xutility b/stl/inc/xutility index 259aeb2775b..f80ed07fa86 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -1124,33 +1124,6 @@ using _Iter_value_t = iter_value_t<_Iter>; template using _Iter_diff_t = iter_difference_t<_Iter>; -// STRUCT SYNTH_THREE_WAY -struct _Synth_three_way { - // clang-format off - template - _NODISCARD constexpr auto operator()(const _Ty1& _Left, const _Ty2& _Right) const requires requires { - { _Left < _Right } -> _Boolean_testable; - { _Right < _Left } -> _Boolean_testable; - } - // clang-format on - { - if constexpr (three_way_comparable_with<_Ty1, _Ty2>) { - return _Left <=> _Right; - } else { - if (_Left < _Right) { - return weak_ordering::less; - } else if (_Right < _Left) { - return weak_ordering::greater; - } else { - return weak_ordering::equivalent; - } - } - } -}; - -// ALIAS TEMPLATE _Synth_three_way_result -template -using _Synth_three_way_result = decltype(_Synth_three_way{}(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())); #else // ^^^ __cpp_lib_concepts / !__cpp_lib_concepts vvv // STRUCT TEMPLATE iterator_traits template From 47830642cca82dfd50ba33fafcbf113087ce4bcc Mon Sep 17 00:00:00 2001 From: Curtis Jacques Bezault Date: Thu, 13 Aug 2020 12:57:42 -0700 Subject: [PATCH 28/64] clang failure --- stl/inc/tuple | 14 +- tests/std/tests/P1614R2_spaceship/test.cpp | 296 +++++++++++++++++++-- 2 files changed, 280 insertions(+), 30 deletions(-) diff --git a/stl/inc/tuple b/stl/inc/tuple index a1d007bf4c8..0efd730f4a1 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -235,7 +235,7 @@ public: #ifdef __cpp_lib_concepts constexpr strong_ordering _Three_way_compare(const tuple&) const noexcept { return strong_ordering::equal; - } + } #else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv constexpr bool _Less(const tuple&) const noexcept { return false; @@ -679,14 +679,13 @@ public: #ifdef __cpp_lib_concepts template constexpr common_comparison_category_t<_Synth_three_way_result<_This, _Other_first>, - decltype(declval>()._Three_way_compare(declval>()))> - _Three_way_compare(const tuple<_Other_first, _Other_rest...>& _Right) const { - if (auto _Result = _Synth_three_way()(_Myfirst._Val, _Right._Myfirst._Val); _Result != 0) - { + decltype(declval>()._Three_way_compare(declval>()))> + _Three_way_compare(const tuple<_Other_first, _Other_rest...>& _Right) const { + if (auto _Result = _Synth_three_way()(_Myfirst._Val, _Right._Myfirst._Val); _Result != 0) { return _Result; } return _Mybase::_Three_way_compare(_Right._Get_rest()); - } + } #else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv template constexpr bool _Less(const tuple<_Other...>& _Right) const { @@ -748,8 +747,7 @@ _NODISCARD constexpr bool operator==(const tuple<_Types1...>& _Left, const tuple #ifdef __cpp_lib_concepts template -_NODISCARD constexpr auto operator<=>( - const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { +_NODISCARD constexpr auto operator<=>(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { static_assert(sizeof...(_Types1) == sizeof...(_Types2), "cannot compare tuples of different sizes"); return _Left._Three_way_compare(_Right); } diff --git a/tests/std/tests/P1614R2_spaceship/test.cpp b/tests/std/tests/P1614R2_spaceship/test.cpp index 84160c9ece7..018e74621f6 100644 --- a/tests/std/tests/P1614R2_spaceship/test.cpp +++ b/tests/std/tests/P1614R2_spaceship/test.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -28,21 +29,23 @@ #include template -using SpaceshipType = decltype(std::declval() <=> std::declval()); +using SpaceshipType = std::compare_three_way_result_t; using PartiallyOrdered = double; +struct WeaklyOrdered {}; +using StronglyOrdered = int; -struct WeaklyOrdered { - [[nodiscard]] constexpr bool operator==(const WeaklyOrdered&) const { - return true; - } +[[nodiscard]] constexpr bool operator==(const WeaklyOrdered&, const WeaklyOrdered&) { + return true; +} - [[nodiscard]] constexpr std::weak_ordering operator<=>(const WeaklyOrdered&) const { - return std::weak_ordering::equivalent; - } -}; +[[nodiscard]] constexpr std::weak_ordering operator<=>(const WeaklyOrdered&, const WeaklyOrdered&) { + return std::weak_ordering::equivalent; +} -using StronglyOrdered = int; +[[nodiscard]] constexpr std::partial_ordering operator<=>(const WeaklyOrdered&, const PartiallyOrdered&) { + return std::partial_ordering::equivalent; +} // Activates synth-three-way in N4861 16.4.2.1 [expos.only.func]/2. struct SynthOrdered { @@ -152,16 +155,36 @@ void spaceship_test(const SmallType& smaller, const EqualType& smaller_equal, co static_assert(std::is_same_v larger), ReturnType>); } +// TRANSITION, <=> is unimplemented for string. template -inline constexpr bool is_pair = false; -template -inline constexpr bool is_pair> = true; // TRANSITION, std::pair spaceship not yet implemented +inline constexpr bool has_string = false; +template +inline constexpr bool has_string> = true; +template +inline constexpr bool has_string> = true; +template <> +inline constexpr bool has_string> = true; +template <> +inline constexpr bool has_string = true; + +template +inline constexpr bool has_synth_ordered = false; +template +inline constexpr bool has_synth_ordered> = true; +template +inline constexpr bool has_synth_ordered> = true; +template <> +inline constexpr bool has_synth_ordered> = true; +template <> +inline constexpr bool has_synth_ordered = true; +template <> +inline constexpr bool has_synth_ordered = true; template void ordered_containers_test(const Container& smaller, const Container& smaller_equal, const Container& larger) { using Elem = typename Container::value_type; - if constexpr (is_pair // TRANSITION, std::pair spaceship not yet implemented - || std::is_same_v) { + + if constexpr (has_string || has_synth_ordered) { spaceship_test(smaller, smaller_equal, larger); } else { spaceship_test(smaller, smaller_equal, larger); @@ -205,6 +228,158 @@ void diagnostics_test() { } } +template