Implement objectiterator on top of an iterator method in the vtbl
authorSimon Hausmann <simon.hausmann@digia.com>
Mon, 10 Jun 2013 15:11:52 +0000 (17:11 +0200)
committerLars Knoll <lars.knoll@digia.com>
Tue, 11 Jun 2013 14:00:28 +0000 (16:00 +0200)
This makes it easier to implement the array-like wrapper classes
for qml lists and qt lists.

Change-Id: I169025a3e9c76951c0778bcda4bbb1f9a8afc8a0
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
14 files changed:
src/qml/qml/qqmllistwrapper.cpp
src/qml/qml/qqmllistwrapper_p.h
src/qml/qml/v4/qv4managed.cpp
src/qml/qml/v4/qv4managed_p.h
src/qml/qml/v4/qv4object.cpp
src/qml/qml/v4/qv4object_p.h
src/qml/qml/v4/qv4objectiterator.cpp
src/qml/qml/v4/qv4objectiterator_p.h
src/qml/qml/v4/qv4regexp.cpp
src/qml/qml/v4/qv4regexp_p.h
src/qml/qml/v4/qv4sequenceobject.cpp
src/qml/qml/v4/qv4string.cpp
src/qml/qml/v4/qv4stringobject.cpp
src/qml/qml/v4/qv4stringobject_p.h

index ec34905..719119c 100644 (file)
@@ -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<v8::Array> QV8ListWrapper::Enumerator(const v8::AccessorInfo &info)
+Property *QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs)
 {
-    QV8ListResource *resource = v8_resource_cast<QV8ListResource>(info.This());
-
-    if (!resource || resource->object.isNull()) return v8::Array::New();
-
-    quint32 count = resource->property.count?resource->property.count(&resource->property):0;
-
-    v8::Handle<v8::Array> 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<QmlListWrapper>();
+    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
index 5e8a84b..de2a047 100644 (file)
@@ -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:
index 1adf310..efba827 100644 (file)
@@ -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);
index 3b1d4d0..ab7d902 100644 (file)
@@ -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;
 };
 
 }
index 89b8575..e8cf23d 100644 (file)
@@ -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<Object *>(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)
index 98bb218..d21f33d 100644 (file)
@@ -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:
index 446b79e..9c48ec7 100644 (file)
@@ -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<StringObject *>(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;
 }
index a481a75..6a29dd9 100644 (file)
@@ -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);
index 1c059d2..aa20751 100644 (file)
@@ -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;
+}
index b850599..4fb075e 100644 (file)
@@ -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;
index 1c386d7..be9bbfc 100644 (file)
@@ -76,27 +76,27 @@ static void generateWarning(QV4::ExecutionContext *ctx, const QString& descripti
     F(QString, QString, QStringList, QString()) \
     F(QUrl, Url, QList<QUrl>, 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<qint32>(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<QQmlSequence<Container> *>(that)->containerDeleteIndexedProperty(ctx, index); }
     static bool isEqualTo(Managed *that, Managed *other)
     { return static_cast<QQmlSequence<Container> *>(that)->containerIsEqualTo(other); }
+    static Property *advanceIterator(Managed *that, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs)
+    { return static_cast<QQmlSequence<Container> *>(that)->containerAdvanceIterator(it, name, index, attrs); }
 
     static void destroy(Managed *that)
     {
index a310fbe..52e9949 100644 (file)
@@ -92,6 +92,7 @@ const ManagedVTable String::static_vtbl =
     0 /*getLookup*/,
     0 /*setLookup*/,
     Managed::isEqualTo,
+    0 /*advanceIterator*/,
     "String",
 };
 
index 0b8598f..912db7d 100644 (file)
@@ -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<StringObject *>(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<StringObject *>(that);
index 7bd08fa..cbd7fef 100644 (file)
@@ -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);
 };