diff options
author | Ivan Solovev <ivan.solovev@qt.io> | 2023-09-29 20:36:31 +0200 |
---|---|---|
committer | Ivan Solovev <ivan.solovev@qt.io> | 2023-12-07 23:36:14 +0100 |
commit | 3d231e27a8c38f8e840e161e76be3a153d6b0aa9 (patch) | |
tree | 4e66c98abd30052ab9672b1696797e63607a4e38 /tests/auto/corelib/global/qcompare | |
parent | 7cb25eb33c7875c913b4cb0154afd741e602d8aa (diff) |
Long live qCompareThreeWay()
qCompareThreeWay() is a top-level wrapper around the helper
three-way comparison methods, which is mostly convenient for
generic client code.
When implementing compareThreeWay() for Qt types, we normally
provide the implementation only for (LeftType, RightType) pair,
but not the reversed one.
However, it is expected that qCompareThreeWay() would be available
for both combinations, because the reversed result can be easily
calculated.
Solve it by providing a helper hasCompareThreeWay<LT, RT> variable
and branching the implementation based on its value.
The noexcept check is inspired by the old implementation of qSwap().
[ChangeLog][QtCore] Added qCompareThreeWay() as a public API for
three-way comparison.
Task-number: QTBUG-104113
Change-Id: I6f24494d968c336f3dcdf620004b4190769cbdb2
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Diffstat (limited to 'tests/auto/corelib/global/qcompare')
-rw-r--r-- | tests/auto/corelib/global/qcompare/tst_qcompare.cpp | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/tests/auto/corelib/global/qcompare/tst_qcompare.cpp b/tests/auto/corelib/global/qcompare/tst_qcompare.cpp index ba382d57fb..f07b2b8910 100644 --- a/tests/auto/corelib/global/qcompare/tst_qcompare.cpp +++ b/tests/auto/corelib/global/qcompare/tst_qcompare.cpp @@ -20,6 +20,7 @@ private slots: void strongOrdering(); void conversions(); void is_eq_overloads(); + void compareThreeWay(); }; void tst_QCompare::legacyPartialOrdering() @@ -647,5 +648,117 @@ void tst_QCompare::is_eq_overloads() #endif // __cpp_lib_three_way_comparison } +class StringWrapper +{ +public: + explicit StringWrapper() {} + explicit StringWrapper(const QString &val) : m_val(val) {} + QString value() const { return m_val; } + +private: + static Qt::weak_ordering compareHelper(const QString &lhs, const QString &rhs) noexcept + { + const int res = QString::compare(lhs, rhs, Qt::CaseInsensitive); + if (res < 0) + return Qt::weak_ordering::less; + else if (res > 0) + return Qt::weak_ordering::greater; + else + return Qt::weak_ordering::equivalent; + } + + friend bool comparesEqual(const StringWrapper &lhs, const StringWrapper &rhs) noexcept + { return QString::compare(lhs.m_val, rhs.m_val, Qt::CaseInsensitive) == 0; } + friend Qt::weak_ordering + compareThreeWay(const StringWrapper &lhs, const StringWrapper &rhs) noexcept + { return compareHelper(lhs.m_val, rhs.m_val); } + Q_DECLARE_WEAKLY_ORDERED(StringWrapper) + + // these helper functions are intentionally non-noexcept + friend bool comparesEqual(const StringWrapper &lhs, int rhs) + { return comparesEqual(lhs, StringWrapper(QString::number(rhs))); } + friend Qt::weak_ordering compareThreeWay(const StringWrapper &lhs, int rhs) + { return compareHelper(lhs.m_val, QString::number(rhs)); } + Q_DECLARE_WEAKLY_ORDERED(StringWrapper, int) + + QString m_val; +}; + +void tst_QCompare::compareThreeWay() +{ + // test noexcept + + // for custom types + static_assert(noexcept(qCompareThreeWay(std::declval<StringWrapper>(), + std::declval<StringWrapper>()))); + static_assert(!noexcept(qCompareThreeWay(std::declval<StringWrapper>(), + std::declval<int>()))); + static_assert(!noexcept(qCompareThreeWay(std::declval<int>(), + std::declval<StringWrapper>()))); + // for built-in types + static_assert(noexcept(qCompareThreeWay(std::declval<int>(), std::declval<int>()))); + static_assert(noexcept(qCompareThreeWay(std::declval<float>(), std::declval<int>()))); + static_assert(noexcept(qCompareThreeWay(std::declval<double>(), std::declval<float>()))); + static_assert(noexcept(qCompareThreeWay(std::declval<int>(), std::declval<int>()))); + + // enums + enum TestEnum : int { + Smaller, + Bigger + }; + static_assert(noexcept(qCompareThreeWay(std::declval<TestEnum>(), std::declval<TestEnum>()))); + + // pointers + static_assert(noexcept(qCompareThreeWay(std::declval<StringWrapper *>(), + std::declval<StringWrapper *>()))); + static_assert(noexcept(qCompareThreeWay(std::declval<StringWrapper *>(), nullptr))); + + // Test some actual comparison results + + // for custom types + QCOMPARE_EQ(qCompareThreeWay(StringWrapper("ABC"), StringWrapper("abc")), + Qt::weak_ordering::equivalent); + QVERIFY(StringWrapper("ABC") == StringWrapper("abc")); + QCOMPARE_EQ(qCompareThreeWay(StringWrapper("ABC"), StringWrapper("qwe")), + Qt::weak_ordering::less); + QVERIFY(StringWrapper("ABC") != StringWrapper("qwe")); + QCOMPARE_EQ(qCompareThreeWay(StringWrapper("qwe"), StringWrapper("ABC")), + Qt::weak_ordering::greater); + QVERIFY(StringWrapper("qwe") != StringWrapper("ABC")); + QCOMPARE_EQ(qCompareThreeWay(StringWrapper("10"), 10), Qt::weak_ordering::equivalent); + QVERIFY(StringWrapper("10") == 10); + QCOMPARE_EQ(qCompareThreeWay(StringWrapper("10"), 12), Qt::weak_ordering::less); + QVERIFY(StringWrapper("10") != 12); + QCOMPARE_EQ(qCompareThreeWay(StringWrapper("12"), 10), Qt::weak_ordering::greater); + QVERIFY(StringWrapper("12") != 10); + + // reversed compareThreeWay() + auto result = qCompareThreeWay(10, StringWrapper("12")); + QCOMPARE_EQ(result, Qt::weak_ordering::less); + static_assert(std::is_same_v<decltype(result), Qt::weak_ordering>); + QVERIFY(10 != StringWrapper("12")); + result = qCompareThreeWay(12, StringWrapper("10")); + QCOMPARE_EQ(result, Qt::weak_ordering::greater); + static_assert(std::is_same_v<decltype(result), Qt::weak_ordering>); + QVERIFY(12 != StringWrapper("10")); + result = qCompareThreeWay(10, StringWrapper("10")); + QCOMPARE_EQ(result, Qt::weak_ordering::equivalent); + static_assert(std::is_same_v<decltype(result), Qt::weak_ordering>); + QVERIFY(10 == StringWrapper("10")); + + // built-in types + QCOMPARE_EQ(qCompareThreeWay(1, 1.0), Qt::partial_ordering::equivalent); + QCOMPARE_EQ(qCompareThreeWay(1, 2), Qt::strong_ordering::less); + QCOMPARE_EQ(qCompareThreeWay(2.0f, 1.0), Qt::partial_ordering::greater); + + // enums + QCOMPARE_EQ(qCompareThreeWay(Smaller, Bigger), Qt::strong_ordering::less); + + // pointers + std::array<int, 2> arr{1, 0}; + QCOMPARE_EQ(qCompareThreeWay(&arr[1], &arr[0]), Qt::strong_ordering::greater); + QCOMPARE_EQ(qCompareThreeWay(arr.data(), &arr[0]), Qt::strong_ordering::equivalent); +} + QTEST_MAIN(tst_QCompare) #include "tst_qcompare.moc" |