summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/kernel/qvariant.cpp35
-rw-r--r--src/corelib/kernel/qvariant_p.h5
-rw-r--r--tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp97
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