diff options
author | Ulf Hermann <[email protected]> | 2022-05-17 15:50:06 +0200 |
---|---|---|
committer | Ulf Hermann <[email protected]> | 2022-06-02 02:42:51 +0200 |
commit | e3e8008ec325bdc690fd9600025d66860cac5e62 (patch) | |
tree | e82ab867c272e042afc44c627a6f861c2a306418 /src/qml/jsruntime/qv4sequenceobject.cpp | |
parent | 7bfbd706b56c426e2683e519543b56426310520f (diff) |
Allow retrieval of sequences from QJSValue
As we can store sequence types in QJSValue, we should be able to
retrieve them, too.
Move the declaration of the QV4::Sequence struct into a header to make
it less of a hassle to identify sequences.
Change-Id: I3e45bfe193c669107f90cd6c502765c0c9f60fb0
Reviewed-by: Andrei Golubev <[email protected]>
Reviewed-by: Sami Shalayel <[email protected]>
Reviewed-by: Qt CI Bot <[email protected]>
Reviewed-by: Ulf Hermann <[email protected]>
Diffstat (limited to 'src/qml/jsruntime/qv4sequenceobject.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4sequenceobject.cpp | 776 |
1 files changed, 373 insertions, 403 deletions
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index c374a9f3cf..fa7bb9d3dd 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -55,7 +55,34 @@ QT_BEGIN_NAMESPACE -using namespace QV4; +namespace QV4 { + +DEFINE_OBJECT_VTABLE(Sequence); + +static const QMetaSequence *metaSequence(const Heap::Sequence *p) +{ + return p->typePrivate->extraData.ld; +} + +template<typename Compare> +void sortSequence(Sequence *sequence, const Compare &compare) +{ + const auto *p = sequence->d(); + const auto *m = metaSequence(p); + + QSequentialIterable iterable(*m, p->typePrivate->listId, p->container); + if (iterable.canRandomAccessIterate()) { + std::sort(QSequentialIterable::RandomAccessIterator(iterable.mutableBegin()), + QSequentialIterable::RandomAccessIterator(iterable.mutableEnd()), + compare); + } else if (iterable.canReverseIterate()) { + std::sort(QSequentialIterable::BidirectionalIterator(iterable.mutableBegin()), + QSequentialIterable::BidirectionalIterator(iterable.mutableEnd()), + compare); + } else { + qWarning() << "Container has no suitable iterator for sorting"; + } +} // helper function to generate valid warnings if errors occur during sequence operations. static void generateWarning(QV4::ExecutionEngine *v4, const QString& description) @@ -73,468 +100,413 @@ static void generateWarning(QV4::ExecutionEngine *v4, const QString& description QQmlEnginePrivate::warning(engine, retn); } -namespace QV4 { +struct SequenceOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator +{ + ~SequenceOwnPropertyKeyIterator() override = default; + PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override + { + const Sequence *s = static_cast<const Sequence *>(o); + + if (s->d()->isReference) { + if (!s->d()->object) + return ObjectOwnPropertyKeyIterator::next(o, pd, attrs); + s->loadReference(); + } -namespace Heap { + if (arrayIndex < quint32(s->size())) { + uint index = arrayIndex; + ++arrayIndex; + if (attrs) + *attrs = QV4::Attr_Data; + if (pd) + pd->value = s->engine()->fromVariant(s->at(index)); + return PropertyKey::fromArrayIndex(index); + } -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->listId.destroy(container); - QQmlType::derefHandle(typePrivate); - object.destroy(); - Object::destroy(); + return ObjectOwnPropertyKeyIterator::next(o, pd, attrs); } +}; + +struct SequenceCompareFunctor +{ + SequenceCompareFunctor(QV4::ExecutionEngine *v4, const QV4::Value &compareFn) + : m_v4(v4), m_compareFn(&compareFn) + {} - mutable void *container; - const QQmlTypePrivate *typePrivate; - QV4QPointer<QObject> object; - int propertyIndex; - bool isReference : 1; - bool isReadOnly : 1; + bool operator()(const QVariant &lhs, const QVariant &rhs) + { + QV4::Scope scope(m_v4); + ScopedFunctionObject compare(scope, m_compareFn); + if (!compare) + return m_v4->throwTypeError(); + Value *argv = scope.alloc(2); + argv[0] = m_v4->fromVariant(lhs); + argv[1] = m_v4->fromVariant(rhs); + QV4::ScopedValue result(scope, compare->call(m_v4->globalObject, argv, 2)); + if (scope.hasException()) + return false; + return result->toNumber() < 0; + } + +private: + QV4::ExecutionEngine *m_v4; + const QV4::Value *m_compareFn; }; -} +struct SequenceDefaultCompareFunctor +{ + bool operator()(const QVariant &lhs, const QVariant &rhs) + { + return lhs.toString() < rhs.toString(); + } +}; -static const QMetaSequence *meta(const Heap::QV4Sequence *p) +void Heap::Sequence::init(const QQmlType &qmlType, const void *container) { - return p->typePrivate->extraData.ld; + Object::init(); + + Q_ASSERT(qmlType.isSequentialContainer()); + typePrivate = qmlType.priv(); + QQmlType::refHandle(typePrivate); + + this->container = typePrivate->listId.create(container); + propertyIndex = -1; + isReference = false; + isReadOnly = false; + object.init(); + + QV4::Scope scope(internalClass->engine); + QV4::Scoped<QV4::Sequence> o(scope, this); + o->setArrayType(Heap::ArrayData::Custom); } -struct QV4Sequence : public QV4::Object +void Heap::Sequence::init( + QObject *object, int propertyIndex, const QQmlType &qmlType, bool readOnly) { - V4_OBJECT2(QV4Sequence, QV4::Object) - Q_MANAGED_TYPE(V4Sequence) - V4_PROTOTYPE(sequencePrototype) - V4_NEEDS_DESTROY -public: + Object::init(); - static const QMetaSequence *metaSequence(const Heap::QV4Sequence *p) - { - return p->typePrivate->extraData.ld; - } + Q_ASSERT(qmlType.isSequentialContainer()); + typePrivate = qmlType.priv(); + QQmlType::refHandle(typePrivate); + container = QMetaType(typePrivate->listId).create(); + this->propertyIndex = propertyIndex; + isReference = true; + this->isReadOnly = readOnly; + this->object.init(object); + QV4::Scope scope(internalClass->engine); + QV4::Scoped<QV4::Sequence> o(scope, this); + o->setArrayType(Heap::ArrayData::Custom); + o->loadReference(); +} - static const QMetaType valueMetaType(const Heap::QV4Sequence *p) - { - return p->typePrivate->typeId; - } +void Heap::Sequence::destroy() +{ + typePrivate->listId.destroy(container); + QQmlType::derefHandle(typePrivate); + object.destroy(); + Object::destroy(); +} - qsizetype size() const - { - const auto *p = d(); - return metaSequence(p)->size(p->container); - } +const QMetaType Sequence::valueMetaType(const Heap::Sequence *p) +{ + return p->typePrivate->typeId; +} - QVariant at(int index) const - { - const auto *p = d(); - const QMetaType v = valueMetaType(p); - QVariant result; - if (v == QMetaType::fromType<QVariant>()) { - metaSequence(p)->valueAtIndex(p->container, index, &result); - } else { - result = QVariant(v); - metaSequence(p)->valueAtIndex(p->container, index, result.data()); - } - return result; - } +qsizetype Sequence::size() const +{ + const auto *p = d(); + return metaSequence(p)->size(p->container); +} - void append(const QVariant &item) - { - const auto *p = d(); - const auto *m = metaSequence(p); - const QMetaType v = valueMetaType(p); - if (item.metaType() == v) { - m->addValueAtEnd(p->container, item.constData()); - } else if (v == QMetaType::fromType<QVariant>()) { - m->addValueAtEnd(p->container, &item); - } else { - QVariant converted = item; - if (!converted.convert(v)) - converted = QVariant(v); - m->addValueAtEnd(p->container, converted.constData()); - } +QVariant Sequence::at(int index) const +{ + const auto *p = d(); + const QMetaType v = valueMetaType(p); + QVariant result; + if (v == QMetaType::fromType<QVariant>()) { + metaSequence(p)->valueAtIndex(p->container, index, &result); + } else { + result = QVariant(v); + metaSequence(p)->valueAtIndex(p->container, index, result.data()); } + return result; +} - void replace(int index, const QVariant &item) - { - const auto *p = d(); - const auto *m = metaSequence(p); - const QMetaType v = valueMetaType(p); - if (item.metaType() == v) { - m->setValueAtIndex(p->container, index, item.constData()); - } else if (v == QMetaType::fromType<QVariant>()) { - m->setValueAtIndex(p->container, index, &item); - } else { - QVariant converted = item; - if (!converted.convert(v)) - converted = QVariant(v); - m->setValueAtIndex(p->container, index, converted.constData()); - } +void Sequence::append(const QVariant &item) +{ + const auto *p = d(); + const auto *m = metaSequence(p); + const QMetaType v = valueMetaType(p); + if (item.metaType() == v) { + m->addValueAtEnd(p->container, item.constData()); + } else if (v == QMetaType::fromType<QVariant>()) { + m->addValueAtEnd(p->container, &item); + } else { + QVariant converted = item; + if (!converted.convert(v)) + converted = QVariant(v); + m->addValueAtEnd(p->container, converted.constData()); } +} - template<typename Compare> - void sort(const Compare &compare) - { - const auto *p = d(); - const auto *m = metaSequence(p); - - QSequentialIterable iterable(*m, p->typePrivate->listId, p->container); - if (iterable.canRandomAccessIterate()) { - std::sort(QSequentialIterable::RandomAccessIterator(iterable.mutableBegin()), - QSequentialIterable::RandomAccessIterator(iterable.mutableEnd()), - compare); - } else if (iterable.canReverseIterate()) { - std::sort(QSequentialIterable::BidirectionalIterator(iterable.mutableBegin()), - QSequentialIterable::BidirectionalIterator(iterable.mutableEnd()), - compare); - } else { - qWarning() << "Container has no suitable iterator for sorting"; - } +void Sequence::replace(int index, const QVariant &item) +{ + const auto *p = d(); + const auto *m = metaSequence(p); + const QMetaType v = valueMetaType(p); + if (item.metaType() == v) { + m->setValueAtIndex(p->container, index, item.constData()); + } else if (v == QMetaType::fromType<QVariant>()) { + m->setValueAtIndex(p->container, index, &item); + } else { + QVariant converted = item; + if (!converted.convert(v)) + converted = QVariant(v); + m->setValueAtIndex(p->container, index, converted.constData()); } +} - void removeLast(int num) - { - const auto *p = d(); - const auto *m = metaSequence(p); - - if (m->canEraseRangeAtIterator() && m->hasRandomAccessIterator() && num > 1) { - void *i = m->end(p->container); - m->advanceIterator(i, -num); - void *j = m->end(p->container); - m->eraseRangeAtIterator(p->container, i, j); - m->destroyIterator(i); - m->destroyIterator(j); - } else { - for (int i = 0; i < num; ++i) - m->removeValueAtEnd(p->container); - } +void Sequence::removeLast(int num) +{ + const auto *p = d(); + const auto *m = metaSequence(p); + + if (m->canEraseRangeAtIterator() && m->hasRandomAccessIterator() && num > 1) { + void *i = m->end(p->container); + m->advanceIterator(i, -num); + void *j = m->end(p->container); + m->eraseRangeAtIterator(p->container, i, j); + m->destroyIterator(i); + m->destroyIterator(j); + } else { + for (int i = 0; i < num; ++i) + m->removeValueAtEnd(p->container); } +} - QVariant toVariant() - { - const auto *p = d(); - return QVariant(p->typePrivate->listId, p->container); - } +QVariant Sequence::toVariant() const +{ + const auto *p = d(); + return QVariant(p->typePrivate->listId, p->container); +} - // ### Qt 7 use qsizetype instead. - QV4::ReturnedValue containerGetIndexed(uint index, bool *hasProperty) const - { - /* Qt containers have int (rather than uint) allowable indexes. */ - if (index > INT_MAX) { - generateWarning(engine(), QLatin1String("Index out of range during indexed get")); +ReturnedValue Sequence::containerGetIndexed(uint index, bool *hasProperty) const +{ + /* Qt containers have int (rather than uint) allowable indexes. */ + if (index > INT_MAX) { + generateWarning(engine(), QLatin1String("Index out of range during indexed get")); + if (hasProperty) + *hasProperty = false; + return Encode::undefined(); + } + if (d()->isReference) { + if (!d()->object) { if (hasProperty) *hasProperty = false; return Encode::undefined(); } - if (d()->isReference) { - if (!d()->object) { - if (hasProperty) - *hasProperty = false; - return Encode::undefined(); - } - loadReference(); - } - if (index < quint32(size())) { - if (hasProperty) - *hasProperty = true; - return engine()->fromVariant(at(index)); - } + loadReference(); + } + if (index < quint32(size())) { if (hasProperty) - *hasProperty = false; - return Encode::undefined(); + *hasProperty = true; + return engine()->fromVariant(at(index)); } + if (hasProperty) + *hasProperty = false; + return Encode::undefined(); +} - // ### Qt 7 use qsizetype instead. - bool containerPutIndexed(uint index, const QV4::Value &value) - { - if (internalClass()->engine->hasException) - return false; +bool Sequence::containerPutIndexed(uint index, const Value &value) +{ + if (internalClass()->engine->hasException) + return false; - /* Qt containers have int (rather than uint) allowable indexes. */ - if (index > INT_MAX) { - generateWarning(engine(), QLatin1String("Index out of range during indexed set")); - return false; - } + /* Qt containers have int (rather than uint) allowable indexes. */ + if (index > INT_MAX) { + generateWarning(engine(), QLatin1String("Index out of range during indexed set")); + return false; + } - if (d()->isReadOnly) { - engine()->throwTypeError(QLatin1String("Cannot insert into a readonly container")); + if (d()->isReadOnly) { + engine()->throwTypeError(QLatin1String("Cannot insert into a readonly container")); + return false; + } + + if (d()->isReference) { + if (!d()->object) return false; - } + loadReference(); + } - if (d()->isReference) { - if (!d()->object) - return false; - loadReference(); - } + quint32 count = quint32(size()); + const QMetaType valueType = valueMetaType(d()); + const QVariant element = engine()->toVariant(value, valueType, false); - quint32 count = quint32(size()); - const QMetaType valueType = valueMetaType(d()); - const QVariant element = engine()->toVariant(value, valueType, false); - - if (index == count) { - append(element); - } else if (index < count) { - replace(index, element); - } else { - /* according to ECMA262r3 we need to insert */ - /* the value at the given index, increasing length to index+1. */ - while (index > count++) { - append(valueType == QMetaType::fromType<QVariant>() - ? QVariant() - : QVariant(valueType)); - } - append(element); + if (index == count) { + append(element); + } else if (index < count) { + replace(index, element); + } else { + /* according to ECMA262r3 we need to insert */ + /* the value at the given index, increasing length to index+1. */ + while (index > count++) { + append(valueType == QMetaType::fromType<QVariant>() + ? QVariant() + : QVariant(valueType)); } - - if (d()->isReference) - storeReference(); - return true; + append(element); } - QV4::PropertyAttributes containerQueryIndexed(uint index) const - { - /* Qt containers have int (rather than uint) allowable indexes. */ - if (index > INT_MAX) { - generateWarning(engine(), QLatin1String("Index out of range during indexed query")); + if (d()->isReference) + storeReference(); + return true; +} + +PropertyAttributes Sequence::containerQueryIndexed(uint index) const +{ + /* Qt containers have int (rather than uint) allowable indexes. */ + if (index > INT_MAX) { + generateWarning(engine(), QLatin1String("Index out of range during indexed query")); + return QV4::Attr_Invalid; + } + if (d()->isReference) { + if (!d()->object) return QV4::Attr_Invalid; - } - if (d()->isReference) { - if (!d()->object) - return QV4::Attr_Invalid; - loadReference(); - } - return (index < quint32(size())) ? QV4::Attr_Data : QV4::Attr_Invalid; + loadReference(); } + return (index < quint32(size())) ? QV4::Attr_Data : QV4::Attr_Invalid; +} - struct OwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator - { - ~OwnPropertyKeyIterator() override = default; - PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override - { - const QV4Sequence *s = static_cast<const QV4Sequence *>(o); - - if (s->d()->isReference) { - if (!s->d()->object) - return ObjectOwnPropertyKeyIterator::next(o, pd, attrs); - s->loadReference(); - } - - if (arrayIndex < quint32(s->size())) { - uint index = arrayIndex; - ++arrayIndex; - if (attrs) - *attrs = QV4::Attr_Data; - if (pd) - pd->value = s->engine()->fromVariant(s->at(index)); - return PropertyKey::fromArrayIndex(index); - } - - return ObjectOwnPropertyKeyIterator::next(o, pd, attrs); - } - }; - - static OwnPropertyKeyIterator *containerOwnPropertyKeys(const Object *m, Value *target) - { - *target = *m; - return new OwnPropertyKeyIterator; - } +SequenceOwnPropertyKeyIterator *containerOwnPropertyKeys(const Object *m, Value *target) +{ + *target = *m; + return new SequenceOwnPropertyKeyIterator; +} - bool containerDeleteIndexedProperty(uint index) - { - /* Qt containers have int (rather than uint) allowable indexes. */ - if (index > INT_MAX) - return false; - if (d()->isReadOnly) +bool Sequence::containerDeleteIndexedProperty(uint index) +{ + /* Qt containers have int (rather than uint) allowable indexes. */ + if (index > INT_MAX) + return false; + if (d()->isReadOnly) + return false; + if (d()->isReference) { + if (!d()->object) return false; - if (d()->isReference) { - if (!d()->object) - return false; - loadReference(); - } + loadReference(); + } - if (index >= quint32(size())) - return false; + if (index >= quint32(size())) + return false; - /* according to ECMA262r3 it should be Undefined, */ - /* but we cannot, so we insert a default-value instead. */ - replace(index, QVariant()); + /* according to ECMA262r3 it should be Undefined, */ + /* but we cannot, so we insert a default-value instead. */ + replace(index, QVariant()); - if (d()->isReference) - storeReference(); + if (d()->isReference) + storeReference(); - return true; - } + return true; +} - bool containerIsEqualTo(Managed *other) - { - if (!other) - return false; - QV4Sequence *otherSequence = other->as<QV4Sequence>(); - if (!otherSequence) - return false; - if (d()->isReference && otherSequence->d()->isReference) { - return d()->object == otherSequence->d()->object && d()->propertyIndex == otherSequence->d()->propertyIndex; - } else if (!d()->isReference && !otherSequence->d()->isReference) { - return this == otherSequence; - } +bool Sequence::containerIsEqualTo(Managed *other) +{ + if (!other) + return false; + Sequence *otherSequence = other->as<Sequence>(); + if (!otherSequence) return false; + if (d()->isReference && otherSequence->d()->isReference) { + return d()->object == otherSequence->d()->object && d()->propertyIndex == otherSequence->d()->propertyIndex; + } else if (!d()->isReference && !otherSequence->d()->isReference) { + return this == otherSequence; } + return false; +} - struct DefaultCompareFunctor - { - bool operator()(const QVariant &lhs, const QVariant &rhs) - { - return lhs.toString() < rhs.toString(); - } - }; - - struct CompareFunctor - { - CompareFunctor(QV4::ExecutionEngine *v4, const QV4::Value &compareFn) - : m_v4(v4), m_compareFn(&compareFn) - {} - - bool operator()(const QVariant &lhs, const QVariant &rhs) - { - QV4::Scope scope(m_v4); - ScopedFunctionObject compare(scope, m_compareFn); - if (!compare) - return m_v4->throwTypeError(); - Value *argv = scope.alloc(2); - argv[0] = m_v4->fromVariant(lhs); - argv[1] = m_v4->fromVariant(rhs); - QV4::ScopedValue result(scope, compare->call(m_v4->globalObject, argv, 2)); - if (scope.hasException()) - return false; - return result->toNumber() < 0; - } - - private: - QV4::ExecutionEngine *m_v4; - const QV4::Value *m_compareFn; - }; - - bool sort(const FunctionObject *f, const Value *, const Value *argv, int argc) - { - if (d()->isReadOnly) +bool Sequence::sort(const FunctionObject *f, const Value *, const Value *argv, int argc) +{ + if (d()->isReadOnly) + return false; + if (d()->isReference) { + if (!d()->object) return false; - if (d()->isReference) { - if (!d()->object) - return false; - loadReference(); - } - - if (argc == 1 && argv[0].as<FunctionObject>()) - sort(CompareFunctor(f->engine(), argv[0])); - else - sort(DefaultCompareFunctor()); - - if (d()->isReference) - storeReference(); - - return true; + loadReference(); } - void* getRawContainerPtr() const - { return d()->container; } + if (argc == 1 && argv[0].as<FunctionObject>()) + sortSequence(this, SequenceCompareFunctor(f->engine(), argv[0])); + else + sortSequence(this, SequenceDefaultCompareFunctor()); - void loadReference() const - { - Q_ASSERT(d()->object); - Q_ASSERT(d()->isReference); - void *a[] = { d()->container, nullptr }; - QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->propertyIndex, a); - } + if (d()->isReference) + storeReference(); - void storeReference() - { - Q_ASSERT(d()->object); - Q_ASSERT(d()->isReference); - int status = -1; - QQmlPropertyData::WriteFlags flags = QQmlPropertyData::DontRemoveBinding; - void *a[] = { d()->container, nullptr, &status, &flags }; - QMetaObject::metacall(d()->object, QMetaObject::WriteProperty, d()->propertyIndex, a); - } - - static QV4::ReturnedValue virtualGet(const QV4::Managed *that, PropertyKey id, const Value *receiver, bool *hasProperty) - { - if (!id.isArrayIndex()) - return Object::virtualGet(that, id, receiver, hasProperty); - return static_cast<const QV4Sequence *>(that)->containerGetIndexed(id.asArrayIndex(), hasProperty); - } - static bool virtualPut(Managed *that, PropertyKey id, const QV4::Value &value, Value *receiver) - { - if (id.isArrayIndex()) - return static_cast<QV4Sequence *>(that)->containerPutIndexed(id.asArrayIndex(), value); - return Object::virtualPut(that, id, value, receiver); - } - static QV4::PropertyAttributes queryIndexed(const QV4::Managed *that, uint index) - { return static_cast<const QV4Sequence *>(that)->containerQueryIndexed(index); } - static bool virtualDeleteProperty(QV4::Managed *that, PropertyKey id) - { - if (id.isArrayIndex()) { - uint index = id.asArrayIndex(); - return static_cast<QV4Sequence *>(that)->containerDeleteIndexedProperty(index); - } - return Object::virtualDeleteProperty(that, id); - } - static bool virtualIsEqualTo(Managed *that, Managed *other) - { return static_cast<QV4Sequence *>(that)->containerIsEqualTo(other); } - static QV4::OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target) - { return static_cast<const QV4Sequence *>(m)->containerOwnPropertyKeys(m, target);} -}; + return true; +} +void *Sequence::getRawContainerPtr() const +{ return d()->container; } -void Heap::QV4Sequence::init(const QQmlType &qmlType, const void *container) +void Sequence::loadReference() const { - Object::init(); - - Q_ASSERT(qmlType.isSequentialContainer()); - typePrivate = qmlType.priv(); - QQmlType::refHandle(typePrivate); + Q_ASSERT(d()->object); + Q_ASSERT(d()->isReference); + void *a[] = { d()->container, nullptr }; + QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->propertyIndex, a); +} - this->container = typePrivate->listId.create(container); - propertyIndex = -1; - isReference = false; - isReadOnly = false; - object.init(); +void Sequence::storeReference() +{ + Q_ASSERT(d()->object); + Q_ASSERT(d()->isReference); + int status = -1; + QQmlPropertyData::WriteFlags flags = QQmlPropertyData::DontRemoveBinding; + void *a[] = { d()->container, nullptr, &status, &flags }; + QMetaObject::metacall(d()->object, QMetaObject::WriteProperty, d()->propertyIndex, a); +} - QV4::Scope scope(internalClass->engine); - QV4::Scoped<QV4::QV4Sequence> o(scope, this); - o->setArrayType(Heap::ArrayData::Custom); +ReturnedValue Sequence::virtualGet(const Managed *that, PropertyKey id, const Value *receiver, bool *hasProperty) +{ + if (!id.isArrayIndex()) + return Object::virtualGet(that, id, receiver, hasProperty); + return static_cast<const Sequence *>(that)->containerGetIndexed(id.asArrayIndex(), hasProperty); } -void Heap::QV4Sequence::init(QObject *object, int propertyIndex, const QQmlType &qmlType, - bool readOnly) +bool Sequence::virtualPut(Managed *that, PropertyKey id, const Value &value, Value *receiver) { - Object::init(); + if (id.isArrayIndex()) + return static_cast<Sequence *>(that)->containerPutIndexed(id.asArrayIndex(), value); + return Object::virtualPut(that, id, value, receiver); +} - Q_ASSERT(qmlType.isSequentialContainer()); - typePrivate = qmlType.priv(); - QQmlType::refHandle(typePrivate); - container = QMetaType(typePrivate->listId).create(); - this->propertyIndex = propertyIndex; - isReference = true; - this->isReadOnly = readOnly; - this->object.init(object); - QV4::Scope scope(internalClass->engine); - QV4::Scoped<QV4::QV4Sequence> o(scope, this); - o->setArrayType(Heap::ArrayData::Custom); - o->loadReference(); +PropertyAttributes Sequence::queryIndexed(const Managed *that, uint index) +{ return static_cast<const Sequence *>(that)->containerQueryIndexed(index); } + +bool Sequence::virtualDeleteProperty(Managed *that, PropertyKey id) +{ + if (id.isArrayIndex()) { + uint index = id.asArrayIndex(); + return static_cast<Sequence *>(that)->containerDeleteIndexedProperty(index); + } + return Object::virtualDeleteProperty(that, id); } +bool Sequence::virtualIsEqualTo(Managed *that, Managed *other) +{ + return static_cast<Sequence *>(that)->containerIsEqualTo(other); } -namespace QV4 { -DEFINE_OBJECT_VTABLE(QV4Sequence); +OwnPropertyKeyIterator *Sequence::virtualOwnPropertyKeys(const Object *m, Value *target) +{ + return containerOwnPropertyKeys(m, target); } static QV4::ReturnedValue method_get_length(const FunctionObject *b, const Value *thisObject, const Value *, int) { QV4::Scope scope(b); - QV4::Scoped<QV4Sequence> This(scope, thisObject->as<QV4Sequence>()); + QV4::Scoped<Sequence> This(scope, thisObject->as<Sequence>()); if (!This) THROW_TYPE_ERROR(); @@ -549,7 +521,7 @@ static QV4::ReturnedValue method_get_length(const FunctionObject *b, const Value static QV4::ReturnedValue method_set_length(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc) { QV4::Scope scope(f); - QV4::Scoped<QV4Sequence> This(scope, thisObject->as<QV4Sequence>()); + QV4::Scoped<Sequence> This(scope, thisObject->as<Sequence>()); if (!This) THROW_TYPE_ERROR(); @@ -575,7 +547,7 @@ static QV4::ReturnedValue method_set_length(const FunctionObject *f, const Value if (newCount == count) { RETURN_UNDEFINED(); } else if (newCount > count) { - const QMetaType valueMetaType = meta(This->d())->valueMetaType(); + const QMetaType valueMetaType = metaSequence(This->d())->valueMetaType(); /* according to ECMA262r3 we need to insert */ /* undefined values increasing length to newLength. */ /* We cannot, so we insert default-values instead. */ @@ -617,7 +589,7 @@ ReturnedValue SequencePrototype::method_sort(const FunctionObject *b, const Valu if (argc >= 2) return o.asReturnedValue(); - if (auto *s = o->as<QV4Sequence>()) { + if (auto *s = o->as<Sequence>()) { if (!s->sort(b, thisObject, argv, argc)) THROW_TYPE_ERROR(); } @@ -638,7 +610,7 @@ ReturnedValue SequencePrototype::newSequence( const QQmlType qmlType = QQmlMetaType::qmlListType(sequenceType); if (qmlType.isSequentialContainer()) { *succeeded = true; - QV4::ScopedObject obj(scope, engine->memoryManager->allocate<QV4Sequence>( + QV4::ScopedObject obj(scope, engine->memoryManager->allocate<Sequence>( object, propertyIndex, qmlType, readOnly)); return obj.asReturnedValue(); } @@ -664,7 +636,7 @@ ReturnedValue SequencePrototype::fromData(ExecutionEngine *engine, QMetaType typ const QQmlType qmlType = QQmlMetaType::qmlListType(type); if (qmlType.isSequentialContainer()) { *succeeded = true; - QV4::ScopedObject obj(scope, engine->memoryManager->allocate<QV4Sequence>(qmlType, data)); + QV4::ScopedObject obj(scope, engine->memoryManager->allocate<Sequence>(qmlType, data)); return obj.asReturnedValue(); } @@ -672,10 +644,10 @@ ReturnedValue SequencePrototype::fromData(ExecutionEngine *engine, QMetaType typ return Encode::undefined(); } -QVariant SequencePrototype::toVariant(Object *object) +QVariant SequencePrototype::toVariant(const Sequence *object) { Q_ASSERT(object->isListType()); - return object->as<QV4Sequence>()->toVariant(); + return object->toVariant(); } QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHint, bool *succeeded) @@ -721,22 +693,20 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHin return QVariant(); } -void *SequencePrototype::getRawContainerPtr(const Object *object, QMetaType typeHint) +void *SequencePrototype::getRawContainerPtr(const Sequence *object, QMetaType typeHint) { - if (auto *s = object->as<QV4Sequence>()) { - if (s->d()->typePrivate->listId == typeHint) - return s->getRawContainerPtr(); - } + if (object->d()->typePrivate->listId == typeHint) + return object->getRawContainerPtr(); return nullptr; } -QMetaType SequencePrototype::metaTypeForSequence(const QV4::Object *object) +QMetaType SequencePrototype::metaTypeForSequence(const Sequence *object) { - if (auto *s = object->as<QV4Sequence>()) - return s->d()->typePrivate->listId; - return QMetaType(); + return object->d()->typePrivate->listId; } +} // namespace QV4 + QT_END_NAMESPACE #include "moc_qv4sequenceobject_p.cpp" |