diff --git a/stl/inc/xstring b/stl/inc/xstring index 80355987c2c..c5fc7e1c89f 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -39,6 +39,9 @@ struct _Char_traits { // properties of a string or stream element using pos_type = streampos; using off_type = streamoff; using state_type = _Mbstatet; +#if _HAS_CXX20 + using comparison_category = strong_ordering; +#endif // _HAS_CXX20 // For copy/move, we can uniformly call memcpy/memmove (or their builtin versions) for all element types. @@ -217,6 +220,9 @@ public: using pos_type = streampos; using off_type = streamoff; using state_type = mbstate_t; +#if _HAS_CXX20 + using comparison_category = strong_ordering; +#endif // _HAS_CXX20 using _Primary_char_traits::_Copy_s; using _Primary_char_traits::copy; @@ -355,6 +361,9 @@ public: using pos_type = streampos; using off_type = streamoff; using state_type = mbstate_t; +#if _HAS_CXX20 + using comparison_category = strong_ordering; +#endif // _HAS_CXX20 using _Primary_char_traits::_Copy_s; using _Primary_char_traits::copy; @@ -1659,11 +1668,13 @@ _NODISCARD constexpr bool operator==( return _Lhs._Equal(_Rhs); } +#if !_HAS_CXX20 template // TRANSITION, VSO-409326 _NODISCARD constexpr bool operator==( const _Identity_t> _Lhs, const basic_string_view<_Elem, _Traits> _Rhs) noexcept { return _Lhs._Equal(_Rhs); } +#endif // !_HAS_CXX20 template // TRANSITION, VSO-409326 _NODISCARD constexpr bool operator==( @@ -1671,7 +1682,7 @@ _NODISCARD constexpr bool operator==( return _Lhs._Equal(_Rhs); } - +#if !_HAS_CXX20 // FUNCTION TEMPLATES operator!= FOR basic_string_view template _NODISCARD constexpr bool operator!=( @@ -1770,7 +1781,37 @@ _NODISCARD constexpr bool operator>=( const basic_string_view<_Elem, _Traits> _Lhs, const _Identity_t> _Rhs) noexcept { return _Lhs.compare(_Rhs) >= 0; } +#endif // !_HAS_CXX20 + +#if _HAS_CXX20 +template +struct _Get_comparison_category { + using type = weak_ordering; +}; + +template +struct _Get_comparison_category<_Traits, void_t> { + using type = typename _Traits::comparison_category; + + static_assert(_Is_any_of_v, + "N4878 [string.view.comparison]/4: Mandates: R denotes a comparison category type."); +}; + +template +using _Get_comparison_category_t = typename _Get_comparison_category<_Traits>::type; + +template +_NODISCARD constexpr _Get_comparison_category_t<_Traits> operator<=>( + const basic_string_view<_Elem, _Traits> _Lhs, const basic_string_view<_Elem, _Traits> _Rhs) noexcept { + return static_cast<_Get_comparison_category_t<_Traits>>(_Lhs.compare(_Rhs) <=> 0); +} +template // TRANSITION, VSO-409326 +_NODISCARD constexpr _Get_comparison_category_t<_Traits> operator<=>( + const basic_string_view<_Elem, _Traits> _Lhs, const _Identity_t> _Rhs) noexcept { + return static_cast<_Get_comparison_category_t<_Traits>>(_Lhs.compare(_Rhs) <=> 0); +} +#endif // _HAS_CXX20 // TYPEDEFS FOR basic_string_view using string_view = basic_string_view; @@ -4512,13 +4553,26 @@ _NODISCARD bool operator==( } template -_NODISCARD bool operator==(_In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { - return _Right._Equal(_Left); +_NODISCARD bool operator==(const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) { + return _Left._Equal(_Right); } +#if _HAS_CXX20 template -_NODISCARD bool operator==(const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) { - return _Left._Equal(_Right); +_NODISCARD _Get_comparison_category_t<_Traits> operator<=>( + const basic_string<_Elem, _Traits, _Alloc>& _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) noexcept { + return static_cast<_Get_comparison_category_t<_Traits>>(_Left.compare(_Right) <=> 0); +} + +template +_NODISCARD _Get_comparison_category_t<_Traits> operator<=>( + const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) { + return static_cast<_Get_comparison_category_t<_Traits>>(_Left.compare(_Right) <=> 0); +} +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +template +_NODISCARD bool operator==(_In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { + return _Right._Equal(_Left); } template @@ -4600,6 +4654,7 @@ template _NODISCARD bool operator>=(const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) { return !(_Left < _Right); } +#endif // ^^^ !_HAS_CXX20 ^^^ using string = basic_string, allocator>; using wstring = basic_string, allocator>; diff --git a/tests/std/tests/P1614R2_spaceship/test.cpp b/tests/std/tests/P1614R2_spaceship/test.cpp index c488238b56f..cd7135057be 100644 --- a/tests/std/tests/P1614R2_spaceship/test.cpp +++ b/tests/std/tests/P1614R2_spaceship/test.cpp @@ -1,9 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// Covers: -// * spaceship for containers - #include #include #include @@ -21,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -433,14 +431,13 @@ void ordering_test_cases() { std::ssub_match sm3 = m3[0]; std::ssub_match sm4 = m4[0]; - // 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()); - spaceship_test(sm3, 'c', 'm'); - spaceship_test(s1, sm1, sm2); - spaceship_test(s1.c_str(), sm1, sm2); - spaceship_test('c', sm3, sm4); + 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>; @@ -448,12 +445,134 @@ void ordering_test_cases() { std::sub_match::const_iterator>; using PartiallyOrderedMatch = std::sub_match::const_iterator>; - // 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::strong_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>); } + { // char_traits + static_assert(std::is_same_v::comparison_category, std::strong_ordering>); +#ifdef __cpp_char8_t + static_assert(std::is_same_v::comparison_category, std::strong_ordering>); +#endif // __cpp_char8_t + static_assert(std::is_same_v::comparison_category, std::strong_ordering>); + static_assert(std::is_same_v::comparison_category, std::strong_ordering>); + static_assert(std::is_same_v::comparison_category, std::strong_ordering>); + } + { // Strings library + const std::string a1 = "abcdef"; + const std::string a2 = "abcdef"; + const std::string a3 = "abcdefg"; + const std::string a4 = "abcde"; + const std::string a5 = "abddef"; + const std::string a6 = "abbdef"; + + assert((a1 <=> a2) == std::strong_ordering::equivalent); + assert((a1 <=> a3) == std::strong_ordering::less); + assert((a1 <=> a4) == std::strong_ordering::greater); + assert((a1 <=> a5) == std::strong_ordering::less); + assert((a1 <=> a6) == std::strong_ordering::greater); + + assert(a1 == a2); + assert(a1 >= a2); + assert(a1 <= a2); + assert(a1 < a3); + assert(a1 <= a3); + assert(a1 != a3); + assert(a1 > a4); + assert(a1 >= a4); + assert(a1 != a4); + assert(a1 < a5); + assert(a1 <= a5); + assert(a1 != a5); + assert(a1 > a6); + assert(a1 >= a6); + assert(a1 != a6); + + assert((a1 <=> "aardvark") == std::strong_ordering::greater); + assert((a1 <=> "abcdef") == std::strong_ordering::equivalent); + assert((a1 <=> "zebra") == std::strong_ordering::less); + + assert(("aardvark" <=> a1) == std::strong_ordering::less); + assert(("abcdef" <=> a1) == std::strong_ordering::equivalent); + assert(("zebra" <=> a1) == std::strong_ordering::greater); + } + { // string_view + const std::string_view a1 = "abcdef"; + const std::string_view a2 = "abcdef"; + const std::string_view a3 = "abcdefg"; + const std::string_view a4 = "abcde"; + const std::string_view a5 = "abddef"; + const std::string_view a6 = "abbdef"; + + assert((a1 <=> a2) == std::strong_ordering::equivalent); + assert((a1 <=> a3) == std::strong_ordering::less); + assert((a1 <=> a4) == std::strong_ordering::greater); + assert((a1 <=> a5) == std::strong_ordering::less); + assert((a1 <=> a6) == std::strong_ordering::greater); + + assert(a1 == a2); + assert(a1 >= a2); + assert(a1 <= a2); + assert(a1 < a3); + assert(a1 <= a3); + assert(a1 != a3); + assert(a1 > a4); + assert(a1 >= a4); + assert(a1 != a4); + assert(a1 < a5); + assert(a1 <= a5); + assert(a1 != a5); + assert(a1 > a6); + assert(a1 >= a6); + assert(a1 != a6); + + assert((a1 <=> "aardvark") == std::strong_ordering::greater); + assert((a1 <=> "abcdef") == std::strong_ordering::equivalent); + assert((a1 <=> "zebra") == std::strong_ordering::less); + + assert(("aardvark" <=> a1) == std::strong_ordering::less); + assert(("abcdef" <=> a1) == std::strong_ordering::equivalent); + assert(("zebra" <=> a1) == std::strong_ordering::greater); + } + { // constexpr string_view + constexpr std::string_view a1 = "abcdef"; + constexpr std::string_view a2 = "abcdef"; + constexpr std::string_view a3 = "abcdefg"; + constexpr std::string_view a4 = "abcde"; + constexpr std::string_view a5 = "abddef"; + constexpr std::string_view a6 = "abbdef"; + + static_assert((a1 <=> a2) == std::strong_ordering::equivalent); + static_assert((a1 <=> a3) == std::strong_ordering::less); + static_assert((a1 <=> a4) == std::strong_ordering::greater); + static_assert((a1 <=> a5) == std::strong_ordering::less); + static_assert((a1 <=> a6) == std::strong_ordering::greater); + + static_assert(a1 == a2); + static_assert(a1 >= a2); + static_assert(a1 <= a2); + static_assert(a1 < a3); + static_assert(a1 <= a3); + static_assert(a1 != a3); + static_assert(a1 > a4); + static_assert(a1 >= a4); + static_assert(a1 != a4); + static_assert(a1 < a5); + static_assert(a1 <= a5); + static_assert(a1 != a5); + static_assert(a1 > a6); + static_assert(a1 >= a6); + static_assert(a1 != a6); + + static_assert((a1 <=> "aardvark") == std::strong_ordering::greater); + static_assert((a1 <=> "abcdef") == std::strong_ordering::equivalent); + static_assert((a1 <=> "zebra") == std::strong_ordering::less); + + static_assert(("aardvark" <=> a1) == std::strong_ordering::less); + static_assert(("abcdef" <=> a1) == std::strong_ordering::equivalent); + static_assert(("zebra" <=> a1) == std::strong_ordering::greater); + } { // Diagnostics Library diagnostics_test(); diagnostics_test();