From 96f494bf92d246b741b6ae6261c93ef557ef392b Mon Sep 17 00:00:00 2001 From: Ivan Solovev Date: Wed, 17 May 2023 15:01:58 +0200 Subject: Implement helper Qt::compareThreeWay() function for built-in types The helper function RetType compareThreeWay(const T &left, const T &right) noexcept; is used for C++20-comparison macros. Normally it's the user's responsibility to provide this function as a hidden friend of the class which uses the comparison helper macros. For built-in types we provide the implementation inside the Qt namespace. We have to use custom IsIntegralType trait because libstdc++ only treats __{u}int128_t types as integral when compiling in -std=gnu++XX mode, and we compile Qt in -std=c++XX mode. This patch provides the implementations only for compareThreeWay() overloads, because there is no need to implement comparesEqual() for built-in types. It would just be equivalent to calling operator==(), so the user can do it directly. Task-number: QTBUG-104113 Change-Id: I7b3f395458e1ee4c64f442ad48bbf4fec4c19c52 Reviewed-by: Marc Mutz --- src/corelib/global/qcompare.cpp | 151 ++++++++++++ src/corelib/global/qcomparehelpers.h | 132 ++++++++++ .../corelib/global/qcomparehelpers/CMakeLists.txt | 22 ++ .../global/qcomparehelpers/tst_qcomparehelpers.cpp | 270 ++++++++++++++++++--- 4 files changed, 548 insertions(+), 27 deletions(-) diff --git a/src/corelib/global/qcompare.cpp b/src/corelib/global/qcompare.cpp index 9e4d958d16..9d1273c4e6 100644 --- a/src/corelib/global/qcompare.cpp +++ b/src/corelib/global/qcompare.cpp @@ -1098,4 +1098,155 @@ CHECK(strong, equivalent); Q_DECLARE_EQUALITY_COMPARABLE */ +/*! + \fn template Qt::compareThreeWay(LeftInt lhs, RightInt rhs) + \since 6.7 + \relates + \overload + + Implements three-way comparison of integral types. + + \note This function participates in overload resolution only if both + \c LeftInt and \c RightInt are built-in integral types. + + Returns \c {lhs <=> rhs}, provided \c LeftInt and \c RightInt are built-in + integral types. Unlike \c {operator<=>()}, this function template is also + available in C++17. See + \l {https://en.cppreference.com/w/cpp/language/operator_comparison#Three-way_comparison} + {cppreference} for more details. + + This function can also be used in custom \c {compareThreeWay()} functions, + when ordering members of a custom class represented by built-in types: + + \code + class MyClass { + public: + ... + private: + int value; + ... + friend Qt::strong_ordering + compareThreeWay(const MyClass &lhs, const MyClass &rhs) noexcept + { return Qt::compareThreeWay(lhs.value, rhs.value); } + Q_DECLARE_STRONGLY_ORDERED(MyClass) + }; + \endcode + + Returns an instance of \l Qt::strong_ordering that represents the relation + between \a lhs and \a rhs. +*/ + +/*! + \fn template Qt::compareThreeWay(LeftFloat lhs, RightFloat rhs) + \since 6.7 + \relates + \overload + + Implements three-way comparison of floating point types. + + \note This function participates in overload resolution only if both + \c LeftFloat and \c RightFloat are built-in floating-point types. + + Returns \c {lhs <=> rhs}, provided \c LeftFloat and \c RightFloat are + built-in floating-point types. Unlike \c {operator<=>()}, this function + template is also available in C++17. See + \l {https://en.cppreference.com/w/cpp/language/operator_comparison#Three-way_comparison} + {cppreference} for more details. + + This function can also be used in custom \c {compareThreeWay()} functions, + when ordering members of a custom class represented by built-in types: + + \code + class MyClass { + public: + ... + private: + double value; + ... + friend Qt::partial_ordering + compareThreeWay(const MyClass &lhs, const MyClass &rhs) noexcept + { return Qt::compareThreeWay(lhs.value, rhs.value); } + Q_DECLARE_PARTIALLY_ORDERED(MyClass) + }; + \endcode + + Returns an instance of \l Qt::partial_ordering that represents the relation + between \a lhs and \a rhs. If \a lhs or \a rhs is not a number (NaN), + \l Qt::partial_ordering::unordered is returned. +*/ + +/*! + \fn template Qt::compareThreeWay(IntType lhs, FloatType rhs) + \since 6.7 + \relates + \overload + + Implements three-way comparison of integral and floating point types. + + \note This function participates in overload resolution only if \c IntType + is a built-in integral type and \c FloatType is a built-in floating-point + type. + + This function converts \a lhs to \c FloatType and calls the overload for + floating-point types. + + Returns an instance of \l Qt::partial_ordering that represents the relation + between \a lhs and \a rhs. If \a rhs is not a number (NaN), + \l Qt::partial_ordering::unordered is returned. +*/ + +/*! + \fn template Qt::compareThreeWay(FloatType lhs, IntType rhs) + \since 6.7 + \relates + \overload + + Implements three-way comparison of floating point and integral types. + + \note This function participates in overload resolution only if \c FloatType + is a built-in floating-point type and \c IntType is a built-in integral + type. + + This function converts \a rhs to \c FloatType and calls the overload for + floating-point types. + + Returns an instance of \l Qt::partial_ordering that represents the relation + between \a lhs and \a rhs. If \a lhs is not a number (NaN), + \l Qt::partial_ordering::unordered is returned. +*/ + +/*! + \fn template Qt::compareThreeWay(const LeftType *lhs, const RightType *rhs) + \since 6.7 + \relates + \overload + + Implements three-way comparison of pointers. + + \note This function participates in overload resolution if \c LeftType and + \c RightType are the same type, or base and derived types. It is also used + to compare any pointer to \c {std::nullptr_t}. + + Returns an instance of \l Qt::strong_ordering that represents the relation + between \a lhs and \a rhs. +*/ + +/*! + \fn template Qt::compareThreeWay(Enum lhs, Enum rhs) + \since 6.7 + \relates + \overload + + Implements three-way comparison of enum types. + + \note This function participates in overload resolution only if \c Enum + is an enum type. + + This function converts \c Enum to its underlying type and calls the + overload for integral types. + + Returns an instance of \l Qt::strong_ordering that represents the relation + between \a lhs and \a rhs. +*/ + QT_END_NAMESPACE diff --git a/src/corelib/global/qcomparehelpers.h b/src/corelib/global/qcomparehelpers.h index f445e29b00..d0991e91b3 100644 --- a/src/corelib/global/qcomparehelpers.h +++ b/src/corelib/global/qcomparehelpers.h @@ -15,11 +15,15 @@ #endif #include +#include +#include #ifdef __cpp_lib_three_way_comparison #include #endif +#include // std::less + QT_BEGIN_NAMESPACE /* @@ -302,6 +306,134 @@ QT_BEGIN_NAMESPACE #define Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(...) \ QT_OVERLOADED_MACRO(QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE, __VA_ARGS__) +namespace QtPrivate { + +template +constexpr bool IsIntegralType_v = std::numeric_limits>::is_specialized + && std::numeric_limits>::is_integer; + +} // namespace QtPrivate + +namespace Qt { + +template +using if_integral = + std::enable_if_t> + && QtPrivate::IsIntegralType_v>, + bool>; + +template +using if_floating_point = + std::enable_if_t>, + std::is_floating_point>>, + bool>; + +template +using if_integral_and_floating_point = + std::enable_if_t> + && std::is_floating_point_v>, + bool>; + +template +using if_compatible_pointers = + std::enable_if_t, + std::is_base_of, + std::is_base_of>, + bool>; + +template +using if_enum = std::enable_if_t, bool>; + +template = true> +constexpr Qt::strong_ordering compareThreeWay(LeftInt lhs, RightInt rhs) noexcept +{ + static_assert(std::is_signed_v == std::is_signed_v, + "Qt::compareThreeWay() does not allow mixed-sign comparison."); + +#ifdef __cpp_lib_three_way_comparison + return lhs <=> rhs; +#else + if (lhs == rhs) + return Qt::strong_ordering::equivalent; + else if (lhs < rhs) + return Qt::strong_ordering::less; + else + return Qt::strong_ordering::greater; +#endif // __cpp_lib_three_way_comparison +} + +template = true> +constexpr Qt::partial_ordering compareThreeWay(LeftFloat lhs, RightFloat rhs) noexcept +{ +QT_WARNING_PUSH +QT_WARNING_DISABLE_FLOAT_COMPARE +#ifdef __cpp_lib_three_way_comparison + return lhs <=> rhs; +#else + if (lhs < rhs) + return Qt::partial_ordering::less; + else if (lhs > rhs) + return Qt::partial_ordering::greater; + else if (lhs == rhs) + return Qt::partial_ordering::equivalent; + else + return Qt::partial_ordering::unordered; +#endif // __cpp_lib_three_way_comparison +QT_WARNING_POP +} + +template = true> +constexpr Qt::partial_ordering compareThreeWay(IntType lhs, FloatType rhs) noexcept +{ + return compareThreeWay(FloatType(lhs), rhs); +} + +template = true> +constexpr Qt::partial_ordering compareThreeWay(FloatType lhs, IntType rhs) noexcept +{ + return compareThreeWay(lhs, FloatType(rhs)); +} + +template = true> +constexpr Qt::strong_ordering compareThreeWay(const LeftType *lhs, const RightType *rhs) noexcept +{ +#ifdef __cpp_lib_three_way_comparison + return std::compare_three_way{}(lhs, rhs); +#else + if (lhs == rhs) + return Qt::strong_ordering::equivalent; + else if (std::less<>{}(lhs, rhs)) + return Qt::strong_ordering::less; + else + return Qt::strong_ordering::greater; +#endif // __cpp_lib_three_way_comparison +} + +template +constexpr Qt::strong_ordering compareThreeWay(const T *lhs, std::nullptr_t rhs) noexcept +{ + return compareThreeWay(lhs, static_cast(rhs)); +} + +template +constexpr Qt::strong_ordering compareThreeWay(std::nullptr_t lhs, const T *rhs) noexcept +{ + return compareThreeWay(static_cast(lhs), rhs); +} + +template = true> +constexpr Qt::strong_ordering compareThreeWay(Enum lhs, Enum rhs) noexcept +{ + return compareThreeWay(qToUnderlying(lhs), qToUnderlying(rhs)); +} + +} // namespace Qt + QT_END_NAMESPACE #endif // QCOMPAREHELPERS_H diff --git a/tests/auto/corelib/global/qcomparehelpers/CMakeLists.txt b/tests/auto/corelib/global/qcomparehelpers/CMakeLists.txt index ab0620e8b1..4647bb5c7b 100644 --- a/tests/auto/corelib/global/qcomparehelpers/CMakeLists.txt +++ b/tests/auto/corelib/global/qcomparehelpers/CMakeLists.txt @@ -7,3 +7,25 @@ qt_internal_add_test(tst_qcomparehelpers LIBRARIES Qt::TestPrivate ) + +# CMake recognizes CXX_STANDARD=23 only starting from version 3.20 +# macOS has some issues with concepts, see QTBUG-117765 +if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20" AND NOT MACOS) + qt_internal_add_test(tst_qcomparehelpers_cpp23 + SOURCES + tst_qcomparehelpers.cpp + DEFINES + tst_QCompareHelpers=tst_QCompareHelpersCpp23 + LIBRARIES + Qt::TestPrivate + ) + + # Try to build this test in C++23 mode to test std::float16_t support. + # Use CXX_STANDARD_REQUIRED OFF, so that we just fall back to C++17 if the + # compiler does not support C++23. + set_target_properties(tst_qcomparehelpers_cpp23 + PROPERTIES + CXX_STANDARD 23 + CXX_STANDARD_REQUIRED OFF + ) +endif() diff --git a/tests/auto/corelib/global/qcomparehelpers/tst_qcomparehelpers.cpp b/tests/auto/corelib/global/qcomparehelpers/tst_qcomparehelpers.cpp index e3810f8605..995418780a 100644 --- a/tests/auto/corelib/global/qcomparehelpers/tst_qcomparehelpers.cpp +++ b/tests/auto/corelib/global/qcomparehelpers/tst_qcomparehelpers.cpp @@ -5,6 +5,10 @@ #include #include +#if defined(__STDCPP_FLOAT16_T__) && __has_include() +#include +#endif + class IntWrapper { public: @@ -21,13 +25,7 @@ private: friend Qt::strong_ordering compareThreeWay(const IntWrapper &lhs, const IntWrapper &rhs) noexcept { - // ### Qt::compareThreeWay - if (lhs.m_val < rhs.m_val) - return Qt::strong_ordering::less; - else if (lhs.m_val > rhs.m_val) - return Qt::strong_ordering::greater; - else - return Qt::strong_ordering::equal; + return Qt::compareThreeWay(lhs.m_val, rhs.m_val); } friend bool comparesEqual(const IntWrapper &lhs, int rhs) noexcept { return lhs.m_val == rhs; } @@ -52,16 +50,7 @@ private: friend Qt::partial_ordering compareThreeWay(const DoubleWrapper &lhs, const DoubleWrapper &rhs) noexcept { - // ### Qt::compareThreeWay - if (qIsNaN(lhs.m_val) || qIsNaN(rhs.m_val)) - return Qt::partial_ordering::unordered; - - if (lhs.m_val < rhs.m_val) - return Qt::partial_ordering::less; - else if (lhs.m_val > rhs.m_val) - return Qt::partial_ordering::greater; - else - return Qt::partial_ordering::equivalent; + return Qt::compareThreeWay(lhs.m_val, rhs.m_val); } friend bool comparesEqual(const DoubleWrapper &lhs, const IntWrapper &rhs) noexcept { return comparesEqual(lhs, DoubleWrapper(rhs.value())); } @@ -72,16 +61,7 @@ private: { return lhs.m_val == rhs; } friend Qt::partial_ordering compareThreeWay(const DoubleWrapper &lhs, double rhs) noexcept { - // ### Qt::compareThreeWay - if (qIsNaN(lhs.m_val) || qIsNaN(rhs)) - return Qt::partial_ordering::unordered; - - if (lhs.m_val < rhs) - return Qt::partial_ordering::less; - else if (lhs.m_val > rhs) - return Qt::partial_ordering::greater; - else - return Qt::partial_ordering::equivalent; + return Qt::compareThreeWay(lhs.m_val, rhs); } Q_DECLARE_PARTIALLY_ORDERED(DoubleWrapper) @@ -210,6 +190,8 @@ private slots: { compareImpl, QAnyStringView, Qt::weak_ordering>(); } void generatedClasses(); + + void builtinOrder(); }; template @@ -487,5 +469,239 @@ void tst_QCompareHelpers::generatedClasses() QTestPrivate::testEqualityOperatorsCompile(); } +template = true> +void testOrderForTypes() +{ + LeftType l0{0}; + LeftType l1{1}; + RightType r0{0}; + RightType r1{1}; + QCOMPARE_EQ(Qt::compareThreeWay(l0, r1), Qt::strong_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(l1, r0), Qt::strong_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(l1, r1), Qt::strong_ordering::equivalent); + // also swap types + QCOMPARE_EQ(Qt::compareThreeWay(r1, l0), Qt::strong_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(r0, l1), Qt::strong_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(r1, l1), Qt::strong_ordering::equivalent); + +#ifdef __cpp_lib_three_way_comparison + QCOMPARE_EQ(Qt::compareThreeWay(l0, r1), std::strong_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(l1, r0), std::strong_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(l1, r1), std::strong_ordering::equivalent); + + QCOMPARE_EQ(Qt::compareThreeWay(r1, l0), std::strong_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(r0, l1), std::strong_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(r1, l1), std::strong_ordering::equivalent); +#endif // __cpp_lib_three_way_comparison + + if constexpr (std::is_signed_v) { + LeftType lm1{-1}; + QCOMPARE_EQ(Qt::compareThreeWay(lm1, r1), Qt::strong_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(r1, lm1), Qt::strong_ordering::greater); +#ifdef __cpp_lib_three_way_comparison + QCOMPARE_EQ(Qt::compareThreeWay(lm1, r1), std::strong_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(r1, lm1), std::strong_ordering::greater); +#endif // __cpp_lib_three_way_comparison + } + if constexpr (std::is_signed_v) { + RightType rm1{-1}; + QCOMPARE_EQ(Qt::compareThreeWay(rm1, l1), Qt::strong_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(l1, rm1), Qt::strong_ordering::greater); +#ifdef __cpp_lib_three_way_comparison + QCOMPARE_EQ(Qt::compareThreeWay(rm1, l1), std::strong_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(l1, rm1), std::strong_ordering::greater); +#endif // __cpp_lib_three_way_comparison + } +} + +template = true> +void testOrderForTypes() +{ + LeftType lNeg{-1.0}; + LeftType lPos{1.0}; + + RightType rNeg{-1.0}; + RightType rPos{1.0}; + + QCOMPARE_EQ(Qt::compareThreeWay(lNeg, rPos), Qt::partial_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(lPos, rNeg), Qt::partial_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(rNeg, lPos), Qt::partial_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(rPos, lNeg), Qt::partial_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(lNeg, rNeg), Qt::partial_ordering::equivalent); + QCOMPARE_EQ(Qt::compareThreeWay(rNeg, lNeg), Qt::partial_ordering::equivalent); + + LeftType lNaN{std::numeric_limits::quiet_NaN()}; + LeftType lInf{std::numeric_limits::infinity()}; + + RightType rNaN{std::numeric_limits::quiet_NaN()}; + RightType rInf{std::numeric_limits::infinity()}; + + QCOMPARE_EQ(Qt::compareThreeWay(lNaN, rPos), Qt::partial_ordering::unordered); + QCOMPARE_EQ(Qt::compareThreeWay(rNeg, lNaN), Qt::partial_ordering::unordered); + QCOMPARE_EQ(Qt::compareThreeWay(lNeg, rNaN), Qt::partial_ordering::unordered); + QCOMPARE_EQ(Qt::compareThreeWay(rNaN, lPos), Qt::partial_ordering::unordered); + QCOMPARE_EQ(Qt::compareThreeWay(rNaN, lNaN), Qt::partial_ordering::unordered); + QCOMPARE_EQ(Qt::compareThreeWay(lNaN, rNaN), Qt::partial_ordering::unordered); + QCOMPARE_EQ(Qt::compareThreeWay(lNaN, rInf), Qt::partial_ordering::unordered); + QCOMPARE_EQ(Qt::compareThreeWay(rNaN, -lInf), Qt::partial_ordering::unordered); + + QCOMPARE_EQ(Qt::compareThreeWay(lInf, rPos), Qt::partial_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(rPos, lInf), Qt::partial_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(rInf, lNeg), Qt::partial_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(lNeg, rInf), Qt::partial_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(lInf, -rInf), Qt::partial_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(-lInf, rInf), Qt::partial_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(-rInf, lInf), Qt::partial_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(rInf, -lInf), Qt::partial_ordering::greater); + +#ifdef __cpp_lib_three_way_comparison + QCOMPARE_EQ(Qt::compareThreeWay(lNeg, rPos), std::partial_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(lPos, rNeg), std::partial_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(rNeg, lPos), std::partial_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(rPos, lNeg), std::partial_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(lNeg, rNeg), std::partial_ordering::equivalent); + QCOMPARE_EQ(Qt::compareThreeWay(rNeg, lNeg), std::partial_ordering::equivalent); + + QCOMPARE_EQ(Qt::compareThreeWay(lNaN, rPos), std::partial_ordering::unordered); + QCOMPARE_EQ(Qt::compareThreeWay(rNeg, lNaN), std::partial_ordering::unordered); + QCOMPARE_EQ(Qt::compareThreeWay(lNeg, rNaN), std::partial_ordering::unordered); + QCOMPARE_EQ(Qt::compareThreeWay(rNaN, lPos), std::partial_ordering::unordered); + QCOMPARE_EQ(Qt::compareThreeWay(rNaN, lNaN), std::partial_ordering::unordered); + QCOMPARE_EQ(Qt::compareThreeWay(lNaN, rNaN), std::partial_ordering::unordered); + QCOMPARE_EQ(Qt::compareThreeWay(lNaN, rInf), std::partial_ordering::unordered); + QCOMPARE_EQ(Qt::compareThreeWay(rNaN, -lInf), std::partial_ordering::unordered); + + QCOMPARE_EQ(Qt::compareThreeWay(lInf, rPos), std::partial_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(rPos, lInf), std::partial_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(rInf, lNeg), std::partial_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(lNeg, rInf), std::partial_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(lInf, -rInf), std::partial_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(-lInf, rInf), std::partial_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(-rInf, lInf), std::partial_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(rInf, -lInf), std::partial_ordering::greater); +#endif // __cpp_lib_three_way_comparison +} + +template = true> +void testOrderForTypes() +{ + IntType l0{0}; + IntType l1{1}; + + FloatType r0{0.0}; + FloatType r1{1.0}; + FloatType rNaN{std::numeric_limits::quiet_NaN()}; + + QCOMPARE_EQ(Qt::compareThreeWay(l0, r1), Qt::partial_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(l1, r0), Qt::partial_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(r1, l0), Qt::partial_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(r0, l1), Qt::partial_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(l0, r0), Qt::partial_ordering::equivalent); + QCOMPARE_EQ(Qt::compareThreeWay(r0, l0), Qt::partial_ordering::equivalent); + QCOMPARE_EQ(Qt::compareThreeWay(l0, rNaN), Qt::partial_ordering::unordered); + QCOMPARE_EQ(Qt::compareThreeWay(rNaN, l1), Qt::partial_ordering::unordered); +#ifdef __cpp_lib_three_way_comparison + QCOMPARE_EQ(Qt::compareThreeWay(l0, r1), std::partial_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(l1, r0), std::partial_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(r1, l0), std::partial_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(r0, l1), std::partial_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(l0, r0), std::partial_ordering::equivalent); + QCOMPARE_EQ(Qt::compareThreeWay(r0, l0), std::partial_ordering::equivalent); + QCOMPARE_EQ(Qt::compareThreeWay(l0, rNaN), std::partial_ordering::unordered); + QCOMPARE_EQ(Qt::compareThreeWay(rNaN, l1), std::partial_ordering::unordered); +#endif // __cpp_lib_three_way_comparison +} + +enum class TestEnum : quint8 { + Smaller, + Bigger +}; + +void tst_QCompareHelpers::builtinOrder() +{ +#define TEST_BUILTIN(Left, Right) \ + testOrderForTypes(); \ + if (QTest::currentTestFailed()) { \ + qDebug("Failed Qt::compareThreeWay() test for builtin types " #Left " and " #Right); \ + return; \ + } + + // some combinations + TEST_BUILTIN(char, char) +#if CHAR_MIN < 0 + TEST_BUILTIN(char, short) + TEST_BUILTIN(qint8, char) +#else + TEST_BUILTIN(char, ushort) + TEST_BUILTIN(quint8, char) +#endif + TEST_BUILTIN(qint8, qint8) + TEST_BUILTIN(qint8, int) + TEST_BUILTIN(ulong, quint8) + TEST_BUILTIN(ushort, uchar) + TEST_BUILTIN(int, int) + TEST_BUILTIN(uint, ulong) + TEST_BUILTIN(long, int) + TEST_BUILTIN(uint, quint64) + TEST_BUILTIN(qint64, short) + TEST_BUILTIN(wchar_t, wchar_t) + TEST_BUILTIN(uint, char16_t) + TEST_BUILTIN(char32_t, char32_t) + TEST_BUILTIN(char32_t, ushort) +#ifdef __cpp_char8_t + TEST_BUILTIN(char8_t, char8_t) + TEST_BUILTIN(char8_t, ushort) + TEST_BUILTIN(char8_t, uint) + TEST_BUILTIN(char8_t, quint64) +#endif // __cpp_char8_t +#ifdef QT_SUPPORTS_INT128 + TEST_BUILTIN(qint128, qint128) + TEST_BUILTIN(quint128, quint128) + TEST_BUILTIN(qint128, int) + TEST_BUILTIN(ushort, quint128) +#endif + TEST_BUILTIN(float, double) + TEST_BUILTIN(double, float) + TEST_BUILTIN(quint64, float) + TEST_BUILTIN(qint64, double) +#ifdef __STDCPP_FLOAT16_T__ + TEST_BUILTIN(std::float16_t, std::float16_t) + TEST_BUILTIN(std::float16_t, double) + TEST_BUILTIN(qint64, std::float16_t) + TEST_BUILTIN(uint, std::float16_t) +#endif + + TEST_BUILTIN(long double, long double) + TEST_BUILTIN(float, long double) + TEST_BUILTIN(double, long double) + TEST_BUILTIN(quint64, long double) + TEST_BUILTIN(ushort, long double) + + QCOMPARE_EQ(Qt::compareThreeWay(TestEnum::Smaller, TestEnum::Bigger), + Qt::strong_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(TestEnum::Bigger, TestEnum::Smaller), + Qt::strong_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(TestEnum::Smaller, TestEnum::Smaller), + Qt::strong_ordering::equivalent); + + std::array arr{1, 0}; + QCOMPARE_EQ(Qt::compareThreeWay(&arr[0], &arr[1]), Qt::strong_ordering::less); + QCOMPARE_EQ(Qt::compareThreeWay(arr.data(), &arr[0]), Qt::strong_ordering::equivalent); + + class Base {}; + class Derived : public Base {}; + + auto b = std::make_unique(); + auto d = std::make_unique(); + QCOMPARE_NE(Qt::compareThreeWay(b.get(), d.get()), Qt::strong_ordering::equivalent); + QCOMPARE_EQ(Qt::compareThreeWay(b.get(), nullptr), Qt::strong_ordering::greater); + QCOMPARE_EQ(Qt::compareThreeWay(nullptr, d.get()), Qt::strong_ordering::less); + +#undef TEST_BUILTIN +} + QTEST_MAIN(tst_QCompareHelpers) #include "tst_qcomparehelpers.moc" -- cgit v1.2.3