From 1162b4bfc9149ef50bb39b15ecba5ac6ba158290 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 10 Sep 2020 18:23:23 +0200 Subject: Add a QMetaAssociation This requires refactoring of QMetaSequence, as they share a lot of common functionality. QMetaAssociation provides a low level interface to an associative container. Task-number: QTBUG-81716 Change-Id: I273e00abd82f1549ba8803c323d82aa3a2d12ded Reviewed-by: Lars Knoll --- .../kernel/qmetacontainer/tst_qmetacontainer.cpp | 313 +++++++++++++++++++-- .../auto/corelib/kernel/qvariant/tst_qvariant.cpp | 2 +- 2 files changed, 288 insertions(+), 27 deletions(-) (limited to 'tests/auto/corelib/kernel') diff --git a/tests/auto/corelib/kernel/qmetacontainer/tst_qmetacontainer.cpp b/tests/auto/corelib/kernel/qmetacontainer/tst_qmetacontainer.cpp index c4892de2cc..4bfef31b00 100644 --- a/tests/auto/corelib/kernel/qmetacontainer/tst_qmetacontainer.cpp +++ b/tests/auto/corelib/kernel/qmetacontainer/tst_qmetacontainer.cpp @@ -38,6 +38,7 @@ #include #include #include +#include namespace CheckContainerTraits { @@ -57,12 +58,12 @@ static_assert(QContainerTraits::has_clear_v>); static_assert(QContainerTraits::has_clear_v>); static_assert(QContainerTraits::has_clear_v>); -static_assert(QContainerTraits::has_at_v>); -static_assert(!QContainerTraits::has_at_v>); -static_assert(!QContainerTraits::has_at_v); -static_assert(QContainerTraits::has_at_v>); -static_assert(!QContainerTraits::has_at_v>); -static_assert(!QContainerTraits::has_at_v>); +static_assert(QContainerTraits::has_at_index_v>); +static_assert(!QContainerTraits::has_at_index_v>); +static_assert(!QContainerTraits::has_at_index_v); +static_assert(QContainerTraits::has_at_index_v>); +static_assert(!QContainerTraits::has_at_index_v>); +static_assert(!QContainerTraits::has_at_index_v>); static_assert(QContainerTraits::can_get_at_index_v>); static_assert(!QContainerTraits::can_get_at_index_v>); @@ -127,30 +128,30 @@ static_assert(QContainerTraits::has_const_iterator_v>); static_assert(QContainerTraits::has_const_iterator_v>); static_assert(QContainerTraits::has_const_iterator_v>); -static_assert(QContainerTraits::can_get_at_iterator_v>); -static_assert(QContainerTraits::can_get_at_iterator_v>); -static_assert(!QContainerTraits::can_get_at_iterator_v); -static_assert(QContainerTraits::can_get_at_iterator_v>); -static_assert(QContainerTraits::can_get_at_iterator_v>); -static_assert(QContainerTraits::can_get_at_iterator_v>); - -static_assert(QContainerTraits::can_set_at_iterator_v>); -static_assert(!QContainerTraits::can_set_at_iterator_v>); -static_assert(!QContainerTraits::can_get_at_iterator_v); -static_assert(QContainerTraits::can_set_at_iterator_v>); -static_assert(!QContainerTraits::can_set_at_iterator_v>); -static_assert(QContainerTraits::can_set_at_iterator_v>); - -static_assert(QContainerTraits::can_insert_at_iterator_v>); -static_assert(!QContainerTraits::can_insert_at_iterator_v>); -static_assert(!QContainerTraits::can_insert_at_iterator_v); -static_assert(QContainerTraits::can_insert_at_iterator_v>); -static_assert(!QContainerTraits::can_insert_at_iterator_v>); +static_assert(QContainerTraits::iterator_dereferences_to_value_v>); +static_assert(QContainerTraits::iterator_dereferences_to_value_v>); +static_assert(!QContainerTraits::iterator_dereferences_to_value_v); +static_assert(QContainerTraits::iterator_dereferences_to_value_v>); +static_assert(QContainerTraits::iterator_dereferences_to_value_v>); +static_assert(QContainerTraits::iterator_dereferences_to_value_v>); + +static_assert(QContainerTraits::can_set_value_at_iterator_v>); +static_assert(!QContainerTraits::can_set_value_at_iterator_v>); +static_assert(!QContainerTraits::can_set_value_at_iterator_v); +static_assert(QContainerTraits::can_set_value_at_iterator_v>); +static_assert(!QContainerTraits::can_set_value_at_iterator_v>); +static_assert(QContainerTraits::can_set_value_at_iterator_v>); + +static_assert(QContainerTraits::can_insert_value_at_iterator_v>); +static_assert(!QContainerTraits::can_insert_value_at_iterator_v>); +static_assert(!QContainerTraits::can_insert_value_at_iterator_v); +static_assert(QContainerTraits::can_insert_value_at_iterator_v>); +static_assert(!QContainerTraits::can_insert_value_at_iterator_v>); // The iterator is only a hint, but syntactically indistinguishable from others. // It's explicitly there to be signature compatible with std::vector::insert, though. // Also, inserting into a set is not guaranteed to actually do anything. -static_assert(QContainerTraits::can_insert_at_iterator_v>); +static_assert(QContainerTraits::can_insert_value_at_iterator_v>); static_assert(QContainerTraits::can_erase_at_iterator_v>); static_assert(QContainerTraits::can_erase_at_iterator_v>); @@ -172,10 +173,19 @@ private: std::set stdset; std::forward_list forwardList; + QHash qhash; + QMap qmap; + std::map stdmap; + std::unordered_map stdunorderedmap; + private slots: void init(); void testSequence_data(); void testSequence(); + + void testAssociation_data(); + void testAssociation(); + void cleanup(); }; @@ -192,6 +202,28 @@ void tst_QMetaContainer::init() QMetaSequence::fromContainer>(), QMetaSequence::fromContainer>() }; + qhash = { + { 233, QMetaType() }, + { 11, QMetaType::fromType() }, + { 6626, QMetaType::fromType() } + }; + qmap = { + { "eins", true }, + { "zwei", false }, + { "elfundvierzig", true } + }; + + stdmap = { + { QStringLiteral("dkdkdkd"), 58583 }, + { QStringLiteral("ooo30393"), 12 }, + { QStringLiteral("2dddd30393"), 999999 }, + }; + stdunorderedmap = { + { 11, QMetaAssociation::fromContainer>() }, + { 12, QMetaAssociation::fromContainer>() }, + { 393, QMetaAssociation::fromContainer>() }, + { 293, QMetaAssociation::fromContainer>() } + }; } void tst_QMetaContainer::cleanup() @@ -201,6 +233,10 @@ void tst_QMetaContainer::cleanup() qset.clear(); stdset.clear(); forwardList.clear(); + qhash.clear(); + qmap.clear(); + stdmap.clear(); + stdunorderedmap.clear(); } void tst_QMetaContainer::testSequence_data() @@ -486,5 +522,230 @@ void tst_QMetaContainer::testSequence() metaSequence.destroyConstIterator(constEnd); } +void tst_QMetaContainer::testAssociation_data() +{ + QTest::addColumn("container"); + QTest::addColumn("metaAssociation"); + QTest::addColumn("keyType"); + QTest::addColumn("mappedType"); + QTest::addColumn("hasSize"); + QTest::addColumn("canRemove"); + QTest::addColumn("canSetMapped"); + QTest::addColumn("hasBidirectionalIterator"); + QTest::addColumn("hasRandomAccessIterator"); + + QTest::addRow("QHash") + << static_cast(&qhash) + << QMetaAssociation::fromContainer>() + << QMetaType::fromType() + << QMetaType::fromType() + << true << true << true << false << false; + QTest::addRow("QMap") + << static_cast(&qmap) + << QMetaAssociation::fromContainer>() + << QMetaType::fromType() + << QMetaType::fromType() + << true << true << true << true << false; + QTest::addRow("std::map") + << static_cast(&stdmap) + << QMetaAssociation::fromContainer>() + << QMetaType::fromType() + << QMetaType::fromType() + << true << true << true << true << false; + QTest::addRow("std::unorderedmap") + << static_cast(&stdunorderedmap) + << QMetaAssociation::fromContainer>() + << QMetaType::fromType() + << QMetaType::fromType() + << true << true << true << false << false; + QTest::addRow("QSet") + << static_cast(&qset) + << QMetaAssociation::fromContainer>() + << QMetaType::fromType() + << QMetaType() + << true << true << false << false << false; + QTest::addRow("std::set") + << static_cast(&stdset) + << QMetaAssociation::fromContainer>() + << QMetaType::fromType() + << QMetaType() + << true << true << false << true << false; +} + +void tst_QMetaContainer::testAssociation() +{ + QFETCH(void *, container); + QFETCH(QMetaAssociation, metaAssociation); + QFETCH(QMetaType, keyType); + QFETCH(QMetaType, mappedType); + QFETCH(bool, hasSize); + QFETCH(bool, canRemove); + QFETCH(bool, canSetMapped); + QFETCH(bool, hasBidirectionalIterator); + QFETCH(bool, hasRandomAccessIterator); + + QCOMPARE(metaAssociation.hasSize(), hasSize); + QCOMPARE(metaAssociation.canRemoveKey(), canRemove); + QCOMPARE(metaAssociation.canSetMappedAtKey(), canSetMapped); + QCOMPARE(metaAssociation.canSetMappedAtIterator(), canSetMapped); + + // Apparently implementations can choose to provide "better" iterators than required by the std. + if (hasBidirectionalIterator) + QCOMPARE(metaAssociation.hasBidirectionalIterator(), hasBidirectionalIterator); + if (hasRandomAccessIterator) + QCOMPARE(metaAssociation.hasRandomAccessIterator(), hasRandomAccessIterator); + + QVariant key1(keyType); + QVariant key2(keyType); + QVariant key3(keyType); + + QVariant mapped1(mappedType); + QVariant mapped2(mappedType); + QVariant mapped3(mappedType); + + if (hasSize) { + const qsizetype size = metaAssociation.size(container); + + QVERIFY(metaAssociation.canInsertKey()); + + // var1 is invalid, and our containers do not contain an invalid key so far. + metaAssociation.insertKey(container, key1.constData()); + QCOMPARE(metaAssociation.size(container), size + 1); + metaAssociation.removeKey(container, key1.constData()); + QCOMPARE(metaAssociation.size(container), size); + } else { + metaAssociation.insertKey(container, key1.constData()); + metaAssociation.removeKey(container, key1.constData()); + } + + QVERIFY(metaAssociation.hasIterator()); + QVERIFY(metaAssociation.hasConstIterator()); + QVERIFY(metaAssociation.canGetKeyAtIterator()); + QVERIFY(metaAssociation.canGetKeyAtConstIterator()); + + void *it = metaAssociation.begin(container); + void *end = metaAssociation.end(container); + QVERIFY(it); + QVERIFY(end); + + void *constIt = metaAssociation.constBegin(container); + void *constEnd = metaAssociation.constEnd(container); + QVERIFY(constIt); + QVERIFY(constEnd); + + const qsizetype size = metaAssociation.diffIterator(end, it); + QCOMPARE(size, metaAssociation.diffConstIterator(constEnd, constIt)); + if (hasSize) + QCOMPARE(size, metaAssociation.size(container)); + + qsizetype count = 0; + for (; !metaAssociation.compareIterator(it, end); + metaAssociation.advanceIterator(it, 1), metaAssociation.advanceConstIterator(constIt, 1)) { + metaAssociation.keyAtIterator(it, key1.data()); + metaAssociation.keyAtConstIterator(constIt, key3.data()); + QCOMPARE(key3, key1); + ++count; + } + + QCOMPARE(count, size); + QVERIFY(metaAssociation.compareConstIterator(constIt, constEnd)); + + metaAssociation.destroyIterator(it); + metaAssociation.destroyIterator(end); + metaAssociation.destroyConstIterator(constIt); + metaAssociation.destroyConstIterator(constEnd); + + if (metaAssociation.canSetMappedAtIterator()) { + void *it = metaAssociation.begin(container); + void *end = metaAssociation.end(container); + QVERIFY(it); + QVERIFY(end); + + for (; !metaAssociation.compareIterator(it, end); metaAssociation.advanceIterator(it, 1)) { + metaAssociation.mappedAtIterator(it, mapped1.data()); + metaAssociation.setMappedAtIterator(it, mapped2.constData()); + metaAssociation.mappedAtIterator(it, mapped3.data()); + QCOMPARE(mapped2, mapped3); + mapped2 = mapped1; + } + + metaAssociation.destroyIterator(it); + metaAssociation.destroyIterator(end); + + it = metaAssociation.constBegin(container); + end = metaAssociation.constEnd(container); + QVERIFY(it); + QVERIFY(end); + + for (; !metaAssociation.compareConstIterator(it, end); metaAssociation.advanceConstIterator(it, 1)) { + metaAssociation.mappedAtConstIterator(it, mapped1.data()); + metaAssociation.keyAtConstIterator(it, key1.data()); + metaAssociation.setMappedAtKey(container, key1.constData(), mapped2.constData()); + metaAssociation.mappedAtConstIterator(it, mapped3.data()); + QCOMPARE(mapped2, mapped3); + mapped2 = mapped1; + } + + metaAssociation.destroyConstIterator(it); + metaAssociation.destroyConstIterator(end); + } + + if (metaAssociation.hasBidirectionalIterator()) { + void *it = metaAssociation.end(container); + void *end = metaAssociation.begin(container); + QVERIFY(it); + QVERIFY(end); + + void *constIt = metaAssociation.constEnd(container); + void *constEnd = metaAssociation.constBegin(container); + QVERIFY(constIt); + QVERIFY(constEnd); + + qsizetype size = 0; + if (metaAssociation.hasRandomAccessIterator()) { + size = metaAssociation.diffIterator(end, it); + QCOMPARE(size, metaAssociation.diffConstIterator(constEnd, constIt)); + } else { + size = -metaAssociation.diffIterator(it, end); + } + + if (hasSize) + QCOMPARE(size, -metaAssociation.size(container)); + + qsizetype count = 0; + do { + metaAssociation.advanceIterator(it, -1); + metaAssociation.advanceConstIterator(constIt, -1); + --count; + + metaAssociation.keyAtIterator(it, key1.data()); + metaAssociation.keyAtConstIterator(constIt, key3.data()); + QCOMPARE(key3, key1); + } while (!metaAssociation.compareIterator(it, end)); + + QCOMPARE(count, size); + QVERIFY(metaAssociation.compareConstIterator(constIt, constEnd)); + + metaAssociation.destroyIterator(it); + metaAssociation.destroyIterator(end); + metaAssociation.destroyConstIterator(constIt); + metaAssociation.destroyConstIterator(constEnd); + } + + QVERIFY(metaAssociation.canClear()); + constIt = metaAssociation.constBegin(container); + constEnd = metaAssociation.constEnd(container); + QVERIFY(!metaAssociation.compareConstIterator(constIt, constEnd)); + metaAssociation.destroyConstIterator(constIt); + metaAssociation.destroyConstIterator(constEnd); + + metaAssociation.clear(container); + constIt = metaAssociation.constBegin(container); + constEnd = metaAssociation.constEnd(container); + QVERIFY(metaAssociation.compareConstIterator(constIt, constEnd)); + metaAssociation.destroyConstIterator(constIt); + metaAssociation.destroyConstIterator(constEnd); +} + QTEST_MAIN(tst_QMetaContainer) #include "tst_qmetacontainer.moc" diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index a6c0ecb012..7be1ea19d7 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -4558,7 +4558,7 @@ void tst_QVariant::shouldDeleteVariantDataWorksForSequential() MyType mytype {2, "zwei"}; *static_cast(dataPtr) = mytype; }; - metaSequence.valueMetaType = QMetaType::fromType(); + metaSequence.valueMetaType = QtPrivate::qMetaTypeInterfaceForType(); QSequentialIterable iterable(QMetaSequence(&metaSequence), nullptr); QVariant value1 = iterable.at(0); -- cgit v1.2.3