From f9331bc051cd6bec620e77af8ef3fbd0d14b44ef Mon Sep 17 00:00:00 2001 From: Ivan Solovev Date: Wed, 31 Jul 2024 15:42:44 +0200 Subject: [PATCH] Q(Multi)Map: update (in)equality operators Use comparison helper macros for the inequality operators. Note that we cannot use the "public" macros, because we need to provide attributes for the comparison of the same type, so use the _HELPER macro. Extend the unit tests with the compile-time checks + provide the missing tests for QMultiMap (in)equality operators. Task-number: QTBUG-120305 Change-Id: I0a622cea29079b8437bebc873b7ba97986516eed Reviewed-by: Thiago Macieira --- src/corelib/tools/qmap.h | 33 +++---- src/corelib/tools/qmap.qdoc | 1 + src/corelib/tools/qmultimap.qdoc | 1 + tests/auto/corelib/tools/qmap/CMakeLists.txt | 2 + tests/auto/corelib/tools/qmap/tst_qmap.cpp | 96 ++++++++++++++++++++ 5 files changed, 117 insertions(+), 16 deletions(-) diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index 326ae7d8a51..26a479aafbe 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -5,6 +5,7 @@ #ifndef QMAP_H #define QMAP_H +#include #include #include #include @@ -243,8 +244,10 @@ public: } #ifndef Q_QDOC - template friend - QTypeTraits::compare_eq_result_container operator==(const QMap &lhs, const QMap &rhs) +private: + template = true> + friend bool comparesEqual(const QMap &lhs, const QMap &rhs) { if (lhs.d == rhs.d) return true; @@ -253,13 +256,11 @@ public: Q_ASSERT(lhs.d); return rhs.d ? (lhs.d->m == rhs.d->m) : lhs.d->m.empty(); } - - template friend - QTypeTraits::compare_eq_result_container operator!=(const QMap &lhs, const QMap &rhs) - { - return !(lhs == rhs); - } + QT_DECLARE_EQUALITY_OPERATORS_HELPER(QMap, QMap, /* non-constexpr */, noexcept(false), + template = true>) // TODO: add the other comparison operators; std::map has them. +public: #else friend bool operator==(const QMap &lhs, const QMap &rhs); friend bool operator!=(const QMap &lhs, const QMap &rhs); @@ -914,8 +915,10 @@ public: } #ifndef Q_QDOC - template friend - QTypeTraits::compare_eq_result_container operator==(const QMultiMap &lhs, const QMultiMap &rhs) +private: + template = true> + friend bool comparesEqual(const QMultiMap &lhs, const QMultiMap &rhs) { if (lhs.d == rhs.d) return true; @@ -924,13 +927,11 @@ public: Q_ASSERT(lhs.d); return rhs.d ? (lhs.d->m == rhs.d->m) : lhs.d->m.empty(); } - - template friend - QTypeTraits::compare_eq_result_container operator!=(const QMultiMap &lhs, const QMultiMap &rhs) - { - return !(lhs == rhs); - } + QT_DECLARE_EQUALITY_OPERATORS_HELPER(QMultiMap, QMultiMap, /* non-constexpr */, noexcept(false), + template = true>) // TODO: add the other comparison operators; std::multimap has them. +public: #else friend bool operator==(const QMultiMap &lhs, const QMultiMap &rhs); friend bool operator!=(const QMultiMap &lhs, const QMultiMap &rhs); diff --git a/src/corelib/tools/qmap.qdoc b/src/corelib/tools/qmap.qdoc index 0cabf3df38c..1574fa581e4 100644 --- a/src/corelib/tools/qmap.qdoc +++ b/src/corelib/tools/qmap.qdoc @@ -6,6 +6,7 @@ \class QMap \inmodule QtCore \brief The QMap class is a template class that provides an associative array. + \compares equality \ingroup tools \ingroup shared diff --git a/src/corelib/tools/qmultimap.qdoc b/src/corelib/tools/qmultimap.qdoc index 0b05192817d..63f516bee37 100644 --- a/src/corelib/tools/qmultimap.qdoc +++ b/src/corelib/tools/qmultimap.qdoc @@ -6,6 +6,7 @@ \class QMultiMap \inmodule QtCore \brief The QMultiMap class is a template class that provides an associative array with multiple equivalent keys. + \compares equality \ingroup tools \ingroup shared diff --git a/tests/auto/corelib/tools/qmap/CMakeLists.txt b/tests/auto/corelib/tools/qmap/CMakeLists.txt index bddf9267f86..da1fb366456 100644 --- a/tests/auto/corelib/tools/qmap/CMakeLists.txt +++ b/tests/auto/corelib/tools/qmap/CMakeLists.txt @@ -14,6 +14,8 @@ endif() qt_internal_add_test(tst_qmap SOURCES tst_qmap.cpp + LIBRARIES + Qt::TestPrivate ) qt_internal_undefine_global_definition(tst_qmap QT_NO_JAVA_STYLE_ITERATORS) diff --git a/tests/auto/corelib/tools/qmap/tst_qmap.cpp b/tests/auto/corelib/tools/qmap/tst_qmap.cpp index 6950dcf7056..afed1b53840 100644 --- a/tests/auto/corelib/tools/qmap/tst_qmap.cpp +++ b/tests/auto/corelib/tools/qmap/tst_qmap.cpp @@ -7,6 +7,8 @@ #include #include +#include + using namespace Qt::StringLiterals; QT_WARNING_DISABLE_DEPRECATED @@ -30,6 +32,7 @@ private slots: void swap(); + void comparisonCompiles(); void operator_eq(); void empty(); @@ -632,6 +635,16 @@ void tst_QMap::swap() sanityCheckTree(m2, __LINE__); } +void tst_QMap::comparisonCompiles() +{ + QTestPrivate::testEqualityOperatorsCompile>(); + QTestPrivate::testEqualityOperatorsCompile>(); + QTestPrivate::testEqualityOperatorsCompile>(); + QTestPrivate::testEqualityOperatorsCompile>(); + QTestPrivate::testEqualityOperatorsCompile>(); + QTestPrivate::testEqualityOperatorsCompile>(); +} + void tst_QMap::operator_eq() { { @@ -642,31 +655,37 @@ void tst_QMap::operator_eq() QVERIFY(a == b); QCOMPARE(qHash(a), qHash(b)); QVERIFY(!(a != b)); + QT_TEST_EQUALITY_OPS(a, b, true); a.insert(1,1); b.insert(1,1); QVERIFY(a == b); QCOMPARE(qHash(a), qHash(b)); QVERIFY(!(a != b)); + QT_TEST_EQUALITY_OPS(a, b, true); a.insert(0,1); b.insert(0,1); QVERIFY(a == b); QCOMPARE(qHash(a), qHash(b)); QVERIFY(!(a != b)); + QT_TEST_EQUALITY_OPS(a, b, true); // compare for inequality: a.insert(42,0); QVERIFY(a != b); QVERIFY(!(a == b)); + QT_TEST_EQUALITY_OPS(a, b, false); a.insert(65, -1); QVERIFY(a != b); QVERIFY(!(a == b)); + QT_TEST_EQUALITY_OPS(a, b, false); b.insert(-1, -1); QVERIFY(a != b); QVERIFY(!(a == b)); + QT_TEST_EQUALITY_OPS(a, b, false); } { @@ -677,19 +696,23 @@ void tst_QMap::operator_eq() QVERIFY(a == b); QCOMPARE(qHash(a), qHash(b)); QVERIFY(!(a != b)); + QT_TEST_EQUALITY_OPS(a, b, true); a.insert("Hello", "World"); QVERIFY(a != b); QVERIFY(!(a == b)); + QT_TEST_EQUALITY_OPS(a, b, false); b.insert("Hello", "World"); QVERIFY(a == b); QCOMPARE(qHash(a), qHash(b)); QVERIFY(!(a != b)); + QT_TEST_EQUALITY_OPS(a, b, true); a.insert("Goodbye", "cruel world"); QVERIFY(a != b); QVERIFY(!(a == b)); + QT_TEST_EQUALITY_OPS(a, b, false); b.insert("Goodbye", "cruel world"); @@ -697,12 +720,14 @@ void tst_QMap::operator_eq() a.insert(QString(), QString()); QVERIFY(a != b); QVERIFY(!(a == b)); + QT_TEST_EQUALITY_OPS(a, b, false); // empty keys and null keys match: b.insert(QString(""), QString()); QVERIFY(a == b); QCOMPARE(qHash(a), qHash(b)); QVERIFY(!(a != b)); + QT_TEST_EQUALITY_OPS(a, b, true); } { @@ -713,6 +738,77 @@ void tst_QMap::operator_eq() b.insert("willy", 1); QVERIFY(a != b); QVERIFY(!(a == b)); + QT_TEST_EQUALITY_OPS(a, b, false); + } + + // multimap + { + QMultiMap a; + QMultiMap b; + + QCOMPARE_EQ(a, b); + QT_TEST_EQUALITY_OPS(a, b, true); + + a.insert(1, 1); + b.insert(1, 1); + QCOMPARE_EQ(a, b); + QT_TEST_EQUALITY_OPS(a, b, true); + + a.insert(1, 2); + QCOMPARE_NE(a, b); + QT_TEST_EQUALITY_OPS(a, b, false); + + b.insert(1, 2); + QCOMPARE_EQ(a, b); + QT_TEST_EQUALITY_OPS(a, b, true); + + b.insert(2, 1); + QCOMPARE_NE(a, b); + QT_TEST_EQUALITY_OPS(a, b, false); + + a.insert(2, 2); + QCOMPARE_NE(a, b); + QT_TEST_EQUALITY_OPS(a, b, false); + + a.insert(2, 1); + b.insert(2, 2); + // The insertion order matters! + QCOMPARE_NE(a, b); + QT_TEST_EQUALITY_OPS(a, b, false); + } + { + QMultiMap a; + QMultiMap b; + + QCOMPARE_EQ(a, b); + QT_TEST_EQUALITY_OPS(a, b, true); + + a.insert("Hello", 1); + b.insert("Hello", 1); + QCOMPARE_EQ(a, b); + QT_TEST_EQUALITY_OPS(a, b, true); + + a.insert("Hello", 2); + QCOMPARE_NE(a, b); + QT_TEST_EQUALITY_OPS(a, b, false); + + b.insert("Hello", 2); + QCOMPARE_EQ(a, b); + QT_TEST_EQUALITY_OPS(a, b, true); + + b.insert("World", 1); + QCOMPARE_NE(a, b); + QT_TEST_EQUALITY_OPS(a, b, false); + + a.insert("World", 2); + QCOMPARE_NE(a, b); + QT_TEST_EQUALITY_OPS(a, b, false); + + a.insert("World", 1); + b.insert("World", 2); + // The insertion order matters! + QCOMPARE_NE(a, b); + QT_TEST_EQUALITY_OPS(a, b, false); } }