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 <ulf.hermann@qt.io>
This commit is contained in:
parent
943cb0999d
commit
6db55e3451
@ -1014,6 +1014,24 @@ struct ContainerCapabilitiesImpl<Container, decltype(std::declval<Container>().p
|
||||
{ static_cast<Container *>(const_cast<void *>(container))->push_back(*static_cast<const typename Container::value_type *>(value)); }
|
||||
};
|
||||
|
||||
namespace QtPrivate {
|
||||
namespace ContainerCapabilitiesMetaProgrammingHelper {
|
||||
template<typename... Ts>
|
||||
using void_t = void;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
struct ContainerCapabilitiesImpl<Container, QtPrivate::ContainerCapabilitiesMetaProgrammingHelper::void_t<decltype(std::declval<Container>().insert(std::declval<typename Container::value_type>())), decltype(std::declval<typename Container::value_type>() == std::declval<typename Container::value_type>())>>
|
||||
{
|
||||
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<Container *>(const_cast<void *>(container))->insert(*static_cast<const typename Container::value_type *>(value)); }
|
||||
};
|
||||
|
||||
template<typename T, typename Category = typename std::iterator_traits<typename T::const_iterator>::iterator_category>
|
||||
struct CapabilitiesImpl;
|
||||
|
||||
|
@ -5161,14 +5161,28 @@ void tst_QVariant::sequentialIterableEndianessSanityCheck()
|
||||
|
||||
void tst_QVariant::sequentialIterableAppend()
|
||||
{
|
||||
QVector<int> container {1, 2};
|
||||
auto variant = QVariant::fromValue(container);
|
||||
QVERIFY(variant.canConvert<QtMetaTypePrivate::QSequentialIterableImpl>());
|
||||
auto asIterable = variant.value<QtMetaTypePrivate::QSequentialIterableImpl>();
|
||||
const int i = 3, j = 4;
|
||||
asIterable.append(&i);
|
||||
asIterable.append(&j);
|
||||
QCOMPARE(variant.value<QVector<int>>(), QVector<int> ({1, 2, 3, 4}));
|
||||
{
|
||||
QVector<int> container {1, 2};
|
||||
auto variant = QVariant::fromValue(container);
|
||||
QVERIFY(variant.canConvert<QtMetaTypePrivate::QSequentialIterableImpl>());
|
||||
auto asIterable = variant.value<QtMetaTypePrivate::QSequentialIterableImpl>();
|
||||
const int i = 3, j = 4;
|
||||
asIterable.append(&i);
|
||||
asIterable.append(&j);
|
||||
QCOMPARE(variant.value<QVector<int>>(), QVector<int> ({1, 2, 3, 4}));
|
||||
}
|
||||
{
|
||||
QSet<QByteArray> container { QByteArray{"hello"}, QByteArray{"world"} };
|
||||
auto variant = QVariant::fromValue(std::move(container));
|
||||
QVERIFY(variant.canConvert<QtMetaTypePrivate::QSequentialIterableImpl>());
|
||||
auto asIterable = variant.value<QtMetaTypePrivate::QSequentialIterableImpl>();
|
||||
QByteArray qba1 {"goodbye"};
|
||||
QByteArray qba2 { "moon" };
|
||||
asIterable.append( &qba1 );
|
||||
asIterable.append( &qba2);
|
||||
QSet<QByteArray> reference { "hello", "world", "goodbye", "moon" };
|
||||
QCOMPARE(variant.value<QSet<QByteArray>>(), reference);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QVariant::preferDirectConversionOverInterfaces()
|
||||
|
Loading…
Reference in New Issue
Block a user