diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -13,6 +13,9 @@ /* string synopsis +#include +#include + namespace std { @@ -48,6 +51,8 @@ typedef streamoff off_type; typedef streampos pos_type; typedef mbstate_t state_type; + using comparison_category = strong_ordering; // Since C++20 only for the specializations + // char, wchar_t, char8_t, char16_t, and char32_t. static void assign(char_type& c1, const char_type& c2) noexcept; static constexpr bool eq(char_type c1, char_type c2) noexcept; @@ -370,60 +375,68 @@ const basic_string& rhs) noexcept; // constexpr since C++20 template -bool operator==(const charT* lhs, const basic_string& rhs) noexcept; // constexpr since C++20 +bool operator==(const charT* lhs, const basic_string& rhs) noexcept; // constexpr since C++20, removed in C++20 template bool operator==(const basic_string& lhs, const charT* rhs) noexcept; // constexpr since C++20 template bool operator!=(const basic_string& lhs, - const basic_string& rhs) noexcept; // constexpr since C++20 + const basic_string& rhs) noexcept; // constexpr since C++20, removed in C++20 template -bool operator!=(const charT* lhs, const basic_string& rhs) noexcept; // constexpr since C++20 +bool operator!=(const charT* lhs, const basic_string& rhs) noexcept; // constexpr since C++20, removed in C++20 template -bool operator!=(const basic_string& lhs, const charT* rhs) noexcept; // constexpr since C++20 +bool operator!=(const basic_string& lhs, const charT* rhs) noexcept; // constexpr since C++20, removed in C++20 template bool operator< (const basic_string& lhs, - const basic_string& rhs) noexcept; // constexpr since C++20 + const basic_string& rhs) noexcept; // constexpr since C++20, removed in C++20 template -bool operator< (const basic_string& lhs, const charT* rhs) noexcept; // constexpr since C++20 +bool operator< (const basic_string& lhs, const charT* rhs) noexcept; // constexpr since C++20, removed in C++20 template -bool operator< (const charT* lhs, const basic_string& rhs) noexcept; // constexpr since C++20 +bool operator< (const charT* lhs, const basic_string& rhs) noexcept; // constexpr since C++20, removed in C++20 template bool operator> (const basic_string& lhs, - const basic_string& rhs) noexcept; // constexpr since C++20 + const basic_string& rhs) noexcept; // constexpr since C++20, removed in C++20 template -bool operator> (const basic_string& lhs, const charT* rhs) noexcept; // constexpr since C++20 +bool operator> (const basic_string& lhs, const charT* rhs) noexcept; // constexpr since C++20, removed in C++20 template -bool operator> (const charT* lhs, const basic_string& rhs) noexcept; // constexpr since C++20 +bool operator> (const charT* lhs, const basic_string& rhs) noexcept; // constexpr since C++20, removed in C++20 template bool operator<=(const basic_string& lhs, - const basic_string& rhs) noexcept; // constexpr since C++20 + const basic_string& rhs) noexcept; // constexpr since C++20, removed in C++20 template -bool operator<=(const basic_string& lhs, const charT* rhs) noexcept; // constexpr since C++20 +bool operator<=(const basic_string& lhs, const charT* rhs) noexcept; // constexpr since C++20, removed in C++20 template -bool operator<=(const charT* lhs, const basic_string& rhs) noexcept; // constexpr since C++20 +bool operator<=(const charT* lhs, const basic_string& rhs) noexcept; // constexpr since C++20, removed in C++20 template bool operator>=(const basic_string& lhs, - const basic_string& rhs) noexcept; // constexpr since C++20 + const basic_string& rhs) noexcept; // constexpr since C++20, removed in C++20 template -bool operator>=(const basic_string& lhs, const charT* rhs) noexcept; // constexpr since C++20 +bool operator>=(const basic_string& lhs, const charT* rhs) noexcept; // constexpr since C++20, removed in C++20 template -bool operator>=(const charT* lhs, const basic_string& rhs) noexcept; // constexpr since C++20 +bool operator>=(const charT* lhs, const basic_string& rhs) noexcept; // constexpr since C++20, removed in C++20 + +template // since C++20 +constexpr see below operator<=>(const basic_string& lhs, + const basic_string& rhs) noexcept; + +template // since C++20 +constexpr see below operator<=>(const basic_string& lhs, + const charT* rhs) noexcept; template void swap(basic_string& lhs, @@ -4149,10 +4162,14 @@ operator==(const basic_string<_CharT, _Traits, _Allocator>& __lhs, const basic_string<_CharT, _Traits, _Allocator>& __rhs) _NOEXCEPT { +#if _LIBCPP_STD_VER > 17 + return basic_string_view<_CharT, _Traits>(__lhs) == basic_string_view<_CharT, _Traits>(__rhs); +#else size_t __lhs_sz = __lhs.size(); return __lhs_sz == __rhs.size() && _Traits::compare(__lhs.data(), __rhs.data(), __lhs_sz) == 0; +#endif } template @@ -4174,6 +4191,7 @@ return true; } +#if _LIBCPP_STD_VER < 20 template inline _LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI bool @@ -4186,6 +4204,7 @@ if (__lhs_len != __rhs.size()) return false; return __rhs.compare(0, _String::npos, __lhs, __lhs_len) == 0; } +#endif // _LIBCPP_STD_VER < 20 template inline _LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI @@ -4193,13 +4212,34 @@ operator==(const basic_string<_CharT,_Traits,_Allocator>& __lhs, const _CharT* __rhs) _NOEXCEPT { +#if _LIBCPP_STD_VER > 17 + return basic_string_view<_CharT, _Traits>(__lhs) == basic_string_view<_CharT, _Traits>(__rhs); +#else typedef basic_string<_CharT, _Traits, _Allocator> _String; _LIBCPP_ASSERT(__rhs != nullptr, "operator==(basic_string, char*): received nullptr"); size_t __rhs_len = _Traits::length(__rhs); if (__rhs_len != __lhs.size()) return false; return __lhs.compare(0, _String::npos, __rhs, __rhs_len) == 0; +#endif } +#if _LIBCPP_STD_VER > 17 + +template +_LIBCPP_HIDE_FROM_ABI constexpr auto operator<=>( + const basic_string<_CharT, _Traits, _Allocator>& __lhs, + const basic_string<_CharT, _Traits, _Allocator>& __rhs) noexcept { + return basic_string_view<_CharT, _Traits>(__lhs) <=> basic_string_view<_CharT, _Traits>(__rhs); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr auto +operator<=>(const basic_string<_CharT, _Traits, _Allocator>& __lhs, const _CharT* __rhs) noexcept { + return basic_string_view<_CharT, _Traits>(__lhs) <=> basic_string_view<_CharT, _Traits>(__rhs); +} + +#else // _LIBCPP_STD_VER > 17 + template inline _LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI bool @@ -4342,6 +4382,7 @@ { return !(__lhs < __rhs); } +#endif // _LIBCPP_STD_VER > 17 // operator + diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string.cmp/comparison.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string.cmp/comparison.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string.cmp/comparison.pass.cpp @@ -0,0 +1,102 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// Starting with C++20 the spaceship operator was included. This tests +// comparison in that context, thus doesn't support older language versions. +// These are tested per operator. + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// template +// see below operator<=>(const basic_string& lhs, +// const basic_string& rhs) noexcept; +// template +// see below operator<=>(const basic_string& lhs, +// const charT* rhs); + +#include + +#include +#include +#include + +#include "constexpr_char_traits.h" +#include "make_string.h" +#include "test_comparisons.h" +#include "test_macros.h" + +#define STR(S) MAKE_STRING(CharT, S) + +template +constexpr bool test() { + AssertOrderAreNoexcept(); + AssertOrderReturn(); + + using CharT = typename T::value_type; + + // sorted values + std::array v{ + STR(""), + STR("abc"), + STR("abcdef"), + STR("acb"), + }; + + // sorted values with embedded NUL character + std::array vn{ + STR("abc"), + STR("abc\0"), + STR("abc\0def"), + STR("acb\0"), + }; + static_assert(v.size() == vn.size()); + + for (size_t i = 0; i < v.size(); ++i) { + for (size_t j = 0; j < v.size(); ++j) { + assert(testOrder(v[i], v[j], i == j ? Ordering::equivalent : i < j ? Ordering::less : Ordering::greater)); + + assert(testOrder( + v[i], + std::basic_string{v[j]}.c_str(), + i == j ? Ordering::equivalent + : i < j ? Ordering::less + : Ordering::greater)); + + // NUL test omitted for c-strings since it will fail. + assert(testOrder(vn[i], vn[j], i == j ? Ordering::equivalent : i < j ? Ordering::less : Ordering::greater)); + } + } + + return true; +} + +constexpr bool test_all_types() { + test(); + test>, std::weak_ordering>(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test(); + test>, std::weak_ordering>(); +#endif + test(); + test>, std::weak_ordering>(); + test(); + test>, std::weak_ordering>(); + test(); + test>, std::weak_ordering>(); + + return true; +} + +int main(int, char**) { + test_all_types(); + static_assert(test_all_types()); + + return 0; +}