Implement checking of op<=> in the compare test helpers

The operator<=> is only checked if it is implemented.

Task-number: QTBUG-104113
Change-Id: I89396ca5edea7db9e1f9b0459c277cb4268e1f48
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
bb10
Ivan Solovev 2023-05-02 12:33:26 +02:00
parent fe12650e9d
commit 5a28aacd85
1 changed files with 84 additions and 0 deletions

View File

@ -16,12 +16,22 @@
//
#include <QtCore/q20type_traits.h>
#include <QtCore/qxptype_traits.h>
#include <QtTest/qtest.h>
QT_BEGIN_NAMESPACE
namespace QTestPrivate {
#ifdef __cpp_lib_three_way_comparison
template <typename LT, typename RT>
using HasThreeWayComparisonOp = decltype(std::declval<LT>() <=> std::declval<RT>());
template <typename LT, typename RT>
constexpr bool implementsThreeWayComparisonOp_v = qxp::is_detected_v<HasThreeWayComparisonOp,
LT, RT>;
#endif
Q_TESTLIB_EXPORT QByteArray formatTypeWithCRefImpl(QMetaType type, bool isConst,
bool isRef, bool isRvalueRef);
@ -95,6 +105,9 @@ void testEqualityOperatorsCompile()
This function checks that the types \c LeftType and \c RightType properly
define all comparison operators (==, !=, <, >, <=, >=). The checks are
performed for all combinations of cvref-qualified lvalues and rvalues.
If compiled in C++20 mode, also checks \c {operator<=>()} if that is
implemented.
*/
template <typename LeftType, typename RightType = LeftType>
void testAllComparisonOperatorsCompile()
@ -106,6 +119,11 @@ void testAllComparisonOperatorsCompile()
FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, <, bool)
FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, >=, bool)
FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, <=, bool)
#ifdef __cpp_lib_three_way_comparison
if constexpr (implementsThreeWayComparisonOp_v<LeftType, RightType>) {
FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, <=>, std::partial_ordering)
}
#endif
}
#undef CHECK_SINGLE_OPERATOR
@ -127,6 +145,20 @@ void testAllComparisonOperatorsCompile()
Func(std::as_const(Left), std::as_const(Right), Op, Expected); \
/* END */
#ifdef __cpp_lib_three_way_comparison
// Hide the macro under an ifdef, because it otherwise triggers a warning
// in Clang C++17 build.
#define CHECK_RUNTIME_3WAY(Left, Right, Op, Expected) \
do { \
QCOMPARE_EQ((Left <=> Right) Op 0, Expected); \
QCOMPARE_EQ((std::move(Left) <=> Right) Op 0, Expected); \
QCOMPARE_EQ((Left <=> std::move(Right)) Op 0, Expected); \
QCOMPARE_EQ((std::move(Left) <=> std::move(Right)) Op 0, Expected); \
} while (false); \
/* END */
#endif // __cpp_lib_three_way_comparison
/*!
\internal
@ -167,6 +199,9 @@ void testEqualityOperators(LeftType lhs, RightType rhs, bool expectedEqual)
(==, !=, <, >, <=, >=) for the \a lhs operand of type \c {LeftType} and
the \a rhs operand of type \c {RightType}.
If compiled in C++20 mode, also checks \c {operator<=>()} if that is
implemented.
When compiled in C++17 mode, the \c OrderingType must be one of
Qt::partial_ordering, Qt::strong_ordering, or Qt::weak_ordering.
In C++20 mode, also the \c {std::*_ordering} types can be used.
@ -222,6 +257,29 @@ void testAllComparisonOperators(LeftType lhs, RightType rhs, OrderingType expect
!expectedUnordered && (expectedEqual || expectedLess))
CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, >=,
!expectedUnordered && !expectedLess)
#ifdef __cpp_lib_three_way_comparison
if constexpr (implementsThreeWayComparisonOp_v<LeftType, RightType>) {
if constexpr (std::is_convertible_v<OrderingType, std::strong_ordering>)
static_assert(std::is_same_v<decltype(lhs <=> rhs), std::strong_ordering>);
else if constexpr (std::is_convertible_v<OrderingType, std::weak_ordering>)
static_assert(std::is_same_v<decltype(lhs <=> rhs), std::weak_ordering>);
else
static_assert(std::is_same_v<decltype(lhs <=> rhs), std::partial_ordering>);
CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, ==,
!expectedUnordered && expectedEqual)
CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, !=,
expectedUnordered || !expectedEqual)
CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, <,
!expectedUnordered && expectedLess)
CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, >,
!expectedUnordered && !expectedLess && !expectedEqual)
CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, <=,
!expectedUnordered && (expectedEqual || expectedLess))
CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, >=,
!expectedUnordered && !expectedLess)
}
#endif
if constexpr (!std::is_same_v<LeftType, RightType>) {
CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, ==,
@ -236,9 +294,35 @@ void testAllComparisonOperators(LeftType lhs, RightType rhs, OrderingType expect
!expectedUnordered && !expectedLess)
CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, >=,
!expectedUnordered && (expectedEqual || expectedLess))
#ifdef __cpp_lib_three_way_comparison
if constexpr (implementsThreeWayComparisonOp_v<LeftType, RightType>) {
if constexpr (std::is_convertible_v<OrderingType, std::strong_ordering>)
static_assert(std::is_same_v<decltype(rhs <=> lhs), std::strong_ordering>);
else if constexpr (std::is_convertible_v<OrderingType, std::weak_ordering>)
static_assert(std::is_same_v<decltype(rhs <=> lhs), std::weak_ordering>);
else
static_assert(std::is_same_v<decltype(rhs <=> lhs), std::partial_ordering>);
CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, ==,
!expectedUnordered && expectedEqual)
CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, !=,
expectedUnordered || !expectedEqual)
CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, <,
!expectedUnordered && !expectedLess && !expectedEqual)
CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, >,
!expectedUnordered && expectedLess)
CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, <=,
!expectedUnordered && !expectedLess)
CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, >=,
!expectedUnordered && (expectedEqual || expectedLess))
}
#endif
}
}
#ifdef __cpp_lib_three_way_comparison
#undef CHECK_RUNTIME_3WAY
#endif
#undef CHECK_RUNTIME_CREF
#undef CHECK_RUNTIME_LR