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
parent
5a28aacd85
commit
96f494bf92
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in New Issue