From 5c808073af5b8f1290602fcccf60666c9a3682f8 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 10 Sep 2020 18:25:02 +0200 Subject: Extend QSequentialIterable and add QAssociativeIterable And add mutable iterators. This requires some refactoring of the existing iterators. Task-number: QTBUG-81716 Change-Id: I61b3a3e8c0df5fd449679257a29d9f0c3d19c4f0 Reviewed-by: Lars Knoll --- .../auto/corelib/kernel/qvariant/tst_qvariant.cpp | 292 +++++++++++++-------- tests/auto/tools/moc/forward-declared-param.h | 2 + 2 files changed, 179 insertions(+), 115 deletions(-) (limited to 'tests') diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index 7be1ea19d7..4190a0cb9f 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -4151,91 +4151,148 @@ struct KeyGetter > }; #endif -void tst_QVariant::iterateContainerElements() +template +void sortIterable(QSequentialIterable *iterable) { -#ifdef Q_COMPILER_RANGE_FOR - -#define TEST_RANGE_FOR(CONTAINER) \ - numSeen = 0; \ - containerIter = intList.begin(); \ - for (QVariant v : listIter) { \ - QVERIFY(ContainerAPI::compare(v, *containerIter)); \ - QVERIFY(ContainerAPI::compare(v, varList.at(numSeen))); \ - ++containerIter; \ - ++numSeen; \ - } \ - QCOMPARE(numSeen, (int)std::distance(intList.begin(), intList.end())); - -#else - -#define TEST_RANGE_FOR(CONTAINER) + std::sort(Iterator(iterable->mutableBegin()), Iterator(iterable->mutableEnd()), + [&](const QVariant &a, const QVariant &b) { + return a.toInt() < b.toInt(); + }); +} -#endif +template +void testSequentialIteration() +{ + int numSeen = 0; + Container sequence; + ContainerAPI::insert(sequence, 1); + ContainerAPI::insert(sequence, 2); + ContainerAPI::insert(sequence, 3); + + QVariant listVariant = QVariant::fromValue(sequence); + QVERIFY(listVariant.canConvert()); + QVariantList varList = listVariant.value(); + QCOMPARE(varList.size(), (int)std::distance(sequence.begin(), sequence.end())); + QSequentialIterable listIter = listVariant.value(); + QCOMPARE(varList.size(), listIter.size()); + + typename Container::iterator containerIter = sequence.begin(); + const typename Container::iterator containerEnd = sequence.end(); + for (int i = 0; i < listIter.size(); ++i, ++containerIter, ++numSeen) + { + QVERIFY(ContainerAPI::compare(listIter.at(i), *containerIter)); + QVERIFY(ContainerAPI::compare(listIter.at(i), varList.at(i))); + } + QCOMPARE(numSeen, (int)std::distance(sequence.begin(), sequence.end())); + QCOMPARE(containerIter, containerEnd); + + containerIter = sequence.begin(); + numSeen = 0; + Q_FOREACH (const QVariant &v, listIter) { + QVERIFY(ContainerAPI::compare(v, *containerIter)); + QVERIFY(ContainerAPI::compare(v, varList.at(numSeen))); + ++containerIter; + ++numSeen; + } + QCOMPARE(numSeen, (int)std::distance(sequence.begin(), sequence.end())); + + numSeen = 0; + containerIter = sequence.begin(); + for (QVariant v : listIter) { + QVERIFY(ContainerAPI::compare(v, *containerIter)); + QVERIFY(ContainerAPI::compare(v, varList.at(numSeen))); + ++containerIter; + ++numSeen; + } + QCOMPARE(numSeen, (int)std::distance(sequence.begin(), sequence.end())); + + auto compareLists = [&]() { + int numSeen = 0; + auto varList = listVariant.value(); + auto varIter = varList.begin(); + for (const QVariant &v : qAsConst(listIter)) { + QVERIFY(ContainerAPI::compare(v, *varIter)); + ++varIter; + ++numSeen; + } + QCOMPARE(varIter, varList.end()); + numSeen = 0; + auto constVarIter = varList.constBegin(); + for (QVariant v : listIter) { + QVERIFY(ContainerAPI::compare(v, *constVarIter)); + ++constVarIter; + ++numSeen; + } + QCOMPARE(numSeen, (int)std::distance(varList.begin(), varList.end())); + }; + compareLists(); + + QVariant first = listIter.at(0); + QVariant second = listIter.at(1); + QVariant third = listIter.at(2); + compareLists(); + listIter.addValue(third); + compareLists(); + listIter.addValue(second); + compareLists(); + listIter.addValue(first); + compareLists(); + + QCOMPARE(listIter.size(), 6); + + if (listIter.canRandomAccessIterate()) + sortIterable(&listIter); + else if (listIter.canReverseIterate()) + sortIterable(&listIter); + else if (listIter.canForwardIterate()) + return; // std::sort cannot sort with only forward iterators. + else + QFAIL("The container has no meaningful iterators"); + + compareLists(); + QCOMPARE(listIter.size(), 6); + QCOMPARE(listIter.at(0), first); + QCOMPARE(listIter.at(1), first); + QCOMPARE(listIter.at(2), second); + QCOMPARE(listIter.at(3), second); + QCOMPARE(listIter.at(4), third); + QCOMPARE(listIter.at(5), third); + + listIter.removeValue(); + compareLists(); + QCOMPARE(listIter.size(), 5); + QCOMPARE(listIter.at(0), first); + QCOMPARE(listIter.at(1), first); + QCOMPARE(listIter.at(2), second); + QCOMPARE(listIter.at(3), second); + QCOMPARE(listIter.at(4), third); +} -#define TEST_SEQUENTIAL_ITERATION_ON_FULL_NAME(CONTAINER) \ - { \ - int numSeen = 0; \ - CONTAINER intList; \ - ContainerAPI::insert(intList, 1); \ - ContainerAPI::insert(intList, 2); \ - ContainerAPI::insert(intList, 3); \ - \ - QVariant listVariant = QVariant::fromValue(intList); \ - QVERIFY(listVariant.canConvert()); \ - QVariantList varList = listVariant.value(); \ - QCOMPARE(varList.size(), (int)std::distance(intList.begin(), intList.end())); \ - QSequentialIterable listIter = listVariant.value(); \ - QCOMPARE(varList.size(), listIter.size()); \ - \ - CONTAINER::iterator containerIter = intList.begin(); \ - const CONTAINER::iterator containerEnd = intList.end(); \ - for (int i = 0; i < listIter.size(); ++i, ++containerIter, ++numSeen) \ - { \ - QVERIFY(ContainerAPI::compare(listIter.at(i), *containerIter)); \ - QVERIFY(ContainerAPI::compare(listIter.at(i), varList.at(i))); \ - } \ - QCOMPARE(numSeen, (int)std::distance(intList.begin(), intList.end())); \ - QCOMPARE(containerIter, containerEnd); \ - \ - containerIter = intList.begin(); \ - numSeen = 0; \ - Q_FOREACH (const QVariant &v, listIter) { \ - QVERIFY(ContainerAPI::compare(v, *containerIter)); \ - QVERIFY(ContainerAPI::compare(v, varList.at(numSeen))); \ - ++containerIter; \ - ++numSeen; \ - } \ - QCOMPARE(numSeen, (int)std::distance(intList.begin(), intList.end())); \ - TEST_RANGE_FOR(CONTAINER) \ - } - -#define TEST_SEQUENTIAL_ITERATION(CONTAINER, VALUE_TYPE) \ - TEST_SEQUENTIAL_ITERATION_ON_FULL_NAME(CONTAINER ) - - - TEST_SEQUENTIAL_ITERATION(QQueue, int) - TEST_SEQUENTIAL_ITERATION(QQueue, QVariant) - TEST_SEQUENTIAL_ITERATION(QQueue, QString) - TEST_SEQUENTIAL_ITERATION(QList, int) - TEST_SEQUENTIAL_ITERATION(QList, QVariant) - TEST_SEQUENTIAL_ITERATION(QList, QString) - TEST_SEQUENTIAL_ITERATION(QList, QByteArray) - TEST_SEQUENTIAL_ITERATION(QStack, int) - TEST_SEQUENTIAL_ITERATION(QStack, QVariant) - TEST_SEQUENTIAL_ITERATION(QStack, QString) - TEST_SEQUENTIAL_ITERATION(std::vector, int) - TEST_SEQUENTIAL_ITERATION(std::vector, QVariant) - TEST_SEQUENTIAL_ITERATION(std::vector, QString) - TEST_SEQUENTIAL_ITERATION(std::list, int) - TEST_SEQUENTIAL_ITERATION(std::list, QVariant) - TEST_SEQUENTIAL_ITERATION(std::list, QString) - TEST_SEQUENTIAL_ITERATION_ON_FULL_NAME(QStringList) - TEST_SEQUENTIAL_ITERATION_ON_FULL_NAME(QByteArrayList) +void tst_QVariant::iterateContainerElements() +{ + testSequentialIteration>(); + testSequentialIteration>(); + testSequentialIteration>(); + testSequentialIteration>(); + testSequentialIteration>(); + testSequentialIteration>(); + testSequentialIteration>(); + testSequentialIteration>(); + testSequentialIteration>(); + testSequentialIteration>(); + testSequentialIteration>(); + testSequentialIteration>(); + testSequentialIteration>(); + testSequentialIteration>(); + testSequentialIteration>(); + testSequentialIteration>(); + testSequentialIteration(); + testSequentialIteration(); #ifdef TEST_FORWARD_LIST - TEST_SEQUENTIAL_ITERATION(std::forward_list, int) - TEST_SEQUENTIAL_ITERATION(std::forward_list, QVariant) - TEST_SEQUENTIAL_ITERATION(std::forward_list, QString) + testSequentialIteration>(); + testSequentialIteration>(); + testSequentialIteration>(); #endif { @@ -4575,37 +4632,42 @@ void tst_QVariant::shouldDeleteVariantDataWorksForAssociative() { QCOMPARE(instanceCount, 0); { - QtMetaTypePrivate::QAssociativeIterableImpl iterator {}; - - iterator._size = [](const void *) {return 1;}; - iterator._metaType_value = QMetaType::fromType(); - iterator._metaType_key = QMetaType::fromType(); - iterator._begin = [](const void *, void **) {}; - iterator._end = [](const void *, void **) {}; - iterator._advance = [](void **, int) {}; - iterator._destroyIter = [](void **){}; - iterator._equalIter = [](void * const *, void * const *){return true; /*all iterators are nullptr*/}; - iterator._destroyIter = [](void **){}; - iterator._find = [](const void *, const void *, void **iterator ) -> void { - (*iterator) = reinterpret_cast(quintptr(42)); + QtMetaContainerPrivate::QMetaAssociationInterface iterator {}; + + iterator.sizeFn = [](const void *) -> qsizetype {return 1;}; + iterator.mappedMetaType = QtPrivate::qMetaTypeInterfaceForType(); + iterator.keyMetaType = QtPrivate::qMetaTypeInterfaceForType(); + iterator.createConstIteratorFn = []( + const void *, QtMetaContainerPrivate::QMetaContainerInterface::Position) -> void * { + return nullptr; + }; + iterator.advanceConstIteratorFn = [](void *, qsizetype) {}; + iterator.destroyConstIteratorFn = [](const void *){}; + iterator.compareConstIteratorFn = [](const void *, const void *) { + return true; /*all iterators are nullptr*/ + }; + iterator.createConstIteratorAtKeyFn = [](const void *, const void *) -> void * { + return reinterpret_cast(quintptr(42)); }; - iterator._getKey = [](void * const *iterator, void *dataPtr) -> void { + iterator.copyConstIteratorFn = [](void *, const void *) {}; + iterator.diffConstIteratorFn = [](const void *, const void *) -> qsizetype { return 0; }; + iterator.keyAtConstIteratorFn = [](const void *iterator, void *dataPtr) -> void { MyType mytype {1, "key"}; - if (reinterpret_cast(*iterator) == 42) { + if (reinterpret_cast(iterator) == 42) { mytype.number = 42; mytype.text = "find_key"; } *static_cast(dataPtr) = mytype; }; - iterator._getValue = [](void * const *iterator, void *dataPtr) -> void { + iterator.mappedAtConstIteratorFn = [](const void *iterator, void *dataPtr) -> void { MyType mytype {2, "value"}; - if (reinterpret_cast(*iterator) == 42) { + if (reinterpret_cast(iterator) == 42) { mytype.number = 42; mytype.text = "find_value"; } *static_cast(dataPtr) = mytype; }; - QAssociativeIterable iterable {iterator}; + QAssociativeIterable iterable(QMetaAssociation(&iterator), nullptr); auto it = iterable.begin(); QVariant value1 = it.key(); QVERIFY(value1.canConvert()); @@ -4695,37 +4757,37 @@ void tst_QVariant::sequentialIterableAppend() { QList container { 1, 2 }; auto variant = QVariant::fromValue(container); - QVERIFY(variant.canConvert()); - auto asIterable = variant.value(); + QVERIFY(variant.canConvert>()); + QSequentialIterable asIterable = variant.value>(); const int i = 3, j = 4; void *mutableIterable = asIterable.mutableIterable(); - asIterable.metaSequence().addValueAtEnd(mutableIterable, &i); - asIterable.metaSequence().addValueAtEnd(mutableIterable, &j); + asIterable.metaContainer().addValueAtEnd(mutableIterable, &i); + asIterable.metaContainer().addValueAtEnd(mutableIterable, &j); QCOMPARE(variant.value>(), QList ({ 1, 2, 3, 4 })); - asIterable.metaSequence().addValueAtBegin(mutableIterable, &i); - asIterable.metaSequence().addValueAtBegin(mutableIterable, &j); + asIterable.metaContainer().addValueAtBegin(mutableIterable, &i); + asIterable.metaContainer().addValueAtBegin(mutableIterable, &j); QCOMPARE(variant.value>(), QList ({ 4, 3, 1, 2, 3, 4 })); - asIterable.metaSequence().removeValueAtBegin(mutableIterable); + asIterable.metaContainer().removeValueAtBegin(mutableIterable); QCOMPARE(variant.value>(), QList ({ 3, 1, 2, 3, 4 })); - asIterable.metaSequence().removeValueAtEnd(mutableIterable); + asIterable.metaContainer().removeValueAtEnd(mutableIterable); QCOMPARE(variant.value>(), QList ({ 3, 1, 2, 3 })); } { QSet container { QByteArray{"hello"}, QByteArray{"world"} }; auto variant = QVariant::fromValue(std::move(container)); - QVERIFY(variant.canConvert()); - auto asIterable = variant.value(); + QVERIFY(variant.canConvert>()); + QSequentialIterable asIterable = variant.value>(); QByteArray qba1 {"goodbye"}; QByteArray qba2 { "moon" }; void *mutableIterable = asIterable.mutableIterable(); - asIterable.metaSequence().addValue(mutableIterable, &qba1); - asIterable.metaSequence().addValue(mutableIterable, &qba2); + asIterable.metaContainer().addValue(mutableIterable, &qba1); + asIterable.metaContainer().addValue(mutableIterable, &qba2); QSet reference { "hello", "world", "goodbye", "moon" }; QCOMPARE(variant.value>(), reference); - asIterable.metaSequence().addValue(mutableIterable, &qba1); - asIterable.metaSequence().addValue(mutableIterable, &qba2); + asIterable.metaContainer().addValue(mutableIterable, &qba1); + asIterable.metaContainer().addValue(mutableIterable, &qba2); QCOMPARE(variant.value>(), reference); } } @@ -4741,8 +4803,8 @@ void tst_QVariant::preferDirectConversionOverInterfaces() calledCorrectConverter = true; return QVariantList {}; }); - QMetaType::registerConverter([](const MyType &) { - return QAssociativeIterableImpl {}; + QMetaType::registerConverter([](const MyType &) { + return QAssociativeIterable {}; }); QMetaType::registerConverter([&calledCorrectConverter](const MyType &) { calledCorrectConverter = true; @@ -4756,7 +4818,7 @@ void tst_QVariant::preferDirectConversionOverInterfaces() QVERIFY(holder.canConvert()); QVERIFY(holder.canConvert()); - QVERIFY(holder.canConvert()); + QVERIFY(holder.canConvert()); QVERIFY(holder.canConvert()); QVERIFY(holder.canConvert()); diff --git a/tests/auto/tools/moc/forward-declared-param.h b/tests/auto/tools/moc/forward-declared-param.h index 484e546482..8438ca9128 100644 --- a/tests/auto/tools/moc/forward-declared-param.h +++ b/tests/auto/tools/moc/forward-declared-param.h @@ -38,6 +38,8 @@ struct ForwardDeclaredParam; template class ForwardDeclaredContainer; struct FullyDefined {}; +inline size_t qHash(const FullyDefined &, size_t seed = 0) { return seed; } +inline bool operator==(const FullyDefined &, const FullyDefined &) { return true; } Q_DECLARE_METATYPE(FullyDefined) class ForwardDeclaredParamClass : public QObject -- cgit v1.2.3