summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/global/qcompare
diff options
context:
space:
mode:
authorIvan Solovev <ivan.solovev@qt.io>2023-09-29 20:36:31 +0200
committerIvan Solovev <ivan.solovev@qt.io>2023-12-07 23:36:14 +0100
commit3d231e27a8c38f8e840e161e76be3a153d6b0aa9 (patch)
tree4e66c98abd30052ab9672b1696797e63607a4e38 /tests/auto/corelib/global/qcompare
parent7cb25eb33c7875c913b4cb0154afd741e602d8aa (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.cpp113
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"