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 <marc.mutz@qt.io>
bb10
Ivan Solovev 2023-05-17 15:01:58 +02:00
parent 5a28aacd85
commit 96f494bf92
4 changed files with 548 additions and 27 deletions

View File

@ -1098,4 +1098,155 @@ CHECK(strong, equivalent);
Q_DECLARE_EQUALITY_COMPARABLE
*/
/*!
\fn template <typename LeftInt, typename RightInt> Qt::compareThreeWay(LeftInt lhs, RightInt rhs)
\since 6.7
\relates <QtCompare>
\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 <typename LeftFloat, typename RightFloat> Qt::compareThreeWay(LeftFloat lhs, RightFloat rhs)
\since 6.7
\relates <QtCompare>
\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 <typename IntType, typename FloatType> Qt::compareThreeWay(IntType lhs, FloatType rhs)
\since 6.7
\relates <QtCompare>
\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 <typename FloatType, typename IntType> Qt::compareThreeWay(FloatType lhs, IntType rhs)
\since 6.7
\relates <QtCompare>
\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 <typename LeftType, typename RightType> Qt::compareThreeWay(const LeftType *lhs, const RightType *rhs)
\since 6.7
\relates <QtCompare>
\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 <class Enum> Qt::compareThreeWay(Enum lhs, Enum rhs)
\since 6.7
\relates <QtCompare>
\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

View File

@ -15,11 +15,15 @@
#endif
#include <QtCore/qoverload.h>
#include <QtCore/qttypetraits.h>
#include <QtCore/qtypes.h>
#ifdef __cpp_lib_three_way_comparison
#include <compare>
#endif
#include <functional> // 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 <typename T>
constexpr bool IsIntegralType_v = std::numeric_limits<std::remove_const_t<T>>::is_specialized
&& std::numeric_limits<std::remove_const_t<T>>::is_integer;
} // namespace QtPrivate
namespace Qt {
template <typename T, typename U>
using if_integral =
std::enable_if_t<QtPrivate::IsIntegralType_v<std::remove_reference_t<T>>
&& QtPrivate::IsIntegralType_v<std::remove_reference_t<U>>,
bool>;
template <typename T, typename U>
using if_floating_point =
std::enable_if_t<std::conjunction_v<std::is_floating_point<std::remove_reference_t<T>>,
std::is_floating_point<std::remove_reference_t<U>>>,
bool>;
template <typename T, typename U>
using if_integral_and_floating_point =
std::enable_if_t<QtPrivate::IsIntegralType_v<std::remove_reference_t<T>>
&& std::is_floating_point_v<std::remove_reference_t<U>>,
bool>;
template <typename T, typename U>
using if_compatible_pointers =
std::enable_if_t<std::disjunction_v<std::is_same<T, U>,
std::is_base_of<T, U>,
std::is_base_of<U, T>>,
bool>;
template <typename Enum>
using if_enum = std::enable_if_t<std::is_enum_v<Enum>, bool>;
template <typename LeftInt, typename RightInt,
if_integral<LeftInt, RightInt> = true>
constexpr Qt::strong_ordering compareThreeWay(LeftInt lhs, RightInt rhs) noexcept
{
static_assert(std::is_signed_v<LeftInt> == std::is_signed_v<RightInt>,
"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 <typename LeftFloat, typename RightFloat,
if_floating_point<LeftFloat, RightFloat> = 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 <typename IntType, typename FloatType,
if_integral_and_floating_point<IntType, FloatType> = true>
constexpr Qt::partial_ordering compareThreeWay(IntType lhs, FloatType rhs) noexcept
{
return compareThreeWay(FloatType(lhs), rhs);
}
template <typename FloatType, typename IntType,
if_integral_and_floating_point<IntType, FloatType> = true>
constexpr Qt::partial_ordering compareThreeWay(FloatType lhs, IntType rhs) noexcept
{
return compareThreeWay(lhs, FloatType(rhs));
}
template <typename LeftType, typename RightType,
if_compatible_pointers<LeftType, RightType> = 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 <typename T>
constexpr Qt::strong_ordering compareThreeWay(const T *lhs, std::nullptr_t rhs) noexcept
{
return compareThreeWay(lhs, static_cast<const T *>(rhs));
}
template <typename T>
constexpr Qt::strong_ordering compareThreeWay(std::nullptr_t lhs, const T *rhs) noexcept
{
return compareThreeWay(static_cast<const T *>(lhs), rhs);
}
template <class Enum, if_enum<Enum> = 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

View File

@ -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()

View File

@ -5,6 +5,10 @@
#include <QtTest/qtest.h>
#include <QtTest/private/qcomparisontesthelper_p.h>
#if defined(__STDCPP_FLOAT16_T__) && __has_include(<stdfloat>)
#include <stdfloat>
#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<StringWrapper<QString>, QAnyStringView, Qt::weak_ordering>(); }
void generatedClasses();
void builtinOrder();
};
template<typename LeftType, typename RightType, typename OrderingType>
@ -487,5 +469,239 @@ void tst_QCompareHelpers::generatedClasses()
QTestPrivate::testEqualityOperatorsCompile<DummyNone, int>();
}
template <typename LeftType, typename RightType,
Qt::if_integral<LeftType, RightType> = 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>) {
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>) {
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 <typename LeftType, typename RightType,
Qt::if_floating_point<LeftType, RightType> = 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<LeftType>::quiet_NaN()};
LeftType lInf{std::numeric_limits<LeftType>::infinity()};
RightType rNaN{std::numeric_limits<RightType>::quiet_NaN()};
RightType rInf{std::numeric_limits<RightType>::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 <typename IntType, typename FloatType,
Qt::if_integral_and_floating_point<IntType, FloatType> = true>
void testOrderForTypes()
{
IntType l0{0};
IntType l1{1};
FloatType r0{0.0};
FloatType r1{1.0};
FloatType rNaN{std::numeric_limits<FloatType>::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<Left, Right>(); \
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<int, 2> 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<Base>();
auto d = std::make_unique<Derived>();
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"