summaryrefslogtreecommitdiff
path: root/src/qml/jsruntime/qv4sequenceobject.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-01-07 11:01:56 +0100
committerUlf Hermann <ulf.hermann@qt.io>2022-01-28 15:03:00 +0100
commitb0fc028cb5a5dfa9e95640a32e9b38ca6df0734d (patch)
tree7a446acca0f5bcbe4e62a1ac22bdb0185913bc5a /src/qml/jsruntime/qv4sequenceobject.cpp
parent8c4c0605b077d63e3d73d34ad6dcc4a2cf607b4c (diff)
downloadqtdeclarative-b0fc028cb5a5dfa9e95640a32e9b38ca6df0734d.tar.gz
QML: Allow named lists of value types
We register QList<T> as sequential container type for any value type T we get. This way we can always find a type to use for list<t> with t being a value type. The metatypes are shuffled around so that we have an easier time associating a type with its list and vice versa. As QQmlPropertyData's isQList flag denotes both QQmlListProperty<T> and QList<T> now, we need to use QMetaType::IsQmlList more often. Conversely, any name given to extra sequential containers registered via QML_SEQUENTIAL_CONTAINER is explicitly ignored now. As you can do list<foo> for any type foo now, there is not much of a point in having further named container registrations for the same type. It would just make things more complicated. Mind that the name had already been ignored before, just not explicitly. [ChangeLog][QtQml] You can now use lists of value types in QML. For example a property of type list<int> will hold a list of integers. Task-number: QTBUG-82443 Change-Id: I7bee61cee3963dae5d231bf59f70b8012984371d Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4sequenceobject.cpp')
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp87
1 files changed, 52 insertions, 35 deletions
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 7d4c91bb50..42ad6b8716 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -81,7 +81,7 @@ struct QV4Sequence : Object {
void init(const QQmlType &qmlType, const void *container);
void init(QObject *object, int propertyIndex, const QQmlType &qmlType, bool readOnly);
void destroy() {
- typePrivate->typeId.destroy(container);
+ typePrivate->listId.destroy(container);
QQmlType::derefHandle(typePrivate);
object.destroy();
Object::destroy();
@@ -110,31 +110,41 @@ struct QV4Sequence : public QV4::Object
V4_NEEDS_DESTROY
public:
+ static const QMetaSequence *metaSequence(const Heap::QV4Sequence *p)
+ {
+ return p->typePrivate->extraData.ld;
+ }
+
+ static const QMetaType valueMetaType(const Heap::QV4Sequence *p)
+ {
+ return p->typePrivate->typeId;
+ }
+
qsizetype size() const
{
const auto *p = d();
- return meta(p)->size(p->container);
+ return metaSequence(p)->size(p->container);
}
QVariant at(int index) const
{
const auto *p = d();
- const auto *m = meta(p);
- QVariant result(m->valueMetaType());
- m->valueAtIndex(p->container, index, result.data());
+ QVariant result(valueMetaType(p));
+ metaSequence(p)->valueAtIndex(p->container, index, result.data());
return result;
}
void append(const QVariant &item)
{
const auto *p = d();
- const auto *m = meta(p);
- if (item.metaType() == m->valueMetaType()) {
+ const auto *m = metaSequence(p);
+ const QMetaType v = valueMetaType(p);
+ if (item.metaType() == v) {
m->addValueAtEnd(p->container, item.constData());
} else {
QVariant converted = item;
- if (!converted.convert(m->valueMetaType()))
- converted = QVariant(m->valueMetaType());
+ if (!converted.convert(v))
+ converted = QVariant(v);
m->addValueAtEnd(p->container, converted.constData());
}
}
@@ -142,13 +152,14 @@ public:
void replace(int index, const QVariant &item)
{
const auto *p = d();
- const auto *m = meta(p);
- if (item.metaType() == m->valueMetaType()) {
+ const auto *m = metaSequence(p);
+ const QMetaType v = valueMetaType(p);
+ if (item.metaType() == v) {
m->setValueAtIndex(p->container, index, item.constData());
} else {
QVariant converted = item;
- if (!converted.convert(m->valueMetaType()))
- converted = QVariant(m->valueMetaType());
+ if (!converted.convert(v))
+ converted = QVariant(v);
m->setValueAtIndex(p->container, index, converted.constData());
}
}
@@ -157,9 +168,9 @@ public:
void sort(const Compare &compare)
{
const auto *p = d();
- const auto *m = meta(p);
+ const auto *m = metaSequence(p);
- QSequentialIterable iterable(*m, p->typePrivate->typeId, p->container);
+ QSequentialIterable iterable(*m, p->typePrivate->listId, p->container);
if (iterable.canRandomAccessIterate()) {
std::sort(QSequentialIterable::RandomAccessIterator(iterable.mutableBegin()),
QSequentialIterable::RandomAccessIterator(iterable.mutableEnd()),
@@ -176,7 +187,7 @@ public:
void removeLast(int num)
{
const auto *p = d();
- const auto *m = meta(p);
+ const auto *m = metaSequence(p);
if (m->canEraseRangeAtIterator() && m->hasRandomAccessIterator() && num > 1) {
void *i = m->end(p->container);
@@ -194,7 +205,7 @@ public:
QVariant toVariant()
{
const auto *p = d();
- return QVariant(p->typePrivate->typeId, p->container);
+ return QVariant(p->typePrivate->listId, p->container);
}
// ### Qt 7 use qsizetype instead.
@@ -249,8 +260,8 @@ public:
}
quint32 count = quint32(size());
- const QMetaType valueMetaType = meta(d())->valueMetaType();
- const QVariant element = engine()->toVariant(value, valueMetaType, false);
+ const QMetaType valueType = valueMetaType(d());
+ const QVariant element = engine()->toVariant(value, valueType, false);
if (index == count) {
append(element);
@@ -260,7 +271,7 @@ public:
/* according to ECMA262r3 we need to insert */
/* the value at the given index, increasing length to index+1. */
while (index > count++)
- append(QVariant(valueMetaType));
+ append(QVariant(valueType));
append(element);
}
@@ -471,7 +482,7 @@ void Heap::QV4Sequence::init(const QQmlType &qmlType, const void *container)
typePrivate = qmlType.priv();
QQmlType::refHandle(typePrivate);
- this->container = QMetaType(typePrivate->typeId).create(container);
+ this->container = typePrivate->listId.create(container);
propertyIndex = -1;
isReference = false;
isReadOnly = false;
@@ -490,7 +501,7 @@ void Heap::QV4Sequence::init(QObject *object, int propertyIndex, const QQmlType
Q_ASSERT(qmlType.isSequentialContainer());
typePrivate = qmlType.priv();
QQmlType::refHandle(typePrivate);
- container = QMetaType(typePrivate->typeId).create();
+ container = QMetaType(typePrivate->listId).create();
this->propertyIndex = propertyIndex;
isReference = true;
this->isReadOnly = readOnly;
@@ -571,7 +582,6 @@ static QV4::ReturnedValue method_set_length(const FunctionObject *f, const Value
RETURN_UNDEFINED();
}
-
void SequencePrototype::init()
{
defineDefaultProperty(QStringLiteral("sort"), method_sort, 1);
@@ -612,7 +622,7 @@ ReturnedValue SequencePrototype::newSequence(
// (as well as object ptr + property index for updated-read and write-back)
// and so access/mutate avoids variant conversion.
- const QQmlType qmlType = QQmlMetaType::qmlType(sequenceType);
+ const QQmlType qmlType = QQmlMetaType::qmlListType(sequenceType);
if (qmlType.isSequentialContainer()) {
*succeeded = true;
QV4::ScopedObject obj(scope, engine->memoryManager->allocate<QV4Sequence>(
@@ -638,7 +648,7 @@ ReturnedValue SequencePrototype::fromData(ExecutionEngine *engine, QMetaType typ
// Access and mutation is extremely fast since it will not need to modify any
// QObject property.
- const QQmlType qmlType = QQmlMetaType::qmlType(type);
+ const QQmlType qmlType = QQmlMetaType::qmlListType(type);
if (qmlType.isSequentialContainer()) {
*succeeded = true;
QV4::ScopedObject obj(scope, engine->memoryManager->allocate<QV4Sequence>(qmlType, data));
@@ -666,18 +676,25 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHin
QV4::Scope scope(array.as<Object>()->engine());
QV4::ScopedArrayObject a(scope, array);
- const QQmlType type = QQmlMetaType::qmlType(typeHint);
+ const QQmlType type = QQmlMetaType::qmlListType(typeHint);
if (type.isSequentialContainer()) {
- const QMetaSequence *meta = type.priv()->extraData.ld;
- const QMetaType containerMetaType(type.priv()->typeId);
+ const QQmlTypePrivate *priv = type.priv();
+ const QMetaSequence *meta = priv->extraData.ld;
+ const QMetaType containerMetaType(priv->listId);
QVariant result(containerMetaType);
quint32 length = a->getLength();
QV4::ScopedValue v(scope);
for (quint32 i = 0; i < length; ++i) {
- const QMetaType valueMetaType = meta->valueMetaType();
+ const QMetaType valueMetaType = priv->typeId;
QVariant variant = scope.engine->toVariant(a->get(i), valueMetaType, false);
- if (variant.metaType() != valueMetaType && !variant.convert(valueMetaType))
+ const QMetaType originalType = variant.metaType();
+ if (originalType != valueMetaType && !variant.convert(valueMetaType)) {
+ qWarning() << QLatin1String(
+ "Could not convert array value at position %1 from %2 to %3")
+ .arg(QString::number(i), QString::fromUtf8(originalType.name()),
+ QString::fromUtf8(valueMetaType.name()));
variant = QVariant(valueMetaType);
+ }
meta->addValueAtEnd(result.data(), variant.constData());
}
return result;
@@ -687,20 +704,20 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHin
return QVariant();
}
-void* SequencePrototype::getRawContainerPtr(const Object *object, int typeHint)
+void *SequencePrototype::getRawContainerPtr(const Object *object, QMetaType typeHint)
{
if (auto *s = object->as<QV4Sequence>()) {
- if (s->d()->typePrivate->typeId.id() == typeHint)
+ if (s->d()->typePrivate->listId == typeHint)
return s->getRawContainerPtr();
}
return nullptr;
}
-int SequencePrototype::metaTypeForSequence(const QV4::Object *object)
+QMetaType SequencePrototype::metaTypeForSequence(const QV4::Object *object)
{
if (auto *s = object->as<QV4Sequence>())
- return s->d()->typePrivate->typeId.id();
- return -1;
+ return s->d()->typePrivate->listId;
+ return QMetaType();
}
QT_END_NAMESPACE