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 <thiago.macieira@intel.com>
This commit is contained in:
Ivan Solovev 2024-07-31 15:42:44 +02:00
parent 4f2e95a089
commit f9331bc051
5 changed files with 117 additions and 16 deletions

View File

@ -5,6 +5,7 @@
#ifndef QMAP_H
#define QMAP_H
#include <QtCore/qcompare.h>
#include <QtCore/qhashfunctions.h>
#include <QtCore/qiterator.h>
#include <QtCore/qlist.h>
@ -243,8 +244,10 @@ public:
}
#ifndef Q_QDOC
template <typename AKey = Key, typename AT = T> friend
QTypeTraits::compare_eq_result_container<QMap, AKey, AT> operator==(const QMap &lhs, const QMap &rhs)
private:
template <typename AKey = Key, typename AT = T,
QTypeTraits::compare_eq_result_container<QMap, AKey, AT> = 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 <typename AKey = Key, typename AT = T> friend
QTypeTraits::compare_eq_result_container<QMap, AKey, AT> operator!=(const QMap &lhs, const QMap &rhs)
{
return !(lhs == rhs);
}
QT_DECLARE_EQUALITY_OPERATORS_HELPER(QMap, QMap, /* non-constexpr */, noexcept(false),
template <typename AKey = Key, typename AT = T,
QTypeTraits::compare_eq_result_container<QMap, AKey, AT> = 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 <typename AKey = Key, typename AT = T> friend
QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> operator==(const QMultiMap &lhs, const QMultiMap &rhs)
private:
template <typename AKey = Key, typename AT = T,
QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> = 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 <typename AKey = Key, typename AT = T> friend
QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> operator!=(const QMultiMap &lhs, const QMultiMap &rhs)
{
return !(lhs == rhs);
}
QT_DECLARE_EQUALITY_OPERATORS_HELPER(QMultiMap, QMultiMap, /* non-constexpr */, noexcept(false),
template <typename AKey = Key, typename AT = T,
QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> = 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);

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -7,6 +7,8 @@
#include <QDebug>
#include <QScopeGuard>
#include <private/qcomparisontesthelper_p.h>
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<QMap<int, int>>();
QTestPrivate::testEqualityOperatorsCompile<QMap<QString, QString>>();
QTestPrivate::testEqualityOperatorsCompile<QMap<QString, int>>();
QTestPrivate::testEqualityOperatorsCompile<QMultiMap<int, int>>();
QTestPrivate::testEqualityOperatorsCompile<QMultiMap<QString, QString>>();
QTestPrivate::testEqualityOperatorsCompile<QMultiMap<QString, int>>();
}
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<int, int> a;
QMultiMap<int, int> 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<QString, int> a;
QMultiMap<QString, int> 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);
}
}