Add missing <=> 0 operator to Qt ordering types

It's required by the standard, see e.g. [1] and the eel.is links in
the code.

[ChangeLog][QtCore][QPartialOrdering] Added three-way comparison
operator (<=>) against literal zero, available when compiling in C++20
mode.

[1] https://en.cppreference.com/w/cpp/utility/compare/partial_ordering#Comparisons

Change-Id: I8a3b76661400930c6e247cf5b138ff52bf784395
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
This commit is contained in:
Marc Mutz 2023-11-30 01:38:39 +01:00 committed by Ivan Solovev
parent ccd0dc7f6d
commit c39fff0da5
3 changed files with 130 additions and 0 deletions

View File

@ -47,6 +47,19 @@ enum class Uncomparable : CompareUnderlyingType
} // namespace QtPrivate
namespace QtOrderingPrivate {
template <typename O>
constexpr O reversed(O o) noexcept
{
// https://eel.is/c++draft/cmp.partialord#5
return is_lt(o) ? O::greater :
is_gt(o) ? O::less :
/*else*/ o ;
}
} // namespace QtOrderingPrivate
namespace Qt {
class partial_ordering
@ -107,6 +120,17 @@ public:
{ return rhs.isOrdered() && 0 >= rhs.m_order; }
#ifdef __cpp_lib_three_way_comparison
friend constexpr std::partial_ordering
operator<=>(partial_ordering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept
{ return lhs; } // https://eel.is/c++draft/cmp.partialord#4
friend constexpr std::partial_ordering
operator<=>(QtPrivate::CompareAgainstLiteralZero, partial_ordering rhs) noexcept
{ return QtOrderingPrivate::reversed(rhs); }
#endif // __cpp_lib_three_way_comparison
friend constexpr bool operator==(partial_ordering lhs, partial_ordering rhs) noexcept
{ return lhs.m_order == rhs.m_order; }
@ -253,6 +277,17 @@ public:
{ return 0 >= rhs.m_order; }
#ifdef __cpp_lib_three_way_comparison
friend constexpr std::weak_ordering
operator<=>(weak_ordering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept
{ return lhs; } // https://eel.is/c++draft/cmp.weakord#5
friend constexpr std::weak_ordering
operator<=>(QtPrivate::CompareAgainstLiteralZero, weak_ordering rhs) noexcept
{ return QtOrderingPrivate::reversed(rhs); }
#endif // __cpp_lib_three_way_comparison
friend constexpr bool operator==(weak_ordering lhs, weak_ordering rhs) noexcept
{ return lhs.m_order == rhs.m_order; }
@ -425,6 +460,17 @@ public:
{ return 0 >= rhs.m_order; }
#ifdef __cpp_lib_three_way_comparison
friend constexpr std::strong_ordering
operator<=>(strong_ordering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept
{ return lhs; } // https://eel.is/c++draft/cmp.strongord#6
friend constexpr std::strong_ordering
operator<=>(QtPrivate::CompareAgainstLiteralZero, strong_ordering rhs) noexcept
{ return QtOrderingPrivate::reversed(rhs); }
#endif // __cpp_lib_three_way_comparison
friend constexpr bool operator==(strong_ordering lhs, strong_ordering rhs) noexcept
{ return lhs.m_order == rhs.m_order; }
@ -699,6 +745,17 @@ public:
{ return rhs.isOrdered() && 0 >= rhs.m_order; }
#ifdef __cpp_lib_three_way_comparison
friend constexpr std::partial_ordering
operator<=>(QPartialOrdering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept
{ return lhs; } // https://eel.is/c++draft/cmp.partialord#4
friend constexpr std::partial_ordering
operator<=>(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs) noexcept
{ return QtOrderingPrivate::reversed(rhs); }
#endif // __cpp_lib_three_way_comparison
friend constexpr bool operator==(QPartialOrdering lhs, QPartialOrdering rhs) noexcept
{ return lhs.m_order == rhs.m_order; }

View File

@ -27,6 +27,8 @@
QT_BEGIN_NAMESPACE
class QPartialOrdering;
namespace QtOrderingPrivate {
#ifdef __cpp_lib_three_way_comparison
@ -44,6 +46,9 @@ QT_STD_MAP(weak)
QT_STD_MAP(strong)
#undef QT_STD_MAP
template <> struct StdOrdering<QPartialOrdering> : q20::type_identity<std::partial_ordering> {};
template <> struct QtOrdering<QPartialOrdering> : q20::type_identity< Qt::partial_ordering> {};
template <typename In> constexpr auto to_std(In in) noexcept
-> typename QtOrderingPrivate::StdOrdering<In>::type
{ return in; }

View File

@ -18,6 +18,7 @@ private slots:
void partialOrdering();
void weakOrdering();
void strongOrdering();
void threeWayCompareWithLiteralZero();
void conversions();
void is_eq_overloads();
void compareThreeWay();
@ -500,6 +501,73 @@ void tst_QCompare::strongOrdering()
static_assert(!(0 >= Qt::strong_ordering::greater));
}
void tst_QCompare::threeWayCompareWithLiteralZero()
{
#ifndef __cpp_lib_three_way_comparison
QSKIP("This test requires C++20 <=> support enabled in the compiler and the stdlib.");
#else
// the result of <=> is _always_ a std::_ordering type:
#define CHECK(O) do { \
using StdO = typename QtOrderingPrivate::StdOrdering<O>::type; \
static_assert(std::is_same_v<decltype(0 <=> std::declval<O&>()), StdO>); \
static_assert(std::is_same_v<decltype(std::declval<O&>() <=> 0), StdO>); \
} while (false)
CHECK(Qt::partial_ordering);
CHECK(Qt::weak_ordering);
CHECK(Qt::strong_ordering);
CHECK(QPartialOrdering);
// API symmetry check:
CHECK(std::partial_ordering);
CHECK(std::weak_ordering);
CHECK(std::strong_ordering);
#undef CHECK
#define CHECK(O, what, reversed) do { \
using StdO = typename QtOrderingPrivate::StdOrdering<O>::type; \
static_assert((O :: what <=> 0) == StdO:: what); \
static_assert((0 <=> O :: what) == StdO:: reversed); \
} while (false)
CHECK(Qt::partial_ordering, unordered, unordered);
CHECK(Qt::partial_ordering, equivalent, equivalent);
CHECK(Qt::partial_ordering, less, greater);
CHECK(Qt::partial_ordering, greater, less);
CHECK(Qt::weak_ordering, equivalent, equivalent);
CHECK(Qt::weak_ordering, less, greater);
CHECK(Qt::weak_ordering, greater, less);
CHECK(Qt::strong_ordering, equal, equal);
CHECK(Qt::strong_ordering, less, greater);
CHECK(Qt::strong_ordering, greater, less);
CHECK(QPartialOrdering, unordered, unordered);
CHECK(QPartialOrdering, equivalent, equivalent);
CHECK(QPartialOrdering, less, greater);
CHECK(QPartialOrdering, greater, less);
// API symmetry check:
CHECK(std::partial_ordering, unordered, unordered);
CHECK(std::partial_ordering, equivalent, equivalent);
CHECK(std::partial_ordering, less, greater);
CHECK(std::partial_ordering, greater, less);
CHECK(std::weak_ordering, equivalent, equivalent);
CHECK(std::weak_ordering, less, greater);
CHECK(std::weak_ordering, greater, less);
CHECK(std::strong_ordering, equal, equal);
CHECK(std::strong_ordering, less, greater);
CHECK(std::strong_ordering, greater, less);
#undef CHECK
#endif // __cpp_lib_three_way_comparisons
}
void tst_QCompare::conversions()
{
// Qt::weak_ordering -> Qt::partial_ordering