QFlatMap: add try_emplace (w/o hint)

QFlatMap, like its public brethren, features the broken Qt-style
insert() behavior (what the STL calls insert_or_assign()), which
makes its insert() unusable for actual STL-style insert() work,
with no replacement except the size-check-and-index-operator trick:

    const auto oldSize = c.size();
    auto &e = c[key];
    if (c.size() != oldSize) {
        // inserted
    }

Even though QFlatMap::insert() appears to return the correct info,
it's useless, because the old value has been assigned over by the
time insert() returns.

Pick-to: 6.3 6.2
Change-Id: If4173c42523a128dfd22ab496dde0089ba73f41c
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
This commit is contained in:
Marc Mutz 2022-01-07 09:44:56 +01:00
parent 5327bae6f0
commit f044664c68
2 changed files with 107 additions and 0 deletions

View File

@ -726,6 +726,30 @@ public:
}
}
template <typename...Args>
std::pair<iterator, bool> try_emplace(const Key &key, Args&&...args)
{
auto it = lower_bound(key);
if (it == end() || key_compare::operator()(key, it.key())) {
c.values.emplace(toValuesIterator(it), std::forward<Args>(args)...);
return { fromKeysIterator(c.keys.insert(toKeysIterator(it), key)), true };
} else {
return {it, false};
}
}
template <typename...Args>
std::pair<iterator, bool> try_emplace(Key &&key, Args&&...args)
{
auto it = lower_bound(key);
if (it == end() || key_compare::operator()(key, it.key())) {
c.values.emplace(toValuesIterator(it), std::forward<Args>(args)...);
return { fromKeysIterator(c.keys.insert(toKeysIterator(it), std::move(key))), true };
} else {
return {it, false};
}
}
template <class InputIt, is_compatible_iterator<InputIt> = nullptr>
void insert(InputIt first, InputIt last)
{

View File

@ -26,6 +26,8 @@
**
****************************************************************************/
#define QT_USE_QSTRINGBUILDER
#include <QTest>
#include <private/qflatmap_p.h>
@ -51,6 +53,7 @@ private slots:
void iterators();
void statefulComparator();
void transparency();
void try_emplace();
void viewIterators();
void varLengthArray();
};
@ -425,6 +428,86 @@ void tst_QFlatMap::transparency()
QCOMPARE(m.lower_bound(sv3).value(), "dree");
}
void tst_QFlatMap::try_emplace()
{
using Map = QFlatMap<QByteArray, QByteArray>;
const QByteArray foo = QByteArrayLiteral("foo");
const qsizetype qqq_1 = 3;
const char qqq_2 = 'q';
const QByteArray qqq = QByteArray(qqq_1, qqq_2);
auto sb = [] (const auto &str) { return str % ""; };
auto rvalue = [](const auto &x) { return x; };
#define lvalue(x) x
#define CHECKS() \
do { \
QVERIFY(!m.try_emplace(rvalue(foo), lvalue(foo)).second); \
QCOMPARE(m.value(foo), qqq); \
QVERIFY(!m.try_emplace(lvalue(foo), lvalue(foo)).second); \
QCOMPARE(m.value(foo), qqq); \
QVERIFY(!m.try_emplace(lvalue(foo), sb(foo)).second); \
QCOMPARE(m.value(foo), qqq); \
QVERIFY(!m.try_emplace(rvalue(foo), sb(foo)).second); \
QCOMPARE(m.value(foo), qqq); \
} while (0) \
/* end */
{
Map m;
QVERIFY(m.try_emplace(lvalue(foo), lvalue(qqq)).second);
CHECKS();
}
{
Map m;
QVERIFY(m.try_emplace(lvalue(foo), rvalue(qqq)).second);
CHECKS();
}
{
Map m;
QVERIFY(m.try_emplace(lvalue(foo), qqq_1, qqq_2).second);
QCOMPARE(m.value(foo), qqq);
CHECKS();
}
{
Map m;
QVERIFY(m.try_emplace(lvalue(foo), sb(qqq)).second);
QCOMPARE(m.value(foo), qqq);
CHECKS();
}
{
Map m;
QVERIFY(m.try_emplace(rvalue(foo), lvalue(qqq)).second);
CHECKS();
}
{
Map m;
QVERIFY(m.try_emplace(rvalue(foo), rvalue(qqq)).second);
CHECKS();
}
{
Map m;
QVERIFY(m.try_emplace(rvalue(foo), qqq_1, qqq_2).second);
QCOMPARE(m.value(foo), qqq);
CHECKS();
}
{
Map m;
QVERIFY(m.try_emplace(rvalue(foo), sb(qqq)).second);
QCOMPARE(m.value(foo), qqq);
CHECKS();
}
#undef CHECKS
#undef lvalue
}
void tst_QFlatMap::viewIterators()
{
using Map = QFlatMap<QByteArray, QByteArray>;