From 83ede4249bf24b8a88db0ce957de27052b7aba7c Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 10 Jun 2013 17:11:52 +0200 Subject: [PATCH] Implement objectiterator on top of an iterator method in the vtbl This makes it easier to implement the array-like wrapper classes for qml lists and qt lists. Change-Id: I169025a3e9c76951c0778bcda4bbb1f9a8afc8a0 Reviewed-by: Lars Knoll --- src/qml/qml/qqmllistwrapper.cpp | 34 +++++----- src/qml/qml/qqmllistwrapper_p.h | 1 + src/qml/qml/v4/qv4managed.cpp | 2 +- src/qml/qml/v4/qv4managed_p.h | 7 +++ src/qml/qml/v4/qv4object.cpp | 61 ++++++++++++++++++ src/qml/qml/v4/qv4object_p.h | 2 + src/qml/qml/v4/qv4objectiterator.cpp | 118 +++-------------------------------- src/qml/qml/v4/qv4objectiterator_p.h | 3 - src/qml/qml/v4/qv4regexp.cpp | 5 ++ src/qml/qml/v4/qv4regexp_p.h | 2 +- src/qml/qml/v4/qv4sequenceobject.cpp | 46 ++++++++++---- src/qml/qml/v4/qv4string.cpp | 1 + src/qml/qml/v4/qv4stringobject.cpp | 21 +++++++ src/qml/qml/v4/qv4stringobject_p.h | 1 + 14 files changed, 163 insertions(+), 141 deletions(-) diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp index ec34905..719119c 100644 --- a/src/qml/qml/qqmllistwrapper.cpp +++ b/src/qml/qml/qqmllistwrapper.cpp @@ -108,6 +108,10 @@ Value QmlListWrapper::get(Managed *m, ExecutionContext *ctx, String *name, bool return Value::fromUInt32(count); } + uint idx = name->asArrayIndex(); + if (idx != UINT_MAX) + return getIndexed(m, ctx, idx, hasProperty); + return Value::undefinedValue(); } @@ -139,23 +143,21 @@ void QmlListWrapper::destroy(Managed *that) w->~QmlListWrapper(); } -#if 0 -// ### does this need porting? -v8::Handle QV8ListWrapper::Enumerator(const v8::AccessorInfo &info) +Property *QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs) { - QV8ListResource *resource = v8_resource_cast(info.This()); - - if (!resource || resource->object.isNull()) return v8::Array::New(); - - quint32 count = resource->property.count?resource->property.count(&resource->property):0; - - v8::Handle rv = v8::Array::New(count); - - for (uint ii = 0; ii < count; ++ii) - rv->Set(ii, Value::fromDouble(ii)); - - return rv; + *name = 0; + *index = UINT_MAX; + QmlListWrapper *w = m->as(); + quint32 count = w->property.count ? w->property.count(&w->property) : 0; + if (it->arrayIndex < count) { + if (attrs) + *attrs = QV4::Attr_Data; + *index = it->arrayIndex; + ++it->arrayIndex; + it->tmpDynamicProperty.value = QV4::QObjectWrapper::wrap(w->engine(), w->property.at(&w->property, *index)); + return &it->tmpDynamicProperty; + } + return QV4::Object::advanceIterator(m, it, name, index, attrs); } -#endif QT_END_NAMESPACE diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h index 5e8a84b..de2a047 100644 --- a/src/qml/qml/qqmllistwrapper_p.h +++ b/src/qml/qml/qqmllistwrapper_p.h @@ -83,6 +83,7 @@ public: static Value get(Managed *m, ExecutionContext *ctx, String *name, bool *hasProperty); static Value getIndexed(Managed *m, ExecutionContext *ctx, uint index, bool *hasProperty); static void put(Managed *m, ExecutionContext *ctx, String *name, const Value &value); + static Property *advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes); static void destroy(Managed *that); private: diff --git a/src/qml/qml/v4/qv4managed.cpp b/src/qml/qml/v4/qv4managed.cpp index 1adf310..efba827 100644 --- a/src/qml/qml/v4/qv4managed.cpp +++ b/src/qml/qml/v4/qv4managed.cpp @@ -63,6 +63,7 @@ const ManagedVTable Managed::static_vtbl = 0, 0, isEqualTo, + 0, "Managed", }; @@ -199,7 +200,6 @@ bool Managed::isEqualTo(Managed *, Managed *) return false; } - Value Managed::get(ExecutionContext *ctx, String *name, bool *hasProperty) { return vtbl->get(this, ctx, name, hasProperty); diff --git a/src/qml/qml/v4/qv4managed_p.h b/src/qml/qml/v4/qv4managed_p.h index 3b1d4d0..ab7d902 100644 --- a/src/qml/qml/v4/qv4managed_p.h +++ b/src/qml/qml/v4/qv4managed_p.h @@ -54,9 +54,11 @@ class MemoryManager; struct String; struct Object; struct ObjectPrototype; +struct ObjectIterator; struct ExecutionContext; struct ScriptFunction; struct InternalClass; +struct Property; struct BooleanObject; struct NumberObject; @@ -106,6 +108,7 @@ struct ManagedVTable void (*getLookup)(Managed *m, ExecutionContext *ctx, Lookup *l, Value *result); void (*setLookup)(Managed *m, ExecutionContext *ctx, Lookup *l, const Value &v); bool (*isEqualTo)(Managed *m, Managed *other); + Property *(*advanceIterator)(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes); const char *className; }; @@ -128,6 +131,7 @@ const QV4::ManagedVTable classname::static_vtbl = \ getLookup, \ setLookup, \ isEqualTo, \ + advanceIterator, \ #classname \ } @@ -248,6 +252,8 @@ public: bool isEqualTo(Managed *other) { return vtbl->isEqualTo(this, other); } + Property *advanceIterator(ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes) + { return vtbl->advanceIterator(this, it, name, index, attributes); } static void destroy(Managed *that) { that->_data = 0; } static bool hasInstance(Managed *that, ExecutionContext *ctx, const Value &value); @@ -290,6 +296,7 @@ public: private: friend class MemoryManager; friend struct Identifiers; + friend struct ObjectIterator; }; } diff --git a/src/qml/qml/v4/qv4object.cpp b/src/qml/qml/v4/qv4object.cpp index 89b8575..e8cf23d 100644 --- a/src/qml/qml/v4/qv4object.cpp +++ b/src/qml/qml/v4/qv4object.cpp @@ -516,6 +516,67 @@ void Object::setLookup(Managed *m, ExecutionContext *ctx, Lookup *l, const Value o->put(ctx, l->name, value); } +Property *Object::advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs) +{ + Object *o = static_cast(m); + *name = 0; + *index = UINT_MAX; + + if (!it->arrayIndex) + it->arrayNode = o->sparseArrayBegin(); + + // sparse arrays + if (it->arrayNode) { + while (it->arrayNode != o->sparseArrayEnd()) { + int k = it->arrayNode->key(); + uint pidx = it->arrayNode->value; + Property *p = o->arrayData + pidx; + it->arrayNode = it->arrayNode->nextNode(); + PropertyAttributes a = o->arrayAttributes ? o->arrayAttributes[pidx] : PropertyAttributes(Attr_Data); + if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) { + it->arrayIndex = k + 1; + *index = k; + if (attrs) + *attrs = a; + return p; + } + } + it->arrayNode = 0; + it->arrayIndex = UINT_MAX; + } + // dense arrays + while (it->arrayIndex < o->arrayDataLen) { + uint pidx = o->propertyIndexFromArrayIndex(it->arrayIndex); + Property *p = o->arrayData + pidx; + PropertyAttributes a = o->arrayAttributes ? o->arrayAttributes[pidx] : PropertyAttributes(Attr_Data); + ++it->arrayIndex; + if ((!o->arrayAttributes || !o->arrayAttributes[pidx].isGeneric()) + && (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable())) { + *index = it->arrayIndex - 1; + if (attrs) + *attrs = a; + return p; + } + } + + while (it->memberIndex < o->internalClass->size) { + String *n = o->internalClass->nameMap.at(it->memberIndex); + assert(n); + // ### check that it's not a repeated attribute + + Property *p = o->memberData + it->memberIndex; + PropertyAttributes a = o->internalClass->propertyData[it->memberIndex]; + ++it->memberIndex; + if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) { + *name = n; + if (attrs) + *attrs = a; + return p; + } + } + + return 0; +} // Section 8.12.3 Value Object::internalGet(ExecutionContext *ctx, String *name, bool *hasProperty) diff --git a/src/qml/qml/v4/qv4object_p.h b/src/qml/qml/v4/qv4object_p.h index 98bb218..d21f33d 100644 --- a/src/qml/qml/v4/qv4object_p.h +++ b/src/qml/qml/v4/qv4object_p.h @@ -345,6 +345,7 @@ public: using Managed::deleteIndexedProperty; using Managed::getLookup; using Managed::setLookup; + using Managed::advanceIterator; protected: static const ManagedVTable static_vtbl; static void destroy(Managed *that); @@ -359,6 +360,7 @@ protected: static bool deleteIndexedProperty(Managed *m, ExecutionContext *ctx, uint index); static void getLookup(Managed *m, ExecutionContext *ctx, Lookup *l, Value *result); static void setLookup(Managed *m, ExecutionContext *ctx, Lookup *l, const Value &v); + static Property *advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes); private: diff --git a/src/qml/qml/v4/qv4objectiterator.cpp b/src/qml/qml/v4/qv4objectiterator.cpp index 446b79e..9c48ec7 100644 --- a/src/qml/qml/v4/qv4objectiterator.cpp +++ b/src/qml/qml/v4/qv4objectiterator.cpp @@ -47,24 +47,13 @@ using namespace QV4; ObjectIterator::ObjectIterator(Object *o, uint flags) : object(o) - , internalClass(o ? o->internalClass : 0) , current(o) , arrayNode(0) , arrayIndex(0) , memberIndex(0) , flags(flags) - , wrappedListLength(0) { tmpDynamicProperty.value = Value::undefinedValue(); - if (current) { - if (current->asStringObject()) - this->flags |= CurrentIsString; - - if (current->isListType()) { - wrappedListLength = current->get(o->engine()->id_length).toUInt32(); - assert(current->arrayDataLen == 0); - } - } } Property *ObjectIterator::next(String **name, uint *index, PropertyAttributes *attrs) @@ -76,106 +65,17 @@ Property *ObjectIterator::next(String **name, uint *index, PropertyAttributes *a if (!current) break; - if (flags & CurrentIsString) { - StringObject *s = static_cast(current); - uint slen = s->value.stringValue()->toQString().length(); - while (arrayIndex < slen) { - *index = arrayIndex; - ++arrayIndex; - if (attrs) - *attrs = s->arrayAttributes ? s->arrayAttributes[arrayIndex] : PropertyAttributes(Attr_NotWritable|Attr_NotConfigurable); - return s->__getOwnProperty__(*index); - } - flags &= ~CurrentIsString; - arrayNode = current->sparseArrayBegin(); - // iterate until we're past the end of the string - while (arrayNode && arrayNode->key() < slen) - arrayNode = arrayNode->nextNode(); - } - - if (!arrayIndex) - arrayNode = current->sparseArrayBegin(); - - // sparse arrays - if (arrayNode) { - while (arrayNode != current->sparseArrayEnd()) { - int k = arrayNode->key(); - uint pidx = arrayNode->value; - p = current->arrayData + pidx; - arrayNode = arrayNode->nextNode(); - PropertyAttributes a = current->arrayAttributes ? current->arrayAttributes[pidx] : PropertyAttributes(Attr_Data); - if (!(flags & EnumerableOnly) || a.isEnumerable()) { - arrayIndex = k + 1; - *index = k; - if (attrs) - *attrs = a; - return p; - } - } - arrayNode = 0; - arrayIndex = UINT_MAX; - } - // dense arrays - while (arrayIndex < current->arrayDataLen) { - uint pidx = current->propertyIndexFromArrayIndex(arrayIndex); - p = current->arrayData + pidx; - PropertyAttributes a = current->arrayAttributes ? current->arrayAttributes[pidx] : PropertyAttributes(Attr_Data); - ++arrayIndex; - if ((!current->arrayAttributes || !current->arrayAttributes[pidx].isGeneric()) - && (!(flags & EnumerableOnly) || a.isEnumerable())) { - *index = arrayIndex - 1; - if (attrs) - *attrs = a; - return p; - } - } - - while (arrayIndex < wrappedListLength) { - PropertyAttributes a = current->queryIndexed(arrayIndex); - ++arrayIndex; - if (!(flags & EnumerableOnly) || a.isEnumerable()) { - *index = arrayIndex - 1; - if (attrs) - *attrs = a; - tmpDynamicProperty.value = current->getIndexed(*index); - return &tmpDynamicProperty; - } - } - - if (memberIndex == internalClass->size) { - if (flags & WithProtoChain) - current = current->prototype; - else - current = 0; - if (current && current->asStringObject()) - flags |= CurrentIsString; - else - flags &= ~CurrentIsString; - - internalClass = current ? current->internalClass : 0; - - arrayIndex = 0; - memberIndex = 0; + p = current->advanceIterator(this, name, index, attrs); + if (p) + return p; - if (current && current->isListType()) { - wrappedListLength = current->get(current->engine()->id_length).toUInt32(); - assert(current->arrayDataLen == 0); - } - continue; - } - String *n = internalClass->nameMap.at(memberIndex); - assert(n); - // ### check that it's not a repeated attribute + if (flags & WithProtoChain) + current = current->prototype; + else + current = 0; - p = current->memberData + memberIndex; - PropertyAttributes a = internalClass->propertyData[memberIndex]; - ++memberIndex; - if (!(flags & EnumerableOnly) || a.isEnumerable()) { - *name = n; - if (attrs) - *attrs = a; - return p; - } + arrayIndex = 0; + memberIndex = 0; } return 0; } diff --git a/src/qml/qml/v4/qv4objectiterator_p.h b/src/qml/qml/v4/qv4objectiterator_p.h index a481a75..6a29dd9 100644 --- a/src/qml/qml/v4/qv4objectiterator_p.h +++ b/src/qml/qml/v4/qv4objectiterator_p.h @@ -64,11 +64,9 @@ struct Q_QML_EXPORT ObjectIterator NoFlags = 0, EnumerableOnly = 0x1, WithProtoChain = 0x2, - CurrentIsString = 0x4 }; Object *object; - InternalClass *internalClass; Object *current; SparseArrayNode *arrayNode; uint arrayIndex; @@ -76,7 +74,6 @@ struct Q_QML_EXPORT ObjectIterator uint flags; Property tmpDynamicProperty; - uint wrappedListLength; ObjectIterator(Object *o, uint flags); Property *next(String **name, uint *index, PropertyAttributes *attributes = 0); diff --git a/src/qml/qml/v4/qv4regexp.cpp b/src/qml/qml/v4/qv4regexp.cpp index 1c059d2..aa20751 100644 --- a/src/qml/qml/v4/qv4regexp.cpp +++ b/src/qml/qml/v4/qv4regexp.cpp @@ -173,3 +173,8 @@ bool RegExp::deleteIndexedProperty(Managed *m, ExecutionContext *ctx, uint index { return false; } + +Property *RegExp::advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes) +{ + return 0; +} diff --git a/src/qml/qml/v4/qv4regexp_p.h b/src/qml/qml/v4/qv4regexp_p.h index b850599..4fb075e 100644 --- a/src/qml/qml/v4/qv4regexp_p.h +++ b/src/qml/qml/v4/qv4regexp_p.h @@ -119,7 +119,7 @@ protected: static PropertyAttributes queryIndexed(const Managed *m, uint index); static bool deleteProperty(Managed *m, ExecutionContext *ctx, String *name); static bool deleteIndexedProperty(Managed *m, ExecutionContext *ctx, uint index); - + static Property *advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes); private: friend class RegExpCache; diff --git a/src/qml/qml/v4/qv4sequenceobject.cpp b/src/qml/qml/v4/qv4sequenceobject.cpp index 1c386d7..be9bbfc 100644 --- a/src/qml/qml/v4/qv4sequenceobject.cpp +++ b/src/qml/qml/v4/qv4sequenceobject.cpp @@ -76,27 +76,27 @@ static void generateWarning(QV4::ExecutionContext *ctx, const QString& descripti F(QString, QString, QStringList, QString()) \ F(QUrl, Url, QList, QUrl()) -static QV4::Value convertElementToValue(QV4::ExecutionContext *ctx, const QString &element) +static QV4::Value convertElementToValue(QV4::ExecutionEngine *engine, const QString &element) { - return QV4::Value::fromString(ctx, element); + return QV4::Value::fromString(engine, element); } -static QV4::Value convertElementToValue(QV4::ExecutionContext *ctx, int element) +static QV4::Value convertElementToValue(QV4::ExecutionEngine *, int element) { return QV4::Value::fromInt32(element); } -static QV4::Value convertElementToValue(QV4::ExecutionContext *ctx, const QUrl &element) +static QV4::Value convertElementToValue(QV4::ExecutionEngine *engine, const QUrl &element) { - return QV4::Value::fromString(ctx, element.toString()); + return QV4::Value::fromString(engine, element.toString()); } -static QV4::Value convertElementToValue(QV4::ExecutionContext *ctx, qreal element) +static QV4::Value convertElementToValue(QV4::ExecutionEngine *, qreal element) { return QV4::Value::fromDouble(element); } -static QV4::Value convertElementToValue(QV4::ExecutionContext *ctx, bool element) +static QV4::Value convertElementToValue(QV4::ExecutionEngine *, bool element) { return QV4::Value::fromBoolean(element); } @@ -210,7 +210,7 @@ public: if (signedIdx < m_container.count()) { if (hasProperty) *hasProperty = true; - return convertElementToValue(ctx, m_container.at(signedIdx)); + return convertElementToValue(ctx->engine, m_container.at(signedIdx)); } if (hasProperty) *hasProperty = false; @@ -268,7 +268,29 @@ public: loadReference(); } qint32 signedIdx = static_cast(index); - return (index < m_container.count()) ? QV4::Attr_Data : QV4::Attr_Invalid; + return (signedIdx < m_container.count()) ? QV4::Attr_Data : QV4::Attr_Invalid; + } + + Property *containerAdvanceIterator(ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs) + { + *name = 0; + *index = UINT_MAX; + + if (m_isReference) { + if (!m_object) + return QQmlSequenceBase::advanceIterator(this, it, name, index, attrs); + loadReference(); + } + + if (it->arrayIndex < m_container.count()) { + if (attrs) + *attrs = QV4::Attr_Data; + *index = it->arrayIndex; + ++it->arrayIndex; + it->tmpDynamicProperty.value = convertElementToValue(engine(), m_container.at(*index)); + return &it->tmpDynamicProperty; + } + return QQmlSequenceBase::advanceIterator(this, it, name, index, attrs); } bool containerDeleteIndexedProperty(QV4::ExecutionContext *ctx, uint index) @@ -335,8 +357,8 @@ public: { QV4::Managed *fun = this->m_compareFn.asManaged(); QV4::Value argv[2] = { - convertElementToValue(this->m_ctx, lhs), - convertElementToValue(this->m_ctx, rhs) + convertElementToValue(this->m_ctx->engine, lhs), + convertElementToValue(this->m_ctx->engine, rhs) }; QV4::Value result = fun->call(this->m_ctx, QV4::Value::fromObject(this->m_ctx->engine->globalObject), argv, 2); return result.toNumber() < 0; @@ -458,6 +480,8 @@ private: { return static_cast *>(that)->containerDeleteIndexedProperty(ctx, index); } static bool isEqualTo(Managed *that, Managed *other) { return static_cast *>(that)->containerIsEqualTo(other); } + static Property *advanceIterator(Managed *that, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs) + { return static_cast *>(that)->containerAdvanceIterator(it, name, index, attrs); } static void destroy(Managed *that) { diff --git a/src/qml/qml/v4/qv4string.cpp b/src/qml/qml/v4/qv4string.cpp index a310fbe..52e9949 100644 --- a/src/qml/qml/v4/qv4string.cpp +++ b/src/qml/qml/v4/qv4string.cpp @@ -92,6 +92,7 @@ const ManagedVTable String::static_vtbl = 0 /*getLookup*/, 0 /*setLookup*/, Managed::isEqualTo, + 0 /*advanceIterator*/, "String", }; diff --git a/src/qml/qml/v4/qv4stringobject.cpp b/src/qml/qml/v4/qv4stringobject.cpp index 0b8598f..912db7d 100644 --- a/src/qml/qml/v4/qv4stringobject.cpp +++ b/src/qml/qml/v4/qv4stringobject.cpp @@ -99,6 +99,27 @@ Property *StringObject::getIndex(uint index) const return &tmpProperty; } +Property *StringObject::advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs) +{ + StringObject *s = static_cast(m); + uint slen = s->value.stringValue()->toQString().length(); + if (it->arrayIndex < slen) { + while (it->arrayIndex < slen) { + *index = it->arrayIndex; + ++it->arrayIndex; + if (attrs) + *attrs = s->arrayAttributes ? s->arrayAttributes[it->arrayIndex] : PropertyAttributes(Attr_NotWritable|Attr_NotConfigurable); + return s->__getOwnProperty__(*index); + } + it->arrayNode = s->sparseArrayBegin(); + // iterate until we're past the end of the string + while (it->arrayNode && it->arrayNode->key() < slen) + it->arrayNode = it->arrayNode->nextNode(); + } + + return Object::advanceIterator(m, it, name, index, attrs); +} + void StringObject::markObjects(Managed *that) { StringObject *o = static_cast(that); diff --git a/src/qml/qml/v4/qv4stringobject_p.h b/src/qml/qml/v4/qv4stringobject_p.h index 7bd08fa..cbd7fef 100644 --- a/src/qml/qml/v4/qv4stringobject_p.h +++ b/src/qml/qml/v4/qv4stringobject_p.h @@ -57,6 +57,7 @@ struct StringObject: Object { Property *getIndex(uint index) const; protected: + static Property *advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs); static const ManagedVTable static_vtbl; static void markObjects(Managed *that); }; -- 2.7.4