diff --git a/libcxx/include/__string b/libcxx/include/__string --- a/libcxx/include/__string +++ b/libcxx/include/__string @@ -12,6 +12,7 @@ #include <__config> #include // for search and min +#include // for spaceship support #include // for EOF #include // for memcpy #include // for wmemcpy @@ -315,6 +316,9 @@ typedef streamoff off_type; typedef streampos pos_type; typedef mbstate_t state_type; +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + typedef strong_ordering comparison_category; +#endif static inline _LIBCPP_CONSTEXPR_AFTER_CXX14 void assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {__c1 = __c2;} @@ -418,6 +422,9 @@ typedef streamoff off_type; typedef streampos pos_type; typedef mbstate_t state_type; +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + typedef strong_ordering comparison_category; +#endif static inline _LIBCPP_CONSTEXPR_AFTER_CXX14 void assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {__c1 = __c2;} @@ -548,6 +555,9 @@ typedef streamoff off_type; typedef u8streampos pos_type; typedef mbstate_t state_type; +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + typedef strong_ordering comparison_category; +#endif static inline constexpr void assign(char_type& __c1, const char_type& __c2) noexcept {__c1 = __c2;} @@ -657,6 +667,9 @@ typedef streamoff off_type; typedef u16streampos pos_type; typedef mbstate_t state_type; +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + typedef strong_ordering comparison_category; +#endif static inline _LIBCPP_CONSTEXPR_AFTER_CXX14 void assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {__c1 = __c2;} @@ -777,6 +790,9 @@ typedef streamoff off_type; typedef u32streampos pos_type; typedef mbstate_t state_type; +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + typedef strong_ordering comparison_category; +#endif static inline _LIBCPP_CONSTEXPR_AFTER_CXX14 void assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {__c1 = __c2;} diff --git a/libcxx/include/string_view b/libcxx/include/string_view --- a/libcxx/include/string_view +++ b/libcxx/include/string_view @@ -28,19 +28,22 @@ basic_string_view y) noexcept; template constexpr bool operator!=(basic_string_view x, - basic_string_view y) noexcept; + basic_string_view y) noexcept; // C++17 template constexpr bool operator< (basic_string_view x, - basic_string_view y) noexcept; + basic_string_view y) noexcept; // C++17 template constexpr bool operator> (basic_string_view x, - basic_string_view y) noexcept; + basic_string_view y) noexcept; // C++17 template constexpr bool operator<=(basic_string_view x, - basic_string_view y) noexcept; + basic_string_view y) noexcept; // C++17 template constexpr bool operator>=(basic_string_view x, - basic_string_view y) noexcept; + basic_string_view y) noexcept; // C++17 + template + constexpr auto operator<=>(basic_string_view x, + basic_string_view y) noexcept; // C++20 // see below, sufficient additional overloads of comparison functions // 7.10, Inserters and extractors @@ -678,6 +681,38 @@ return __lhs.compare(__rhs) == 0; } +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + +template +using __test_for_comparison_category = typename _Tp::comparison_category; + +template +constexpr _LIBCPP_INLINE_VISIBILITY +auto operator<=>(const basic_string_view<_CharT, _Traits> __lhs, const basic_string_view<_CharT, _Traits> __rhs) noexcept { + const auto __result = __lhs.compare(__rhs) <=> 0; + if constexpr (_IsValidExpansion<__test_for_comparison_category, _Traits>::value) { + return static_cast(__result); + } + else { + return static_cast(__result); + } +} + +template +constexpr _LIBCPP_INLINE_VISIBILITY +auto operator<=>(const basic_string_view<_CharT, _Traits> __lhs, + const common_type_t> __rhs) noexcept { + const auto __result = __lhs.compare(__rhs) <=> 0; + if constexpr (_IsValidExpansion<__test_for_comparison_category, _Traits>::value) { + return static_cast(__result); + } + else { + return static_cast(__result); + } +} + +#else // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + template _LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY bool operator==(typename common_type >::type __lhs, @@ -819,6 +854,7 @@ return __lhs.compare(__rhs) >= 0; } +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) template basic_ostream<_CharT, _Traits>& diff --git a/libcxx/test/std/strings/string.view/string.view.comparison/opcmp.string_view.pointer.pass.cpp b/libcxx/test/std/strings/string.view/string.view.comparison/opcmp.string_view.pointer.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/string.view/string.view.comparison/opcmp.string_view.pointer.pass.cpp @@ -0,0 +1,92 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +// + +// template +// constexpr bool operator<=>(const charT* lhs, basic_string_view rhs); +// template +// constexpr bool operator<=>(basic_string_view lhs, const charT* rhs); + +#include +#include +#include + +#include "test_macros.h" +#include "compare_char_traits.h" + +template +constexpr void test(typename S::value_type const* const lhs, S const rhs, std::strong_ordering const x) { + auto const y = 0 <=> x; + assert((lhs <=> rhs) == x); + assert((rhs <=> lhs) == y); +} + +template +[[nodiscard]] constexpr bool test_all(S const empty, S const abcde, S const abcdefghij, S const abcdefghijklmnopqrst) { + test(empty.data(), empty, std::strong_ordering::equal); + test(empty.data(), abcde, std::strong_ordering::less); + test(empty.data(), abcdefghij, std::strong_ordering::less); + test(empty.data(), abcdefghijklmnopqrst, std::strong_ordering::less); + test(abcde.data(), empty, std::strong_ordering::greater); + test(abcde.data(), abcde, std::strong_ordering::equal); + test(abcde.data(), abcdefghij, std::strong_ordering::less); + test(abcde.data(), abcdefghijklmnopqrst, std::strong_ordering::less); + test(abcdefghij.data(), empty, std::strong_ordering::greater); + test(abcdefghij.data(), abcde, std::strong_ordering::greater); + test(abcdefghij.data(), abcdefghij, std::strong_ordering::equal); + test(abcdefghij.data(), abcdefghijklmnopqrst, std::strong_ordering::less); + test(abcdefghijklmnopqrst.data(), empty, std::strong_ordering::greater); + test(abcdefghijklmnopqrst.data(), abcde, std::strong_ordering::greater); + test(abcdefghijklmnopqrst.data(), abcdefghij, std::strong_ordering::greater); + test(abcdefghijklmnopqrst.data(), abcdefghijklmnopqrst, std::strong_ordering::equal); + return true; +} + +int main(int, char**) { + static_assert(test_all("", "abcde", "abcdefghij", "abcdefghijklmnopqrst")); + assert(test_all("", "abcde", "abcdefghij", "abcdefghijklmnopqrst")); + ASSERT_SAME_TYPE(decltype(std::string_view() <=> ""), std::strong_ordering); + ASSERT_SAME_TYPE(decltype("" <=> std::string_view()), std::strong_ordering); + + static_assert(test_all(L"", L"abcde", L"abcdefghij", L"abcdefghijklmnopqrst")); + assert(test_all(L"", L"abcde", L"abcdefghij", L"abcdefghijklmnopqrst")); + ASSERT_SAME_TYPE(decltype(std::wstring_view() <=> L""), std::strong_ordering); + ASSERT_SAME_TYPE(decltype(L"" <=> std::wstring_view()), std::strong_ordering); + + static_assert(test_all(u8"", u8"abcde", u8"abcdefghij", u8"abcdefghijklmnopqrst")); + assert(test_all(u8"", u8"abcde", u8"abcdefghij", u8"abcdefghijklmnopqrst")); + ASSERT_SAME_TYPE(decltype(std::u8string_view() <=> u8""), std::strong_ordering); + ASSERT_SAME_TYPE(decltype(u8"" <=> std::u8string_view()), std::strong_ordering); + + static_assert(test_all(u"", u"abcde", u"abcdefghij", u"abcdefghijklmnopqrst")); + assert(test_all(u"", u"abcde", u"abcdefghij", u"abcdefghijklmnopqrst")); + ASSERT_SAME_TYPE(decltype(std::u16string_view() <=> u""), std::strong_ordering); + ASSERT_SAME_TYPE(decltype(u"" <=> std::u16string_view()), std::strong_ordering); + + static_assert(test_all(U"", U"abcde", U"abcdefghij", U"abcdefghijklmnopqrst")); + assert(test_all(U"", U"abcde", U"abcdefghij", U"abcdefghijklmnopqrst")); + ASSERT_SAME_TYPE(decltype(std::u32string_view() <=> U""), std::strong_ordering); + ASSERT_SAME_TYPE(decltype(U"" <=> std::u32string_view()), std::strong_ordering); + + using no_comp_category = std::basic_string_view; + static_assert(test_all("", "abcde", "abcdefghij", "abcdefghijklmnopqrst")); + assert((test_all("", "abcde", "abcdefghij", "abcdefghijklmnopqrst"))); + ASSERT_SAME_TYPE(decltype(no_comp_category() <=> ""), std::weak_ordering); + ASSERT_SAME_TYPE(decltype("" <=> no_comp_category()), std::weak_ordering); + + using data_comp_category = std::basic_string_view; + static_assert(test_all("", "abcde", "abcdefghij", "abcdefghijklmnopqrst")); + assert((test_all("", "abcde", "abcdefghij", "abcdefghijklmnopqrst"))); + ASSERT_SAME_TYPE(decltype(data_comp_category() <=> ""), std::weak_ordering); + ASSERT_SAME_TYPE(decltype("" <=> data_comp_category()), std::weak_ordering); + + return 0; +} diff --git a/libcxx/test/std/strings/string.view/string.view.comparison/opcmp.string_view.string_view.pass.cpp b/libcxx/test/std/strings/string.view/string.view.comparison/opcmp.string_view.string_view.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/string.view/string.view.comparison/opcmp.string_view.string_view.pass.cpp @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +// + +// template +// constexpr bool operator<=>(const charT* lhs, basic_string_view rhs); +// template +// constexpr bool operator<=>(basic_string_view lhs, const charT* rhs); + +#include + +#include +#include + +#include "test_macros.h" +#include "compare_char_traits.h" + +template +constexpr void test(S const lhs, S const rhs, std::strong_ordering const x) { + auto const y = 0 <=> x; + assert((lhs <=> rhs) == x); + assert((rhs <=> lhs) == y); +} + +template +[[nodiscard]] constexpr bool test_all(S const empty, S const abcde, S const abcdefghij, S const abcdefghijklmnopqrst) { + test(empty, empty, std::strong_ordering::equal); + test(empty, abcde, std::strong_ordering::less); + test(empty, abcdefghij, std::strong_ordering::less); + test(empty, abcdefghijklmnopqrst, std::strong_ordering::less); + test(abcde, empty, std::strong_ordering::greater); + test(abcde, abcde, std::strong_ordering::equal); + test(abcde, abcdefghij, std::strong_ordering::less); + test(abcde, abcdefghijklmnopqrst, std::strong_ordering::less); + test(abcdefghij, empty, std::strong_ordering::greater); + test(abcdefghij, abcde, std::strong_ordering::greater); + test(abcdefghij, abcdefghij, std::strong_ordering::equal); + test(abcdefghij, abcdefghijklmnopqrst, std::strong_ordering::less); + test(abcdefghijklmnopqrst, empty, std::strong_ordering::greater); + test(abcdefghijklmnopqrst, abcde, std::strong_ordering::greater); + test(abcdefghijklmnopqrst, abcdefghij, std::strong_ordering::greater); + test(abcdefghijklmnopqrst, abcdefghijklmnopqrst, std::strong_ordering::equal); + return true; +} + +int main(int, char**) { + static_assert(test_all("", "abcde", "abcdefghij", "abcdefghijklmnopqrst")); + ASSERT_SAME_TYPE(decltype(std::operator<=>(std::string_view(), std::string_view())), std::strong_ordering); + assert(test_all("", "abcde", "abcdefghij", "abcdefghijklmnopqrst")); + + static_assert(test_all(L"", L"abcde", L"abcdefghij", L"abcdefghijklmnopqrst")); + ASSERT_SAME_TYPE(decltype(std::operator<=>(std::wstring_view(), std::wstring_view())), std::strong_ordering); + assert(test_all(L"", L"abcde", L"abcdefghij", L"abcdefghijklmnopqrst")); + + static_assert(test_all(u8"", u8"abcde", u8"abcdefghij", u8"abcdefghijklmnopqrst")); + ASSERT_SAME_TYPE(decltype(std::operator<=>(std::u8string_view(), std::u8string_view())), std::strong_ordering); + assert(test_all(u8"", u8"abcde", u8"abcdefghij", u8"abcdefghijklmnopqrst")); + + static_assert(test_all(u"", u"abcde", u"abcdefghij", u"abcdefghijklmnopqrst")); + ASSERT_SAME_TYPE(decltype(std::operator<=>(std::u16string_view(), std::u16string_view())), std::strong_ordering); + assert(test_all(u"", u"abcde", u"abcdefghij", u"abcdefghijklmnopqrst")); + + static_assert(test_all(U"", U"abcde", U"abcdefghij", U"abcdefghijklmnopqrst")); + ASSERT_SAME_TYPE(decltype(std::operator<=>(std::u32string_view(), std::u32string_view())), std::strong_ordering); + assert(test_all(U"", U"abcde", U"abcdefghij", U"abcdefghijklmnopqrst")); + + using no_comp_category = std::basic_string_view; + static_assert(test_all("", "abcde", "abcdefghij", "abcdefghijklmnopqrst")); + ASSERT_SAME_TYPE(decltype(std::operator<=>(no_comp_category(), no_comp_category())), std::weak_ordering); + assert((test_all("", "abcde", "abcdefghij", "abcdefghijklmnopqrst"))); + + using data_comp_category = std::basic_string_view; + static_assert(test_all("", "abcde", "abcdefghij", "abcdefghijklmnopqrst")); + ASSERT_SAME_TYPE(decltype(std::operator<=>(data_comp_category(), data_comp_category())), std::weak_ordering); + assert((test_all("", "abcde", "abcdefghij", "abcdefghijklmnopqrst"))); + + return 0; +} diff --git a/libcxx/test/support/compare_char_traits.h b/libcxx/test/support/compare_char_traits.h new file mode 100644 --- /dev/null +++ b/libcxx/test/support/compare_char_traits.h @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// A set of routines for testing the comparison operators of a type +// +// XXXX6 tests all six comparison operators +// XXXX2 tests only op== and op!= +// +// AssertComparisonsXAreNoexcept static_asserts that the operations are all noexcept. +// AssertComparisonsXReturnBool static_asserts that the operations return bool. +// AssertComparisonsXConvertibleToBool static_asserts that the operations return something convertible to bool. + +#ifndef LIBCXX_TEST_SUPPORT_COMPARE_CHAR_TRAITS_H +#define LIBCXX_TEST_SUPPORT_COMPARE_CHAR_TRAITS_H + +struct traits_without_comparison_category : private std::char_traits { + using base_t = std::char_traits; + using base_t::char_type; + using base_t::int_type; + using base_t::off_type; + using base_t::pos_type; + using base_t::state_type; + // using comparison_category = not defined + + using base_t::assign; + using base_t::compare; + using base_t::copy; + using base_t::eof; + using base_t::eq; + using base_t::eq_int_type; + using base_t::find; + using base_t::length; + using base_t::lt; + using base_t::move; + using base_t::not_eof; + using base_t::to_char_type; + using base_t::to_int_type; +}; + +struct traits_with_data_comparison_category : private std::char_traits { + using base_t = std::char_traits; + using base_t::char_type; + using base_t::int_type; + using base_t::off_type; + using base_t::pos_type; + using base_t::state_type; + // using comparison_category = not defined + inline constexpr static int comparison_category = 0; + + using base_t::assign; + using base_t::compare; + using base_t::copy; + using base_t::eof; + using base_t::eq; + using base_t::eq_int_type; + using base_t::find; + using base_t::length; + using base_t::lt; + using base_t::move; + using base_t::not_eof; + using base_t::to_char_type; + using base_t::to_int_type; +}; + +#endif // LIBCXX_TEST_SUPPORT_COMPARE_CHAR_TRAITS_H