Skip to content

Commit bbedd7a

Browse files
Anju del Moral GonzalezAnjuDelCaseyCarterStephanTLavavej
authored
feature/spaceship: Clause 21: Strings (#1635)
Co-authored-by: Anju Del Moral Gonzalez <[email protected]> Co-authored-by: Casey Carter <[email protected]> Co-authored-by: Stephan T. Lavavej <[email protected]>
1 parent 250aa73 commit bbedd7a

File tree

2 files changed

+192
-18
lines changed

2 files changed

+192
-18
lines changed

stl/inc/xstring

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ struct _Char_traits { // properties of a string or stream element
3939
using pos_type = streampos;
4040
using off_type = streamoff;
4141
using state_type = _Mbstatet;
42+
#if _HAS_CXX20
43+
using comparison_category = strong_ordering;
44+
#endif // _HAS_CXX20
4245

4346
// For copy/move, we can uniformly call memcpy/memmove (or their builtin versions) for all element types.
4447

@@ -217,6 +220,9 @@ public:
217220
using pos_type = streampos;
218221
using off_type = streamoff;
219222
using state_type = mbstate_t;
223+
#if _HAS_CXX20
224+
using comparison_category = strong_ordering;
225+
#endif // _HAS_CXX20
220226

221227
using _Primary_char_traits::_Copy_s;
222228
using _Primary_char_traits::copy;
@@ -355,6 +361,9 @@ public:
355361
using pos_type = streampos;
356362
using off_type = streamoff;
357363
using state_type = mbstate_t;
364+
#if _HAS_CXX20
365+
using comparison_category = strong_ordering;
366+
#endif // _HAS_CXX20
358367

359368
using _Primary_char_traits::_Copy_s;
360369
using _Primary_char_traits::copy;
@@ -1659,19 +1668,21 @@ _NODISCARD constexpr bool operator==(
16591668
return _Lhs._Equal(_Rhs);
16601669
}
16611670

1671+
#if !_HAS_CXX20
16621672
template <class _Elem, class _Traits, int = 1> // TRANSITION, VSO-409326
16631673
_NODISCARD constexpr bool operator==(
16641674
const _Identity_t<basic_string_view<_Elem, _Traits>> _Lhs, const basic_string_view<_Elem, _Traits> _Rhs) noexcept {
16651675
return _Lhs._Equal(_Rhs);
16661676
}
1677+
#endif // !_HAS_CXX20
16671678

16681679
template <class _Elem, class _Traits, int = 2> // TRANSITION, VSO-409326
16691680
_NODISCARD constexpr bool operator==(
16701681
const basic_string_view<_Elem, _Traits> _Lhs, const _Identity_t<basic_string_view<_Elem, _Traits>> _Rhs) noexcept {
16711682
return _Lhs._Equal(_Rhs);
16721683
}
16731684

1674-
1685+
#if !_HAS_CXX20
16751686
// FUNCTION TEMPLATES operator!= FOR basic_string_view
16761687
template <class _Elem, class _Traits>
16771688
_NODISCARD constexpr bool operator!=(
@@ -1770,7 +1781,37 @@ _NODISCARD constexpr bool operator>=(
17701781
const basic_string_view<_Elem, _Traits> _Lhs, const _Identity_t<basic_string_view<_Elem, _Traits>> _Rhs) noexcept {
17711782
return _Lhs.compare(_Rhs) >= 0;
17721783
}
1784+
#endif // !_HAS_CXX20
1785+
1786+
#if _HAS_CXX20
1787+
template <class _Traits, class = void>
1788+
struct _Get_comparison_category {
1789+
using type = weak_ordering;
1790+
};
1791+
1792+
template <class _Traits>
1793+
struct _Get_comparison_category<_Traits, void_t<typename _Traits::comparison_category>> {
1794+
using type = typename _Traits::comparison_category;
1795+
1796+
static_assert(_Is_any_of_v<type, partial_ordering, weak_ordering, strong_ordering>,
1797+
"N4878 [string.view.comparison]/4: Mandates: R denotes a comparison category type.");
1798+
};
1799+
1800+
template <class _Traits>
1801+
using _Get_comparison_category_t = typename _Get_comparison_category<_Traits>::type;
1802+
1803+
template <class _Elem, class _Traits>
1804+
_NODISCARD constexpr _Get_comparison_category_t<_Traits> operator<=>(
1805+
const basic_string_view<_Elem, _Traits> _Lhs, const basic_string_view<_Elem, _Traits> _Rhs) noexcept {
1806+
return static_cast<_Get_comparison_category_t<_Traits>>(_Lhs.compare(_Rhs) <=> 0);
1807+
}
17731808

1809+
template <class _Elem, class _Traits, int = 2> // TRANSITION, VSO-409326
1810+
_NODISCARD constexpr _Get_comparison_category_t<_Traits> operator<=>(
1811+
const basic_string_view<_Elem, _Traits> _Lhs, const _Identity_t<basic_string_view<_Elem, _Traits>> _Rhs) noexcept {
1812+
return static_cast<_Get_comparison_category_t<_Traits>>(_Lhs.compare(_Rhs) <=> 0);
1813+
}
1814+
#endif // _HAS_CXX20
17741815

17751816
// TYPEDEFS FOR basic_string_view
17761817
using string_view = basic_string_view<char>;
@@ -4512,13 +4553,26 @@ _NODISCARD bool operator==(
45124553
}
45134554

45144555
template <class _Elem, class _Traits, class _Alloc>
4515-
_NODISCARD bool operator==(_In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) {
4516-
return _Right._Equal(_Left);
4556+
_NODISCARD bool operator==(const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) {
4557+
return _Left._Equal(_Right);
45174558
}
45184559

4560+
#if _HAS_CXX20
45194561
template <class _Elem, class _Traits, class _Alloc>
4520-
_NODISCARD bool operator==(const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) {
4521-
return _Left._Equal(_Right);
4562+
_NODISCARD _Get_comparison_category_t<_Traits> operator<=>(
4563+
const basic_string<_Elem, _Traits, _Alloc>& _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) noexcept {
4564+
return static_cast<_Get_comparison_category_t<_Traits>>(_Left.compare(_Right) <=> 0);
4565+
}
4566+
4567+
template <class _Elem, class _Traits, class _Alloc>
4568+
_NODISCARD _Get_comparison_category_t<_Traits> operator<=>(
4569+
const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) {
4570+
return static_cast<_Get_comparison_category_t<_Traits>>(_Left.compare(_Right) <=> 0);
4571+
}
4572+
#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv
4573+
template <class _Elem, class _Traits, class _Alloc>
4574+
_NODISCARD bool operator==(_In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) {
4575+
return _Right._Equal(_Left);
45224576
}
45234577

45244578
template <class _Elem, class _Traits, class _Alloc>
@@ -4600,6 +4654,7 @@ template <class _Elem, class _Traits, class _Alloc>
46004654
_NODISCARD bool operator>=(const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) {
46014655
return !(_Left < _Right);
46024656
}
4657+
#endif // ^^^ !_HAS_CXX20 ^^^
46034658

46044659
using string = basic_string<char, char_traits<char>, allocator<char>>;
46054660
using wstring = basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>>;

tests/std/tests/P1614R2_spaceship/test.cpp

Lines changed: 132 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
// Copyright (c) Microsoft Corporation.
22
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
33

4-
// Covers:
5-
// * spaceship for containers
6-
74
#include <array>
85
#include <cassert>
96
#include <compare>
@@ -21,6 +18,7 @@
2118
#include <set>
2219
#include <stack>
2320
#include <string>
21+
#include <string_view>
2422
#include <system_error>
2523
#include <thread>
2624
#include <type_traits>
@@ -434,27 +432,148 @@ void ordering_test_cases() {
434432
std::ssub_match sm3 = m3[0];
435433
std::ssub_match sm4 = m4[0];
436434

437-
// TRANSITION, std::char_traits<char> doesn't define comparison_category
438-
spaceship_test<std::weak_ordering>(sm1, sm1_equal, sm2);
439-
spaceship_test<std::weak_ordering>(sm1, s1, s2);
440-
spaceship_test<std::weak_ordering>(sm1, s1.c_str(), s2.c_str());
441-
spaceship_test<std::weak_ordering>(sm3, 'c', 'm');
442-
spaceship_test<std::weak_ordering>(s1, sm1, sm2);
443-
spaceship_test<std::weak_ordering>(s1.c_str(), sm1, sm2);
444-
spaceship_test<std::weak_ordering>('c', sm3, sm4);
435+
spaceship_test<std::strong_ordering>(sm1, sm1_equal, sm2);
436+
spaceship_test<std::strong_ordering>(sm1, s1, s2);
437+
spaceship_test<std::strong_ordering>(sm1, s1.c_str(), s2.c_str());
438+
spaceship_test<std::strong_ordering>(sm3, 'c', 'm');
439+
spaceship_test<std::strong_ordering>(s1, sm1, sm2);
440+
spaceship_test<std::strong_ordering>(s1.c_str(), sm1, sm2);
441+
spaceship_test<std::strong_ordering>('c', sm3, sm4);
445442

446443
using StronglyOrderedMatch = std::ssub_match;
447444
using WeaklyOrderedMatch = std::sub_match<std::basic_string<WeaklyOrderedChar>::const_iterator>;
448445
using WeaklyOrderdByOmissionMatch =
449446
std::sub_match<std::basic_string<WeaklyOrderedByOmissionChar>::const_iterator>;
450447
using PartiallyOrderedMatch = std::sub_match<std::basic_string<PartiallyOrderedChar>::const_iterator>;
451448

452-
// TRANSITION, std::char_traits<char> doesn't define comparison_category
453-
static_assert(std::is_same_v<SpaceshipType<StronglyOrderedMatch>, std::weak_ordering>);
449+
static_assert(std::is_same_v<SpaceshipType<StronglyOrderedMatch>, std::strong_ordering>);
454450
static_assert(std::is_same_v<SpaceshipType<WeaklyOrderedMatch>, std::weak_ordering>);
455451
static_assert(std::is_same_v<SpaceshipType<WeaklyOrderdByOmissionMatch>, std::weak_ordering>);
456452
static_assert(std::is_same_v<SpaceshipType<PartiallyOrderedMatch>, std::partial_ordering>);
457453
}
454+
{ // char_traits
455+
static_assert(std::is_same_v<std::char_traits<char>::comparison_category, std::strong_ordering>);
456+
#ifdef __cpp_char8_t
457+
static_assert(std::is_same_v<std::char_traits<char8_t>::comparison_category, std::strong_ordering>);
458+
#endif // __cpp_char8_t
459+
static_assert(std::is_same_v<std::char_traits<char16_t>::comparison_category, std::strong_ordering>);
460+
static_assert(std::is_same_v<std::char_traits<char32_t>::comparison_category, std::strong_ordering>);
461+
static_assert(std::is_same_v<std::char_traits<wchar_t>::comparison_category, std::strong_ordering>);
462+
}
463+
{ // Strings library
464+
const std::string a1 = "abcdef";
465+
const std::string a2 = "abcdef";
466+
const std::string a3 = "abcdefg";
467+
const std::string a4 = "abcde";
468+
const std::string a5 = "abddef";
469+
const std::string a6 = "abbdef";
470+
471+
assert((a1 <=> a2) == std::strong_ordering::equivalent);
472+
assert((a1 <=> a3) == std::strong_ordering::less);
473+
assert((a1 <=> a4) == std::strong_ordering::greater);
474+
assert((a1 <=> a5) == std::strong_ordering::less);
475+
assert((a1 <=> a6) == std::strong_ordering::greater);
476+
477+
assert(a1 == a2);
478+
assert(a1 >= a2);
479+
assert(a1 <= a2);
480+
assert(a1 < a3);
481+
assert(a1 <= a3);
482+
assert(a1 != a3);
483+
assert(a1 > a4);
484+
assert(a1 >= a4);
485+
assert(a1 != a4);
486+
assert(a1 < a5);
487+
assert(a1 <= a5);
488+
assert(a1 != a5);
489+
assert(a1 > a6);
490+
assert(a1 >= a6);
491+
assert(a1 != a6);
492+
493+
assert((a1 <=> "aardvark") == std::strong_ordering::greater);
494+
assert((a1 <=> "abcdef") == std::strong_ordering::equivalent);
495+
assert((a1 <=> "zebra") == std::strong_ordering::less);
496+
497+
assert(("aardvark" <=> a1) == std::strong_ordering::less);
498+
assert(("abcdef" <=> a1) == std::strong_ordering::equivalent);
499+
assert(("zebra" <=> a1) == std::strong_ordering::greater);
500+
}
501+
{ // string_view
502+
const std::string_view a1 = "abcdef";
503+
const std::string_view a2 = "abcdef";
504+
const std::string_view a3 = "abcdefg";
505+
const std::string_view a4 = "abcde";
506+
const std::string_view a5 = "abddef";
507+
const std::string_view a6 = "abbdef";
508+
509+
assert((a1 <=> a2) == std::strong_ordering::equivalent);
510+
assert((a1 <=> a3) == std::strong_ordering::less);
511+
assert((a1 <=> a4) == std::strong_ordering::greater);
512+
assert((a1 <=> a5) == std::strong_ordering::less);
513+
assert((a1 <=> a6) == std::strong_ordering::greater);
514+
515+
assert(a1 == a2);
516+
assert(a1 >= a2);
517+
assert(a1 <= a2);
518+
assert(a1 < a3);
519+
assert(a1 <= a3);
520+
assert(a1 != a3);
521+
assert(a1 > a4);
522+
assert(a1 >= a4);
523+
assert(a1 != a4);
524+
assert(a1 < a5);
525+
assert(a1 <= a5);
526+
assert(a1 != a5);
527+
assert(a1 > a6);
528+
assert(a1 >= a6);
529+
assert(a1 != a6);
530+
531+
assert((a1 <=> "aardvark") == std::strong_ordering::greater);
532+
assert((a1 <=> "abcdef") == std::strong_ordering::equivalent);
533+
assert((a1 <=> "zebra") == std::strong_ordering::less);
534+
535+
assert(("aardvark" <=> a1) == std::strong_ordering::less);
536+
assert(("abcdef" <=> a1) == std::strong_ordering::equivalent);
537+
assert(("zebra" <=> a1) == std::strong_ordering::greater);
538+
}
539+
{ // constexpr string_view
540+
constexpr std::string_view a1 = "abcdef";
541+
constexpr std::string_view a2 = "abcdef";
542+
constexpr std::string_view a3 = "abcdefg";
543+
constexpr std::string_view a4 = "abcde";
544+
constexpr std::string_view a5 = "abddef";
545+
constexpr std::string_view a6 = "abbdef";
546+
547+
static_assert((a1 <=> a2) == std::strong_ordering::equivalent);
548+
static_assert((a1 <=> a3) == std::strong_ordering::less);
549+
static_assert((a1 <=> a4) == std::strong_ordering::greater);
550+
static_assert((a1 <=> a5) == std::strong_ordering::less);
551+
static_assert((a1 <=> a6) == std::strong_ordering::greater);
552+
553+
static_assert(a1 == a2);
554+
static_assert(a1 >= a2);
555+
static_assert(a1 <= a2);
556+
static_assert(a1 < a3);
557+
static_assert(a1 <= a3);
558+
static_assert(a1 != a3);
559+
static_assert(a1 > a4);
560+
static_assert(a1 >= a4);
561+
static_assert(a1 != a4);
562+
static_assert(a1 < a5);
563+
static_assert(a1 <= a5);
564+
static_assert(a1 != a5);
565+
static_assert(a1 > a6);
566+
static_assert(a1 >= a6);
567+
static_assert(a1 != a6);
568+
569+
static_assert((a1 <=> "aardvark") == std::strong_ordering::greater);
570+
static_assert((a1 <=> "abcdef") == std::strong_ordering::equivalent);
571+
static_assert((a1 <=> "zebra") == std::strong_ordering::less);
572+
573+
static_assert(("aardvark" <=> a1) == std::strong_ordering::less);
574+
static_assert(("abcdef" <=> a1) == std::strong_ordering::equivalent);
575+
static_assert(("zebra" <=> a1) == std::strong_ordering::greater);
576+
}
458577
{ // Diagnostics Library
459578
diagnostics_test<std::error_code>();
460579
diagnostics_test<std::error_condition>();

0 commit comments

Comments
 (0)