aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/qml/jsruntime/qv4engine.cpp223
-rw-r--r--src/qml/jsruntime/qv4jscall_p.h17
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp12
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp178
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h21
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp18
6 files changed, 223 insertions, 246 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index b2d74c8b5d..f73d881885 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -1485,8 +1485,6 @@ static QVariant toVariant(
static QObject *qtObjectFromJS(const QV4::Value &value);
static QVariant objectToVariant(const QV4::Object *o, V4ObjectSet *visitedObjects = nullptr);
static bool convertToNativeQObject(const QV4::Value &value, QMetaType targetType, void **result);
-static QV4::ReturnedValue variantListToJS(QV4::ExecutionEngine *v4, const QVariantList &lst);
-static QV4::ReturnedValue sequentialIterableToJS(QV4::ExecutionEngine *v4, const QSequentialIterable &lst);
static QV4::ReturnedValue variantMapToJS(QV4::ExecutionEngine *v4, const QVariantMap &vmap);
static QV4::ReturnedValue variantToJS(QV4::ExecutionEngine *v4, const QVariant &value)
{
@@ -1759,6 +1757,18 @@ QV4::ReturnedValue ExecutionEngine::fromData(
QMetaType metaType, const void *ptr,
QV4::Heap::Object *container, int property, uint flags)
{
+ const auto createSequence = [&](const QMetaSequence metaSequence) {
+ QV4::Scope scope(this);
+ QV4::Scoped<Sequence> sequence(scope);
+ if (container) {
+ return QV4::SequencePrototype::newSequence(
+ this, metaType, metaSequence, ptr,
+ container, property, Heap::ReferenceObject::Flags(flags));
+ } else {
+ return QV4::SequencePrototype::fromData(this, metaType, metaSequence, ptr);
+ }
+ };
+
const int type = metaType.id();
if (type < QMetaType::User) {
switch (QMetaType::Type(type)) {
@@ -1823,15 +1833,9 @@ QV4::ReturnedValue ExecutionEngine::fromData(
case QMetaType::QObjectStar:
return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr));
case QMetaType::QStringList:
- {
- QV4::Scope scope(this);
- QV4::ScopedValue retn(scope, QV4::SequencePrototype::fromData(this, metaType, ptr));
- if (!retn->isUndefined())
- return retn->asReturnedValue();
- return QV4::Encode(newArrayObject(*reinterpret_cast<const QStringList *>(ptr)));
- }
+ return createSequence(QMetaSequence::fromContainer<QStringList>());
case QMetaType::QVariantList:
- return variantListToJS(this, *reinterpret_cast<const QVariantList *>(ptr));
+ return createSequence(QMetaSequence::fromContainer<QVariantList>());
case QMetaType::QVariantMap:
return variantMapToJS(this, *reinterpret_cast<const QVariantMap *>(ptr));
case QMetaType::QJsonValue:
@@ -1851,105 +1855,95 @@ QV4::ReturnedValue ExecutionEngine::fromData(
default:
break;
}
+ }
- if (const QMetaObject *vtmo = QQmlMetaType::metaObjectForValueType(metaType)) {
- if (container) {
- return QV4::QQmlValueTypeWrapper::create(
- this, ptr, vtmo, metaType,
- container, property, Heap::ReferenceObject::Flags(flags));
- } else {
- return QV4::QQmlValueTypeWrapper::create(this, ptr, vtmo, metaType);
- }
- }
+ if (metaType.flags() & QMetaType::IsEnumeration)
+ return fromData(metaType.underlyingType(), ptr, container, property, flags);
- } else if (!(metaType.flags() & QMetaType::IsEnumeration)) {
- QV4::Scope scope(this);
- if (metaType == QMetaType::fromType<QQmlListReference>()) {
- typedef QQmlListReferencePrivate QDLRP;
- QDLRP *p = QDLRP::get((QQmlListReference*)const_cast<void *>(ptr));
- if (p->object)
- return QV4::QmlListWrapper::create(scope.engine, p->property, p->propertyType);
- else
- return QV4::Encode::null();
- } else if (auto flags = metaType.flags(); flags & QMetaType::IsQmlList) {
- // casting to QQmlListProperty<QObject> is slightly nasty, but it's the
- // same QQmlListReference does.
- const auto *p = static_cast<const QQmlListProperty<QObject> *>(ptr);
- if (p->object)
- return QV4::QmlListWrapper::create(scope.engine, *p, metaType);
- else
- return QV4::Encode::null();
- } else if (metaType == QMetaType::fromType<QJSValue>()) {
- return QJSValuePrivate::convertToReturnedValue(
- this, *reinterpret_cast<const QJSValue *>(ptr));
- } else if (metaType == QMetaType::fromType<QList<QObject *> >()) {
- // XXX Can this be made more by using Array as a prototype and implementing
- // directly against QList<QObject*>?
- const QList<QObject *> &list = *(const QList<QObject *>*)ptr;
- QV4::ScopedArrayObject a(scope, newArrayObject());
- a->arrayReserve(list.size());
- QV4::ScopedValue v(scope);
- for (int ii = 0; ii < list.size(); ++ii)
- a->arrayPut(ii, (v = QV4::QObjectWrapper::wrap(this, list.at(ii))));
- a->setArrayLengthUnchecked(list.size());
- return a.asReturnedValue();
- } else if (auto flags = metaType.flags(); flags & QMetaType::PointerToQObject) {
- if (flags.testFlag(QMetaType::IsConst))
- return QV4::QObjectWrapper::wrapConst(this, *reinterpret_cast<QObject* const *>(ptr));
- else
- return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr));
- } else if (metaType == QMetaType::fromType<QJSPrimitiveValue>()) {
- const QJSPrimitiveValue *primitive = static_cast<const QJSPrimitiveValue *>(ptr);
- switch (primitive->type()) {
- case QJSPrimitiveValue::Boolean:
- return Encode(primitive->asBoolean());
- case QJSPrimitiveValue::Integer:
- return Encode(primitive->asInteger());
- case QJSPrimitiveValue::String:
- return newString(primitive->asString())->asReturnedValue();
- case QJSPrimitiveValue::Undefined:
- return Encode::undefined();
- case QJSPrimitiveValue::Null:
- return Encode::null();
- case QJSPrimitiveValue::Double:
- return Encode(primitive->asDouble());
- }
+ QV4::Scope scope(this);
+ if (metaType == QMetaType::fromType<QQmlListReference>()) {
+ typedef QQmlListReferencePrivate QDLRP;
+ QDLRP *p = QDLRP::get((QQmlListReference*)const_cast<void *>(ptr));
+ if (p->object)
+ return QV4::QmlListWrapper::create(scope.engine, p->property, p->propertyType);
+ else
+ return QV4::Encode::null();
+ } else if (auto flags = metaType.flags(); flags & QMetaType::IsQmlList) {
+ // casting to QQmlListProperty<QObject> is slightly nasty, but it's the
+ // same QQmlListReference does.
+ const auto *p = static_cast<const QQmlListProperty<QObject> *>(ptr);
+ if (p->object)
+ return QV4::QmlListWrapper::create(scope.engine, *p, metaType);
+ else
+ return QV4::Encode::null();
+ } else if (metaType == QMetaType::fromType<QJSValue>()) {
+ return QJSValuePrivate::convertToReturnedValue(
+ this, *reinterpret_cast<const QJSValue *>(ptr));
+ } else if (metaType == QMetaType::fromType<QList<QObject *> >()) {
+ // XXX Can this be made more by using Array as a prototype and implementing
+ // directly against QList<QObject*>?
+ const QList<QObject *> &list = *(const QList<QObject *>*)ptr;
+ QV4::ScopedArrayObject a(scope, newArrayObject());
+ a->arrayReserve(list.size());
+ QV4::ScopedValue v(scope);
+ for (int ii = 0; ii < list.size(); ++ii)
+ a->arrayPut(ii, (v = QV4::QObjectWrapper::wrap(this, list.at(ii))));
+ a->setArrayLengthUnchecked(list.size());
+ return a.asReturnedValue();
+ } else if (auto flags = metaType.flags(); flags & QMetaType::PointerToQObject) {
+ if (flags.testFlag(QMetaType::IsConst))
+ return QV4::QObjectWrapper::wrapConst(this, *reinterpret_cast<QObject* const *>(ptr));
+ else
+ return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr));
+ } else if (metaType == QMetaType::fromType<QJSPrimitiveValue>()) {
+ const QJSPrimitiveValue *primitive = static_cast<const QJSPrimitiveValue *>(ptr);
+ switch (primitive->type()) {
+ case QJSPrimitiveValue::Boolean:
+ return Encode(primitive->asBoolean());
+ case QJSPrimitiveValue::Integer:
+ return Encode(primitive->asInteger());
+ case QJSPrimitiveValue::String:
+ return newString(primitive->asString())->asReturnedValue();
+ case QJSPrimitiveValue::Undefined:
+ return Encode::undefined();
+ case QJSPrimitiveValue::Null:
+ return Encode::null();
+ case QJSPrimitiveValue::Double:
+ return Encode(primitive->asDouble());
}
+ }
- QV4::Scoped<Sequence> sequence(scope);
+ if (const QMetaObject *vtmo = QQmlMetaType::metaObjectForValueType(metaType)) {
if (container) {
- sequence = QV4::SequencePrototype::newSequence(
- this, metaType, ptr,
- container, property, Heap::ReferenceObject::Flags(flags));
+ return QV4::QQmlValueTypeWrapper::create(
+ this, ptr, vtmo, metaType,
+ container, property, Heap::ReferenceObject::Flags(flags));
} else {
- sequence = QV4::SequencePrototype::fromData(this, metaType, ptr);
+ return QV4::QQmlValueTypeWrapper::create(this, ptr, vtmo, metaType);
}
- if (!sequence->isUndefined())
- return sequence->asReturnedValue();
+ }
- if (QMetaType::canConvert(metaType, QMetaType::fromType<QSequentialIterable>())) {
- QSequentialIterable lst;
- QMetaType::convert(metaType, ptr, QMetaType::fromType<QSequentialIterable>(), &lst);
- return sequentialIterableToJS(this, lst);
- }
+ const QQmlType listType = QQmlMetaType::qmlListType(metaType);
+ if (listType.isSequentialContainer())
+ return createSequence(listType.listMetaSequence());
- if (const QMetaObject *vtmo = QQmlMetaType::metaObjectForValueType(metaType)) {
- if (container) {
- return QV4::QQmlValueTypeWrapper::create(
- this, ptr, vtmo, metaType,
- container, property, Heap::ReferenceObject::Flags(flags));
- } else {
- return QV4::QQmlValueTypeWrapper::create(this, ptr, vtmo, metaType);
- }
- }
- }
+ QSequentialIterable iterable;
+ if (QMetaType::convert(metaType, ptr, QMetaType::fromType<QSequentialIterable>(), &iterable)) {
- // XXX TODO: To be compatible, we still need to handle:
- // + QObjectList
- // + QList<int>
+ // If the resulting iterable is useful for anything, turn it into a QV4::Sequence.
+ const QMetaSequence sequence = iterable.metaContainer();
+ if (sequence.hasSize() && sequence.canGetValueAtIndex())
+ return createSequence(sequence);
- if (metaType.flags() & QMetaType::IsEnumeration)
- return fromData(metaType.underlyingType(), ptr, container, property, flags);
+ // As a last resort, try to read the contents of the container via an iterator
+ // and build a JS array from them.
+ if (sequence.hasConstIterator() && sequence.canGetValueAtConstIterator()) {
+ QV4::ScopedArrayObject a(scope, newArrayObject());
+ for (auto it = iterable.constBegin(), end = iterable.constEnd(); it != end; ++it)
+ a->push_back(fromVariant(*it));
+ return a.asReturnedValue();
+ }
+ }
return QV4::Encode(newVariantObject(metaType, ptr));
}
@@ -1970,39 +1964,6 @@ QVariantMap ExecutionEngine::variantMapFromJS(const Object *o)
return objectToVariant(o).toMap();
}
-
-// Converts a QVariantList to JS.
-// The result is a new Array object with length equal to the length
-// of the QVariantList, and the elements being the QVariantList's
-// elements converted to JS, recursively.
-static QV4::ReturnedValue variantListToJS(QV4::ExecutionEngine *v4, const QVariantList &lst)
-{
- QV4::Scope scope(v4);
- QV4::ScopedArrayObject a(scope, v4->newArrayObject());
- a->arrayReserve(lst.size());
- QV4::ScopedValue v(scope);
- for (int i = 0; i < lst.size(); i++)
- a->arrayPut(i, (v = variantToJS(v4, lst.at(i))));
- a->setArrayLengthUnchecked(lst.size());
- return a.asReturnedValue();
-}
-
-// Converts a QSequentialIterable to JS.
-// The result is a new Array object with length equal to the length
-// of the QSequentialIterable, and the elements being the QSequentialIterable's
-// elements converted to JS, recursively.
-static QV4::ReturnedValue sequentialIterableToJS(QV4::ExecutionEngine *v4, const QSequentialIterable &lst)
-{
- QV4::Scope scope(v4);
- QV4::ScopedArrayObject a(scope, v4->newArrayObject());
- a->arrayReserve(lst.size());
- QV4::ScopedValue v(scope);
- for (int i = 0; i < lst.size(); i++)
- a->arrayPut(i, (v = variantToJS(v4, lst.at(i))));
- a->setArrayLengthUnchecked(lst.size());
- return a.asReturnedValue();
-}
-
// Converts a QVariantMap to JS.
// The result is a new Object object with property names being
// the keys of the QVariantMap, and values being the values of
diff --git a/src/qml/jsruntime/qv4jscall_p.h b/src/qml/jsruntime/qv4jscall_p.h
index e824863b29..7bb38a5fe9 100644
--- a/src/qml/jsruntime/qv4jscall_p.h
+++ b/src/qml/jsruntime/qv4jscall_p.h
@@ -233,9 +233,17 @@ inline ReturnedValue coerceListType(
ExecutionEngine *engine, const Value &value, const QQmlType &qmlType)
{
QMetaType type = qmlType.qListTypeId();
+ const auto metaSequence = [&]() {
+ // TODO: We should really add the metasequence to the same QQmlType that holds
+ // all the other type information. Then we can get rid of the extra
+ // QQmlMetaType::qmlListType() here.
+ return qmlType.isSequentialContainer()
+ ? qmlType.listMetaSequence()
+ : QQmlMetaType::qmlListType(type).listMetaSequence();
+ };
+
if (const QV4::Sequence *sequence = value.as<QV4::Sequence>()) {
- const QQmlTypePrivate *typePrivate = sequence->d()->typePrivate();
- if (typePrivate->listId == type)
+ if (sequence->d()->listType() == type)
return value.asReturnedValue();
}
@@ -256,7 +264,7 @@ inline ReturnedValue coerceListType(
if (!array) {
return (listValueType.flags() & QMetaType::PointerToQObject)
? QmlListWrapper::create(engine, listValueType)
- : SequencePrototype::fromData(engine, type, nullptr);
+ : SequencePrototype::fromData(engine, type, metaSequence(), nullptr);
}
if (listValueType.flags() & QMetaType::PointerToQObject) {
@@ -273,7 +281,8 @@ inline ReturnedValue coerceListType(
return newList->asReturnedValue();
}
- QV4::Scoped<Sequence> sequence(scope, SequencePrototype::fromData(engine, type, nullptr));
+ QV4::Scoped<Sequence> sequence(
+ scope, SequencePrototype::fromData(engine, type, metaSequence(), nullptr));
const qsizetype length = array->getLength();
for (qsizetype i = 0; i < length; ++i)
sequence->containerPutIndexed(i, array->get(i));
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 6a0142a46e..38b9226c9f 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -205,12 +205,12 @@ static ReturnedValue loadProperty(
// See if it's a sequence type.
// Pass nullptr as data. It's lazy-loaded.
- QV4::ScopedValue retn(scope, QV4::SequencePrototype::newSequence(
- v4, propMetaType, nullptr,
- wrapper, property.coreIndex(),
- referenceFlags(scope.engine, property)));
- if (!retn->isUndefined())
- return retn->asReturnedValue();
+ const QQmlType qmlType = QQmlMetaType::qmlListType(propMetaType);
+ if (qmlType.isSequentialContainer()) {
+ return QV4::SequencePrototype::newSequence(
+ v4, propMetaType, qmlType.listMetaSequence(), nullptr,
+ wrapper, property.coreIndex(), referenceFlags(scope.engine, property));
+ }
QVariant v(propMetaType);
property.readProperty(object, v.data());
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 4472a5411a..dc894fb670 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -27,9 +27,9 @@ static ReturnedValue doGetIndexed(const Sequence *s, qsizetype index) {
Heap::ReferenceObject::Flags flags =
Heap::ReferenceObject::EnforcesLocation;
- if (s->d()->typePrivate()->extraData.ld->canSetValueAtIndex())
+ if (s->d()->metaSequence().canSetValueAtIndex())
flags |= Heap::ReferenceObject::CanWriteBack;
- if (Sequence::valueMetaType(s->d()) == QMetaType::fromType<QVariant>())
+ if (s->d()->valueMetaType() == QMetaType::fromType<QVariant>())
flags |= Heap::ReferenceObject::IsVariant;
QV4::ScopedValue v(scope, scope.engine->fromVariant(
@@ -42,18 +42,12 @@ static ReturnedValue doGetIndexed(const Sequence *s, qsizetype index) {
return v->asReturnedValue();
}
-static const QMetaSequence *metaSequence(const Heap::Sequence *p)
-{
- return p->typePrivate()->extraData.ld;
-}
-
template<typename Compare>
void sortSequence(Sequence *sequence, const Compare &compare)
{
- auto *p = sequence->d();
- const auto *m = metaSequence(p);
+ /* non-const */ Heap::Sequence *p = sequence->d();
- QSequentialIterable iterable(*m, p->typePrivate()->listId, p->storagePointer());
+ QSequentialIterable iterable(p->metaSequence(), p->listType(), p->storagePointer());
if (iterable.canRandomAccessIterate()) {
std::sort(QSequentialIterable::RandomAccessIterator(iterable.mutableBegin()),
QSequentialIterable::RandomAccessIterator(iterable.mutableEnd()),
@@ -148,37 +142,35 @@ struct SequenceDefaultCompareFunctor
}
};
-void Heap::Sequence::init(const QQmlType &qmlType, const void *container)
+void Heap::Sequence::initTypes(QMetaType listType, QMetaSequence metaSequence)
{
- ReferenceObject::init(nullptr, -1, NoFlag);
-
- Q_ASSERT(qmlType.isSequentialContainer());
- m_typePrivate = qmlType.priv();
- QQmlType::refHandle(m_typePrivate);
-
- m_container = m_typePrivate->listId.create(container);
-
+ m_listType = listType.iface();
+ Q_ASSERT(m_listType);
+ m_metaSequence = metaSequence.iface();
+ Q_ASSERT(m_metaSequence);
QV4::Scope scope(internalClass->engine);
QV4::Scoped<QV4::Sequence> o(scope, this);
o->setArrayType(Heap::ArrayData::Custom);
}
+void Heap::Sequence::init(QMetaType listType, QMetaSequence metaSequence, const void *container)
+{
+ ReferenceObject::init(nullptr, -1, NoFlag);
+ initTypes(listType, metaSequence);
+ m_container = listType.create(container);
+}
+
void Heap::Sequence::init(
- const QQmlType &qmlType, const void *container,
- Heap::Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags)
+ QMetaType listType, QMetaSequence metaSequence, const void *container,
+ Heap::Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags)
{
ReferenceObject::init(object, propertyIndex, flags);
+ initTypes(listType, metaSequence);
- Q_ASSERT(qmlType.isSequentialContainer());
- m_typePrivate = qmlType.priv();
- QQmlType::refHandle(m_typePrivate);
- QV4::Scope scope(internalClass->engine);
- QV4::Scoped<QV4::Sequence> o(scope, this);
- o->setArrayType(Heap::ArrayData::Custom);
- if (CppStackFrame *frame = scope.engine->currentStackFrame)
+ if (CppStackFrame *frame = internalClass->engine->currentStackFrame)
setLocation(frame->v4Function, frame->statementNumber());
if (container)
- m_container = QMetaType(m_typePrivate->listId).create(container);
+ m_container = listType.create(container);
else if (flags & EnforcesLocation)
QV4::ReferenceObject::readReference(this);
}
@@ -186,28 +178,27 @@ void Heap::Sequence::init(
Heap::Sequence *Heap::Sequence::detached() const
{
return internalClass->engine->memoryManager->allocate<QV4::Sequence>(
- QQmlType(m_typePrivate), m_container);
+ QMetaType(m_listType), QMetaSequence(m_metaSequence), m_container);
}
void Heap::Sequence::destroy()
{
if (m_container)
- m_typePrivate->listId.destroy(m_container);
- QQmlType::derefHandle(m_typePrivate);
+ listType().destroy(m_container);
ReferenceObject::destroy();
}
void *Heap::Sequence::storagePointer()
{
if (!m_container)
- m_container = m_typePrivate->listId.create();
+ m_container = listType().create();
return m_container;
}
bool Heap::Sequence::setVariant(const QVariant &variant)
{
const QMetaType variantReferenceType = variant.metaType();
- if (variantReferenceType != m_typePrivate->listId) {
+ if (variantReferenceType != listType()) {
// This is a stale reference. That is, the property has been
// overwritten with a different type in the meantime.
// We need to modify this reference to the updated type, if
@@ -215,11 +206,10 @@ bool Heap::Sequence::setVariant(const QVariant &variant)
const QQmlType newType = QQmlMetaType::qmlListType(variantReferenceType);
if (newType.isSequentialContainer()) {
if (m_container)
- m_typePrivate->listId.destroy(m_container);
- QQmlType::derefHandle(m_typePrivate);
- m_typePrivate = newType.priv();
- QQmlType::refHandle(m_typePrivate);
- m_container = m_typePrivate->listId.create(variant.constData());
+ listType().destroy(m_container);
+ m_listType = newType.qListTypeId().iface();
+ m_metaSequence = newType.listMetaSequence().iface();
+ m_container = listType().create(variant.constData());
return true;
} else {
return false;
@@ -235,32 +225,27 @@ bool Heap::Sequence::setVariant(const QVariant &variant)
}
QVariant Heap::Sequence::toVariant() const
{
- return QVariant(m_typePrivate->listId, m_container);
-}
-
-const QMetaType Sequence::valueMetaType(const Heap::Sequence *p)
-{
- return p->typePrivate()->typeId;
+ return QVariant(listType(), m_container);
}
qsizetype Sequence::size() const
{
const auto *p = d();
Q_ASSERT(p->storagePointer()); // Must readReference() before
- return metaSequence(p)->size(p->storagePointer());
+ return p->metaSequence().size(p->storagePointer());
}
QVariant Sequence::at(qsizetype index) const
{
const auto *p = d();
Q_ASSERT(p->storagePointer()); // Must readReference() before
- const QMetaType v = valueMetaType(p);
+ const QMetaType v = p->valueMetaType();
QVariant result;
if (v == QMetaType::fromType<QVariant>()) {
- metaSequence(p)->valueAtIndex(p->storagePointer(), index, &result);
+ p->metaSequence().valueAtIndex(p->storagePointer(), index, &result);
} else {
result = QVariant(v);
- metaSequence(p)->valueAtIndex(p->storagePointer(), index, result.data());
+ p->metaSequence().valueAtIndex(p->storagePointer(), index, result.data());
}
return result;
}
@@ -284,45 +269,45 @@ void convertAndDo(const QVariant &item, const QMetaType v, Action action)
void Sequence::append(const QVariant &item)
{
Heap::Sequence *p = d();
- convertAndDo(item, valueMetaType(p), [p](const void *data) {
- metaSequence(p)->addValueAtEnd(p->storagePointer(), data);
+ convertAndDo(item, p->valueMetaType(), [p](const void *data) {
+ p->metaSequence().addValueAtEnd(p->storagePointer(), data);
});
}
void Sequence::append(qsizetype num, const QVariant &item)
{
Heap::Sequence *p = d();
- convertAndDo(item, valueMetaType(p), [p, num](const void *data) {
- const QMetaSequence *m = metaSequence(p);
+ convertAndDo(item, p->valueMetaType(), [p, num](const void *data) {
+ const QMetaSequence m = p->metaSequence();
void *container = p->storagePointer();
for (qsizetype i = 0; i < num; ++i)
- m->addValueAtEnd(container, data);
+ m.addValueAtEnd(container, data);
});
}
void Sequence::replace(qsizetype index, const QVariant &item)
{
Heap::Sequence *p = d();
- convertAndDo(item, valueMetaType(p), [p, index](const void *data) {
- metaSequence(p)->setValueAtIndex(p->storagePointer(), index, data);
+ convertAndDo(item, p->valueMetaType(), [p, index](const void *data) {
+ p->metaSequence().setValueAtIndex(p->storagePointer(), index, data);
});
}
void Sequence::removeLast(qsizetype num)
{
auto *p = d();
- const auto *m = metaSequence(p);
-
- if (m->canEraseRangeAtIterator() && m->hasRandomAccessIterator() && num > 1) {
- void *i = m->end(p->storagePointer());
- m->advanceIterator(i, -num);
- void *j = m->end(p->storagePointer());
- m->eraseRangeAtIterator(p->storagePointer(), i, j);
- m->destroyIterator(i);
- m->destroyIterator(j);
+ const QMetaSequence m = p->metaSequence();
+
+ if (m.canEraseRangeAtIterator() && m.hasRandomAccessIterator() && num > 1) {
+ void *i = m.end(p->storagePointer());
+ m.advanceIterator(i, -num);
+ void *j = m.end(p->storagePointer());
+ m.eraseRangeAtIterator(p->storagePointer(), i, j);
+ m.destroyIterator(i);
+ m.destroyIterator(j);
} else {
for (int i = 0; i < num; ++i)
- m->removeValueAtEnd(p->storagePointer());
+ m.removeValueAtEnd(p->storagePointer());
}
}
@@ -355,7 +340,7 @@ bool Sequence::containerPutIndexed(qsizetype index, const Value &value)
return false;
const qsizetype count = size();
- const QMetaType valueType = valueMetaType(d());
+ const QMetaType valueType = d()->valueMetaType();
const QVariant element = ExecutionEngine::toVariant(value, valueType, false);
if (index < 0)
@@ -518,25 +503,25 @@ int Sequence::virtualMetacall(Object *object, QMetaObject::Call call, int index,
switch (call) {
case QMetaObject::ReadProperty: {
- const QMetaType valueType = valueMetaType(sequence->d());
+ const QMetaType valueType = sequence->d()->valueMetaType();
if (!sequence->loadReference())
return 0;
- const QMetaSequence *metaSequence = sequence->d()->typePrivate()->extraData.ld;
- if (metaSequence->valueMetaType() != valueType)
+ const QMetaSequence metaSequence = sequence->d()->metaSequence();
+ if (metaSequence.valueMetaType() != valueType)
return 0; // value metatype is not what the caller expects anymore.
const void *storagePointer = sequence->d()->storagePointer();
- if (index < 0 || index >= metaSequence->size(storagePointer))
+ if (index < 0 || index >= metaSequence.size(storagePointer))
return 0;
- metaSequence->valueAtIndex(storagePointer, index, a[0]);
+ metaSequence.valueAtIndex(storagePointer, index, a[0]);
break;
}
case QMetaObject::WriteProperty: {
void *storagePointer = sequence->d()->storagePointer();
- const QMetaSequence *metaSequence = sequence->d()->typePrivate()->extraData.ld;
- if (index < 0 || index >= metaSequence->size(storagePointer))
+ const QMetaSequence metaSequence = sequence->d()->metaSequence();
+ if (index < 0 || index >= metaSequence.size(storagePointer))
return 0;
- metaSequence->setValueAtIndex(storagePointer, index, a[0]);
+ metaSequence.setValueAtIndex(storagePointer, index, a[0]);
sequence->storeReference();
break;
}
@@ -592,7 +577,7 @@ static QV4::ReturnedValue method_set_length(const FunctionObject *f, const Value
if (newCount == count) {
RETURN_UNDEFINED();
} else if (newCount > count) {
- const QMetaType valueMetaType = metaSequence(This->d())->valueMetaType();
+ const QMetaType valueMetaType = This->d()->valueMetaType();
/* according to ECMA262r3 we need to insert */
/* undefined values increasing length to newLength. */
/* We cannot, so we insert default-values instead. */
@@ -642,40 +627,43 @@ ReturnedValue SequencePrototype::method_sort(const FunctionObject *b, const Valu
}
ReturnedValue SequencePrototype::newSequence(
- QV4::ExecutionEngine *engine, QMetaType sequenceType, const void *data,
- Heap::Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags)
+ QV4::ExecutionEngine *engine, QMetaType type, QMetaSequence metaSequence, const void *data,
+ Heap::Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags)
{
// This function is called when the property is a QObject Q_PROPERTY of
// the given sequence type. Internally we store a sequence
// (as well as object ptr + property index for updated-read and write-back)
// and so access/mutate avoids variant conversion.
- const QQmlType qmlType = QQmlMetaType::qmlListType(sequenceType);
- if (qmlType.isSequentialContainer()) {
- return engine->memoryManager->allocate<Sequence>(
- qmlType, data, object, propertyIndex, flags)->asReturnedValue();
- }
-
- return Encode::undefined();
+ return engine->memoryManager->allocate<Sequence>(
+ type, metaSequence, data, object, propertyIndex, flags)->asReturnedValue();
}
ReturnedValue SequencePrototype::fromVariant(QV4::ExecutionEngine *engine, const QVariant &v)
{
- return fromData(engine, v.metaType(), v.constData());
+ const QMetaType type = v.metaType();
+ const QQmlType qmlType = QQmlMetaType::qmlListType(type);
+ if (qmlType.isSequentialContainer())
+ return fromData(engine, type, qmlType.listMetaSequence(), v.constData());
+
+ QSequentialIterable iterable;
+ if (QMetaType::convert(
+ type, v.constData(), QMetaType::fromType<QSequentialIterable>(), &iterable)) {
+ return fromData(engine, type, iterable.metaContainer(), v.constData());
+ }
+
+ return Encode::undefined();
}
-ReturnedValue SequencePrototype::fromData(ExecutionEngine *engine, QMetaType type, const void *data)
+ReturnedValue SequencePrototype::fromData(
+ ExecutionEngine *engine, QMetaType type, QMetaSequence metaSequence, const void *data)
{
// This function is called when assigning a sequence value to a normal JS var
// in a JS block. Internally, we store a sequence of the specified type.
// Access and mutation is extremely fast since it will not need to modify any
// QObject property.
- const QQmlType qmlType = QQmlMetaType::qmlListType(type);
- if (qmlType.isSequentialContainer())
- return engine->memoryManager->allocate<Sequence>(qmlType, data)->asReturnedValue();
-
- return Encode::undefined();
+ return engine->memoryManager->allocate<Sequence>(type, metaSequence, data)->asReturnedValue();
}
QVariant SequencePrototype::toVariant(const Sequence *object)
@@ -692,7 +680,7 @@ QVariant SequencePrototype::toVariant(const Sequence *object)
if (!p->hasData())
return QVariant();
- return QVariant(p->typePrivate()->listId, p->storagePointer());
+ return QVariant(p->listType(), p->storagePointer());
}
QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHint)
@@ -747,14 +735,14 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHin
void *SequencePrototype::getRawContainerPtr(const Sequence *object, QMetaType typeHint)
{
- if (object->d()->typePrivate()->listId == typeHint)
+ if (object->d()->listType() == typeHint)
return object->getRawContainerPtr();
return nullptr;
}
QMetaType SequencePrototype::metaTypeForSequence(const Sequence *object)
{
- return object->d()->typePrivate()->listId;
+ return object->d()->listType();
}
} // namespace QV4
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index c7bd96eb97..2ea20b0466 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -37,10 +37,11 @@ struct Q_QML_PRIVATE_EXPORT SequencePrototype : public QV4::Object
static ReturnedValue method_sort(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue newSequence(
- QV4::ExecutionEngine *engine, QMetaType sequenceType, const void *data,
- Heap::Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags);
+ QV4::ExecutionEngine *engine, QMetaType type, QMetaSequence metaSequence, const void *data,
+ Heap::Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags);
static ReturnedValue fromVariant(QV4::ExecutionEngine *engine, const QVariant &vd);
- static ReturnedValue fromData(QV4::ExecutionEngine *engine, QMetaType type, const void *data);
+ static ReturnedValue fromData(
+ QV4::ExecutionEngine *engine, QMetaType type, QMetaSequence metaSequence, const void *data);
static QMetaType metaTypeForSequence(const Sequence *object);
static QVariant toVariant(const Sequence *object);
@@ -52,8 +53,8 @@ namespace Heap {
struct Sequence : ReferenceObject
{
- void init(const QQmlType &qmlType, const void *container);
- void init(const QQmlType &qmlType, const void *container,
+ void init(QMetaType listType, QMetaSequence metaSequence, const void *container);
+ void init(QMetaType listType, QMetaSequence metaSequence, const void *container,
Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags);
Sequence *detached() const;
@@ -68,11 +69,16 @@ struct Sequence : ReferenceObject
bool setVariant(const QVariant &variant);
QVariant toVariant() const;
- const QQmlTypePrivate *typePrivate() const { return m_typePrivate; }
+ QMetaType listType() const { return QMetaType(m_listType); }
+ QMetaType valueMetaType() const { return QMetaType(m_metaSequence->valueMetaType); }
+ QMetaSequence metaSequence() const { return QMetaSequence(m_metaSequence); }
private:
+ void initTypes(QMetaType listType, QMetaSequence metaSequence);
+
void *m_container;
- const QQmlTypePrivate *m_typePrivate;
+ const QtPrivate::QMetaTypeInterface *m_listType;
+ const QtMetaContainerPrivate::QMetaSequenceInterface *m_metaSequence;
};
}
@@ -84,7 +90,6 @@ struct Q_QML_PRIVATE_EXPORT Sequence : public QV4::ReferenceObject
V4_PROTOTYPE(sequencePrototype)
V4_NEEDS_DESTROY
public:
- static const QMetaType valueMetaType(const Heap::Sequence *p);
static QV4::ReturnedValue virtualGet(
const QV4::Managed *that, PropertyKey id, const Value *receiver, bool *hasProperty);
static qint64 virtualGetLength(const Managed *m);
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 08e89f7e91..fb90e3e800 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -21,6 +21,8 @@
#include <private/qqmlpropertycachemethodarguments_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
+#include <QtCore/qsequentialiterable.h>
+
#include <climits> // for CHAR_BIT
QT_BEGIN_NAMESPACE
@@ -864,8 +866,20 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
needActivate = true;
}
} else {
- QV4::ScopedValue sequence(scope, QV4::SequencePrototype::fromData(
- engine, propType, a[0]));
+ if (const QQmlType type = QQmlMetaType::qmlListType(propType);
+ type.isSequentialContainer()) {
+ sequence = QV4::SequencePrototype::fromData(
+ engine, propType, type.listMetaSequence(), a[0]);
+ } else if (QSequentialIterable iterable;
+ QMetaType::convert(
+ propType, a[0],
+ QMetaType::fromType<QSequentialIterable>(),
+ &iterable)) {
+ sequence = QV4::SequencePrototype::fromData(
+ engine, propType, iterable.metaContainer(), a[0]);
+ } else {
+ sequence = QV4::Encode::undefined();
+ }
md->set(engine, id, sequence);
if (sequence->isUndefined()) {
qmlWarning(object)