From 6db55e3451e8ba244e9f2555713d44d988977871 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Thu, 12 Mar 2020 16:25:31 +0100 Subject: [PATCH] QSequentialIterable: Treat sets as appendable QSet and std::(unordered_)set were so far not treated as appendable, as they lack a push_back method. We do however need support for this in declarative to enable converting back from QJSValue arrays to sets. We achieve this by testing for and using the insert method. While vector has also such a method, it doesn't take a single value, but rather a position or iterator + value, so the template specialization is not ambiguous. Task-number: QTBUG-82743 Change-Id: I74fc7b1b856d9bcd38100b274ba2b69578ea8bbb Reviewed-by: Ulf Hermann --- src/corelib/kernel/qmetatype.h | 18 +++++++++++ .../corelib/kernel/qvariant/tst_qvariant.cpp | 30 ++++++++++++++----- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index 59ec8de0e9..7c22ff1693 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -1014,6 +1014,24 @@ struct ContainerCapabilitiesImpl().p { static_cast(const_cast(container))->push_back(*static_cast(value)); } }; +namespace QtPrivate { +namespace ContainerCapabilitiesMetaProgrammingHelper { + template + using void_t = void; +} +} + +template +struct ContainerCapabilitiesImpl().insert(std::declval())), decltype(std::declval() == std::declval())>> +{ + enum {ContainerCapabilities = ContainerIsAppendable}; + + // The code below invokes undefined behavior if and only if the pointer passed into QSequentialIterableImpl + // pointed to a const object to begin with + static void appendImpl(const void *container, const void *value) + { static_cast(const_cast(container))->insert(*static_cast(value)); } +}; + template::iterator_category> struct CapabilitiesImpl; diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index 70bda1a0ef..86c61cba12 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -5161,14 +5161,28 @@ void tst_QVariant::sequentialIterableEndianessSanityCheck() void tst_QVariant::sequentialIterableAppend() { - QVector container {1, 2}; - auto variant = QVariant::fromValue(container); - QVERIFY(variant.canConvert()); - auto asIterable = variant.value(); - const int i = 3, j = 4; - asIterable.append(&i); - asIterable.append(&j); - QCOMPARE(variant.value>(), QVector ({1, 2, 3, 4})); + { + QVector container {1, 2}; + auto variant = QVariant::fromValue(container); + QVERIFY(variant.canConvert()); + auto asIterable = variant.value(); + const int i = 3, j = 4; + asIterable.append(&i); + asIterable.append(&j); + QCOMPARE(variant.value>(), QVector ({1, 2, 3, 4})); + } + { + QSet container { QByteArray{"hello"}, QByteArray{"world"} }; + auto variant = QVariant::fromValue(std::move(container)); + QVERIFY(variant.canConvert()); + auto asIterable = variant.value(); + QByteArray qba1 {"goodbye"}; + QByteArray qba2 { "moon" }; + asIterable.append( &qba1 ); + asIterable.append( &qba2); + QSet reference { "hello", "world", "goodbye", "moon" }; + QCOMPARE(variant.value>(), reference); + } } void tst_QVariant::preferDirectConversionOverInterfaces()