From 217a25a6bf59bb9ce0845267f46244fedd8bcaaa Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 10 Sep 2020 18:30:22 +0200 Subject: QMetaType: Allow registration of mutable views and register iterables In order to modify a container through an iterable, we need the original container to be mutable. The iterable, then, is not a conversion of the container, but rather a view on the container. The concept may be extended to other types. In order to facilitate this, provide a set of methods in QMetaType and QVariant similar to the convert family. The new methods are non-const and expect the original value to stay available during the life time of the view. Change-Id: I363621033f7fc600edcea2acb786820ccba49c86 Reviewed-by: Lars Knoll --- .../auto/corelib/kernel/qvariant/tst_qvariant.cpp | 45 ++++++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) (limited to 'tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp') diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index 4190a0cb9f..8122220b88 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -278,6 +278,7 @@ private slots: void sequentialIterableAppend(); void preferDirectConversionOverInterfaces(); + void mutableView(); private: void dataStream_data(QDataStream::Version version); @@ -4173,7 +4174,7 @@ void testSequentialIteration() QVERIFY(listVariant.canConvert()); QVariantList varList = listVariant.value(); QCOMPARE(varList.size(), (int)std::distance(sequence.begin(), sequence.end())); - QSequentialIterable listIter = listVariant.value(); + QSequentialIterable listIter = listVariant.view(); QCOMPARE(varList.size(), listIter.size()); typename Container::iterator containerIter = sequence.begin(); @@ -4758,7 +4759,7 @@ void tst_QVariant::sequentialIterableAppend() QList container { 1, 2 }; auto variant = QVariant::fromValue(container); QVERIFY(variant.canConvert>()); - QSequentialIterable asIterable = variant.value>(); + QSequentialIterable asIterable = variant.view>(); const int i = 3, j = 4; void *mutableIterable = asIterable.mutableIterable(); asIterable.metaContainer().addValueAtEnd(mutableIterable, &i); @@ -4778,7 +4779,7 @@ void tst_QVariant::sequentialIterableAppend() QSet container { QByteArray{"hello"}, QByteArray{"world"} }; auto variant = QVariant::fromValue(std::move(container)); QVERIFY(variant.canConvert>()); - QSequentialIterable asIterable = variant.value>(); + QSequentialIterable asIterable = variant.view>(); QByteArray qba1 {"goodbye"}; QByteArray qba2 { "moon" }; void *mutableIterable = asIterable.mutableIterable(); @@ -4834,5 +4835,43 @@ void tst_QVariant::preferDirectConversionOverInterfaces() QVERIFY(calledCorrectConverter); } +struct MyTypeView +{ + MyType *data; +}; + +void tst_QVariant::mutableView() +{ + bool calledView = false; + const bool success = QMetaType::registerMutableView([&](MyType &data) { + calledView = true; + return MyTypeView { &data }; + }); + QVERIFY(success); + + QTest::ignoreMessage( + QtWarningMsg, + "Mutable view on type already registered from type MyType to type MyTypeView"); + const bool shouldFail = QMetaType::registerMutableView([&](MyType &) { + return MyTypeView { nullptr }; + }); + QVERIFY(!shouldFail); + + auto original = QVariant::fromValue(MyType {}); + + QVERIFY(original.canView()); + QVERIFY(!original.canConvert()); + + MyTypeView view = original.view(); + QVERIFY(calledView); + const char *txt = "lll"; + view.data->number = 113; + view.data->text = txt; + + MyType extracted = original.view(); + QCOMPARE(extracted.number, 0); + QCOMPARE(extracted.text, nullptr); +} + QTEST_MAIN(tst_QVariant) #include "tst_qvariant.moc" -- cgit v1.2.3