diff options
-rw-r--r-- | src/corelib/kernel/qvariant.cpp | 35 | ||||
-rw-r--r-- | src/corelib/kernel/qvariant_p.h | 5 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp | 97 |
3 files changed, 117 insertions, 20 deletions
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 84ad555f34..a1e1c71d12 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -4520,15 +4520,24 @@ QSequentialIterable::const_iterator QSequentialIterable::end() const return it; } +static const QVariant variantFromVariantDataHelper(const QtMetaTypePrivate::VariantData &d) { + QVariant v; + if (d.metaTypeId == qMetaTypeId<QVariant>()) + v = *reinterpret_cast<const QVariant*>(d.data); + else + v = QVariant(d.metaTypeId, d.data, d.flags & ~QVariantConstructionFlags::ShouldDeleteVariantData); + if (d.flags & QVariantConstructionFlags::ShouldDeleteVariantData) + QMetaType::destroy(d.metaTypeId, const_cast<void *>(d.data)); + return v; +} + /*! Returns the element at position \a idx in the container. */ QVariant QSequentialIterable::at(int idx) const { const QtMetaTypePrivate::VariantData d = m_impl.at(idx); - if (d.metaTypeId == qMetaTypeId<QVariant>()) - return *reinterpret_cast<const QVariant*>(d.data); - return QVariant(d.metaTypeId, d.data, d.flags); + return variantFromVariantDataHelper(d); } /*! @@ -4605,9 +4614,7 @@ QSequentialIterable::const_iterator::operator=(const const_iterator &other) const QVariant QSequentialIterable::const_iterator::operator*() const { const QtMetaTypePrivate::VariantData d = m_impl.getCurrent(); - if (d.metaTypeId == qMetaTypeId<QVariant>()) - return *reinterpret_cast<const QVariant*>(d.data); - return QVariant(d.metaTypeId, d.data, d.flags); + return variantFromVariantDataHelper(d); } /*! @@ -4939,10 +4946,7 @@ QAssociativeIterable::const_iterator::operator=(const const_iterator &other) const QVariant QAssociativeIterable::const_iterator::operator*() const { const QtMetaTypePrivate::VariantData d = m_impl.getCurrentValue(); - QVariant v(d.metaTypeId, d.data, d.flags); - if (d.metaTypeId == qMetaTypeId<QVariant>()) - return *reinterpret_cast<const QVariant*>(d.data); - return v; + return variantFromVariantDataHelper(d); } /*! @@ -4951,10 +4955,7 @@ const QVariant QAssociativeIterable::const_iterator::operator*() const const QVariant QAssociativeIterable::const_iterator::key() const { const QtMetaTypePrivate::VariantData d = m_impl.getCurrentKey(); - QVariant v(d.metaTypeId, d.data, d.flags); - if (d.metaTypeId == qMetaTypeId<QVariant>()) - return *reinterpret_cast<const QVariant*>(d.data); - return v; + return variantFromVariantDataHelper(d); } /*! @@ -4962,11 +4963,7 @@ const QVariant QAssociativeIterable::const_iterator::key() const */ const QVariant QAssociativeIterable::const_iterator::value() const { - const QtMetaTypePrivate::VariantData d = m_impl.getCurrentValue(); - QVariant v(d.metaTypeId, d.data, d.flags); - if (d.metaTypeId == qMetaTypeId<QVariant>()) - return *reinterpret_cast<const QVariant*>(d.data); - return v; + return operator*(); } /*! diff --git a/src/corelib/kernel/qvariant_p.h b/src/corelib/kernel/qvariant_p.h index 3d87beac83..b8b63b5e6f 100644 --- a/src/corelib/kernel/qvariant_p.h +++ b/src/corelib/kernel/qvariant_p.h @@ -105,6 +105,11 @@ inline T *v_cast(QVariant::Private *d, T * = nullptr) #endif +enum QVariantConstructionFlags : uint { + Default = 0x0, + PointerType = 0x1, + ShouldDeleteVariantData = 0x2 // only used in Q*Iterable +}; //a simple template that avoids to allocate 2 memory chunks when creating a QVariant template <class T> class QVariantPrivateSharedEx : public QVariant::PrivateShared diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index edb15a8db2..e719871128 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -31,6 +31,7 @@ #include <QtTest/QtTest> #include <qvariant.h> +#include <QtCore/private/qvariant_p.h> #include <qbitarray.h> #include <qbytearraylist.h> #include <qdatetime.h> @@ -276,7 +277,8 @@ private slots: void nullConvert(); void accessSequentialContainerKey(); - + void shouldDeleteVariantDataWorksForSequential(); + void shouldDeleteVariantDataWorksForAssociative(); void fromStdVariant(); void qt4UuidDataStream(); @@ -4990,6 +4992,99 @@ void tst_QVariant::accessSequentialContainerKey() QCOMPARE(nameResult, QStringLiteral("Seven")); } +void tst_QVariant::shouldDeleteVariantDataWorksForSequential() +{ + QCOMPARE(instanceCount, 0); + { + QtMetaTypePrivate::QSequentialIterableImpl iterator {}; + iterator._iteratorCapabilities = QtMetaTypePrivate::RandomAccessCapability | + QtMetaTypePrivate::BiDirectionalCapability | + QtMetaTypePrivate::ForwardCapability; + iterator._metaType_flags = QVariantConstructionFlags::ShouldDeleteVariantData; + + iterator._size = [](const void *) {return 1;}; + iterator._metaType_id = qMetaTypeId<MyType>(); + iterator._moveToBegin = [](const void *, void **) {}; + iterator._moveToEnd = [](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._at = [](const void *, int ) -> void const * { + MyType mytype {1, "eins"}; + return QMetaType::create(qMetaTypeId<MyType>(), &mytype); + }; + iterator._get = [](void * const *, int, uint) -> QtMetaTypePrivate::VariantData { + MyType mytype {2, "zwei"}; + return {qMetaTypeId<MyType>(), QMetaType::create(qMetaTypeId<MyType>(), &mytype), QVariantConstructionFlags::ShouldDeleteVariantData}; + }; + QSequentialIterable iterable {iterator}; + QVariant value1 = iterable.at(0); + QVERIFY(value1.canConvert<MyType>()); + QCOMPARE(value1.value<MyType>().number, 1); + QVariant value2 = *iterable.begin(); + QVERIFY(value2.canConvert<MyType>()); + QCOMPARE(value2.value<MyType>().number, 2); + } + QCOMPARE(instanceCount, 0); +} + +void tst_QVariant::shouldDeleteVariantDataWorksForAssociative() +{ + QCOMPARE(instanceCount, 0); + { + QtMetaTypePrivate::QAssociativeIterableImpl iterator {}; + iterator._metaType_flags_key = QVariantConstructionFlags::ShouldDeleteVariantData; + iterator._metaType_flags_value = QVariantConstructionFlags::ShouldDeleteVariantData; + + iterator._size = [](const void *) {return 1;}; + iterator._metaType_id_value = qMetaTypeId<MyType>(); + iterator._metaType_id_key = qMetaTypeId<MyType>(); + 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<void *>(quintptr(42)); + }; + iterator._getKey = [](void * const *iterator, int, uint) -> QtMetaTypePrivate::VariantData { + MyType mytype {1, "key"}; + if (reinterpret_cast<quintptr>(*iterator) == 42) { + mytype.number = 42; + mytype.text = "find_key"; + } + return {qMetaTypeId<MyType>(), QMetaType::create(qMetaTypeId<MyType>(), &mytype), QVariantConstructionFlags::ShouldDeleteVariantData}; + }; + iterator._getValue = [](void * const *iterator, int, uint) -> QtMetaTypePrivate::VariantData { + MyType mytype {2, "value"}; + if (reinterpret_cast<quintptr>(*iterator) == 42) { + mytype.number = 42; + mytype.text = "find_value"; + } + return {qMetaTypeId<MyType>(), QMetaType::create(qMetaTypeId<MyType>(), &mytype), QVariantConstructionFlags::ShouldDeleteVariantData}; + }; + QAssociativeIterable iterable {iterator}; + auto it = iterable.begin(); + QVariant value1 = it.key(); + QVERIFY(value1.canConvert<MyType>()); + QCOMPARE(value1.value<MyType>().number, 1); + QCOMPARE(value1.value<MyType>().text, "key"); + QVariant value2 = it.value(); + QVERIFY(value2.canConvert<MyType>()); + QCOMPARE(value2.value<MyType>().number, 2); + auto findIt = iterable.find(QVariant::fromValue(MyType {})); + value1 = findIt.key(); + QCOMPARE(value1.value<MyType>().number, 42); + QCOMPARE(value1.value<MyType>().text, "find_key"); + value2 = findIt.value(); + QCOMPARE(value2.value<MyType>().number, 42); + QCOMPARE(value2.value<MyType>().text, "find_value"); + } + QCOMPARE(instanceCount, 0); +} + void tst_QVariant::fromStdVariant() { #if __has_include(<variant>) && __cplusplus >= 201703L |