QMultiHash: add a QHash&& constructor and unite() overload
Reaches into the internals to avoid erasing one entry at a time from the QHash. Change-Id: I47079592d130d2ecd844998dfa31e633e049d4c1 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
f353519e78
commit
d281f5cc35
@ -697,6 +697,7 @@ class QHash
|
||||
using Node = QHashPrivate::Node<Key, T>;
|
||||
using Data = QHashPrivate::Data<Node>;
|
||||
friend class QSet<Key>;
|
||||
friend class QMultiHash<Key, T>;
|
||||
|
||||
Data *d = nullptr;
|
||||
|
||||
@ -1222,6 +1223,11 @@ public:
|
||||
explicit QMultiHash(const QHash<Key, T> &other)
|
||||
: QMultiHash(other.begin(), other.end())
|
||||
{}
|
||||
|
||||
explicit QMultiHash(QHash<Key, T> &&other)
|
||||
{
|
||||
unite(std::move(other));
|
||||
}
|
||||
void swap(QMultiHash &other) noexcept { qSwap(d, other.d); qSwap(m_size, other.m_size); }
|
||||
|
||||
bool operator==(const QMultiHash &other) const noexcept
|
||||
@ -1815,6 +1821,19 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
QMultiHash &unite(QHash<Key, T> &&other)
|
||||
{
|
||||
if (!other.isDetached()) {
|
||||
unite(other);
|
||||
return *this;
|
||||
}
|
||||
auto it = other.d->begin();
|
||||
for (const auto end = other.d->end(); it != end; ++it)
|
||||
emplace(std::move(it.node()->key), std::move(it.node()->takeValue()));
|
||||
other.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
QPair<iterator, iterator> equal_range(const Key &key)
|
||||
{
|
||||
detach();
|
||||
|
@ -55,6 +55,8 @@ private slots:
|
||||
void rehash_isnt_quadratic();
|
||||
void dont_need_default_constructor();
|
||||
void qmultihash_specific();
|
||||
void qmultihash_qhash_rvalue_ref_ctor();
|
||||
void qmultihash_qhash_rvalue_ref_unite();
|
||||
|
||||
void compare();
|
||||
void compare2();
|
||||
@ -1329,6 +1331,117 @@ void tst_QHash::qmultihash_specific()
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QHash::qmultihash_qhash_rvalue_ref_ctor()
|
||||
{
|
||||
// QHash is empty
|
||||
{
|
||||
QHash<int, MyClass> hash;
|
||||
QMultiHash<int, MyClass> multiHash(std::move(hash));
|
||||
QVERIFY(multiHash.isEmpty());
|
||||
}
|
||||
|
||||
// QHash is detached
|
||||
{
|
||||
MyClass::copies = 0;
|
||||
MyClass::moves = 0;
|
||||
QHash<int, MyClass> hash;
|
||||
hash.emplace(0, "a");
|
||||
hash.emplace(1, "b");
|
||||
QMultiHash<int, MyClass> multiHash(std::move(hash));
|
||||
QCOMPARE(multiHash.size(), 2);
|
||||
QCOMPARE(multiHash[0].str, QString("a"));
|
||||
QCOMPARE(multiHash[1].str, QString("b"));
|
||||
QCOMPARE(MyClass::copies, 0);
|
||||
QCOMPARE(MyClass::moves, 2);
|
||||
QCOMPARE(MyClass::count, 2);
|
||||
}
|
||||
|
||||
// QHash is shared
|
||||
{
|
||||
MyClass::copies = 0;
|
||||
MyClass::moves = 0;
|
||||
QHash<int, MyClass> hash;
|
||||
hash.emplace(0, "a");
|
||||
hash.emplace(1, "b");
|
||||
QHash<int, MyClass> hash2(hash);
|
||||
QMultiHash<int, MyClass> multiHash(std::move(hash));
|
||||
QCOMPARE(multiHash.size(), 2);
|
||||
QCOMPARE(multiHash[0].str, QString("a"));
|
||||
QCOMPARE(multiHash[1].str, QString("b"));
|
||||
QCOMPARE(MyClass::copies, 2);
|
||||
QCOMPARE(MyClass::moves, 0);
|
||||
QCOMPARE(MyClass::count, 4);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QHash::qmultihash_qhash_rvalue_ref_unite()
|
||||
{
|
||||
// QHash is empty
|
||||
{
|
||||
QHash<int, MyClass> hash;
|
||||
QMultiHash<int, MyClass> multiHash;
|
||||
multiHash.unite(std::move(hash));
|
||||
QVERIFY(multiHash.isEmpty());
|
||||
}
|
||||
|
||||
// QHash is detached
|
||||
{
|
||||
MyClass::copies = 0;
|
||||
MyClass::moves = 0;
|
||||
QHash<int, MyClass> hash;
|
||||
hash.emplace(0, "a");
|
||||
hash.emplace(1, "b");
|
||||
QMultiHash<int, MyClass> multiHash;
|
||||
multiHash.unite(std::move(hash));
|
||||
QCOMPARE(multiHash.size(), 2);
|
||||
QCOMPARE(multiHash[0].str, QString("a"));
|
||||
QCOMPARE(multiHash[1].str, QString("b"));
|
||||
QCOMPARE(MyClass::copies, 0);
|
||||
QCOMPARE(MyClass::moves, 2);
|
||||
QCOMPARE(MyClass::count, 2);
|
||||
}
|
||||
|
||||
// QHash is shared
|
||||
{
|
||||
MyClass::copies = 0;
|
||||
MyClass::moves = 0;
|
||||
QHash<int, MyClass> hash;
|
||||
hash.emplace(0, "a");
|
||||
hash.emplace(1, "b");
|
||||
QHash<int, MyClass> hash2(hash);
|
||||
QMultiHash<int, MyClass> multiHash;
|
||||
multiHash.unite(std::move(hash));
|
||||
QCOMPARE(multiHash.size(), 2);
|
||||
QCOMPARE(multiHash[0].str, QString("a"));
|
||||
QCOMPARE(multiHash[1].str, QString("b"));
|
||||
QCOMPARE(MyClass::copies, 2);
|
||||
QCOMPARE(MyClass::moves, 0);
|
||||
QCOMPARE(MyClass::count, 4);
|
||||
}
|
||||
|
||||
// QMultiHash already contains an item with the same key
|
||||
{
|
||||
MyClass::copies = 0;
|
||||
MyClass::moves = 0;
|
||||
QHash<int, MyClass> hash;
|
||||
hash.emplace(0, "a");
|
||||
hash.emplace(1, "b");
|
||||
QMultiHash<int, MyClass> multiHash;
|
||||
multiHash.emplace(0, "c");
|
||||
multiHash.unite(std::move(hash));
|
||||
QCOMPARE(multiHash.size(), 3);
|
||||
const auto aRange = multiHash.equal_range(0);
|
||||
QCOMPARE(std::distance(aRange.first, aRange.second), 2);
|
||||
auto it = aRange.first;
|
||||
QCOMPARE(it->str, QString("a"));
|
||||
QCOMPARE((++it)->str, QString("c"));
|
||||
QCOMPARE(multiHash[1].str, QString("b"));
|
||||
QCOMPARE(MyClass::copies, 0);
|
||||
QCOMPARE(MyClass::moves, 2);
|
||||
QCOMPARE(MyClass::count, 3);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
QList<T> sorted(const QList<T> &list)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user