QHash: implement the heterogeneous non-const operator[]

This complements the previous commit by adding the heterogeneous lookup
in operator[]. Unlike the members of the previous commit, this one may
insert into the hash, in which case it needs a way to cast from the
heterogeneous type K to the actual Key type.

Change-Id: I664b9f014ffc48cbb49bfffd17b037c1063dfb91
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
bb10
Thiago Macieira 2024-02-09 14:52:35 -08:00
parent b53c153a10
commit 9a2e21174a
2 changed files with 33 additions and 4 deletions

View File

@ -713,7 +713,7 @@ struct Data
bool initialized;
};
InsertionResult findOrInsert(const Key &key) noexcept
template <typename K> InsertionResult findOrInsert(const K &key) noexcept
{
Bucket it(static_cast<Span *>(nullptr), 0);
if (numBuckets > 0) {
@ -1062,16 +1062,22 @@ public:
}
T &operator[](const Key &key)
{
return operatorIndexImpl(key);
}
private:
template <typename K> T &operatorIndexImpl(const K &key)
{
const auto copy = isDetached() ? QHash() : *this; // keep 'key' alive across the detach
detach();
auto result = d->findOrInsert(key);
Q_ASSERT(!result.it.atEnd());
if (!result.initialized)
Node::createInPlace(result.it.node(), key, T());
Node::createInPlace(result.it.node(), Key(key), T());
return result.it.node()->value;
}
public:
const T operator[](const Key &key) const noexcept
{
return value(key);
@ -1380,6 +1386,10 @@ public:
{
return valueImpl(key, [&] { return defaultValue; });
}
T &operator[](const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
{
return operatorIndexImpl(key);
}
const T operator[](const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
{
return value(key);
@ -1700,18 +1710,24 @@ public:
}
T &operator[](const Key &key)
{
return operatorIndexImpl(key);
}
private:
template <typename K> T &operatorIndexImpl(const K &key)
{
const auto copy = isDetached() ? QMultiHash() : *this; // keep 'key' alive across the detach
detach();
auto result = d->findOrInsert(key);
Q_ASSERT(!result.it.atEnd());
if (!result.initialized) {
Node::createInPlace(result.it.node(), key, T());
Node::createInPlace(result.it.node(), Key(key), T());
++m_size;
}
return result.it.node()->value->value;
}
public:
const T operator[](const Key &key) const noexcept
{
return value(key);
@ -2341,6 +2357,10 @@ public:
{
return valueImpl(key, [&] { return defaultValue; });
}
T &operator[](const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
{
return operatorIndexImpl(key);
}
const T operator[](const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
{
return value(key);

View File

@ -1262,6 +1262,15 @@ static void heterogeneousSearchTest(const QList<std::remove_const_t<String>> &ke
std::make_pair(hash.constEnd(), hash.constEnd()));
Helper::checkCounter();
// non-const versions
QCOMPARE_EQ(hash[keyView], keys.size()); // already there
Helper::checkCounter();
QCOMPARE_EQ(hash[otherKeyView], 0); // inserts
Helper::resetCounter();
hash[otherKeyView] = INT_MAX;
Helper::checkCounter();
if constexpr (IsMultiHash) {
hash.insert(key, keys.size());
QCOMPARE_EQ(hash.count(keyView), 2);
@ -1303,7 +1312,7 @@ static void heterogeneousSearchTest(const QList<std::remove_const_t<String>> &ke
QCOMPARE_EQ(hash.remove(keyView), true);
}
QCOMPARE_EQ(hash.take(otherKeyView), 0);
QCOMPARE_EQ(hash.take(otherKeyView), INT_MAX);
QVERIFY(hash.isEmpty());
Helper::checkCounter();