1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qjsvalueiterator.h"
5#include "qjsvalueiterator_p.h"
6#include "qjsvalue_p.h"
7#include "private/qv4string_p.h"
8#include "private/qv4object_p.h"
9#include "private/qv4context_p.h"
10
11QT_BEGIN_NAMESPACE
12
13QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValue &v)
14{
15 init(v);
16}
17
18void QJSValueIteratorPrivate::init(const QJSValue &v)
19{
20 engine = nullptr;
21
22 QV4::ExecutionEngine *e = QJSValuePrivate::engine(jsval: &v);
23 if (!e)
24 return;
25 const QV4::Object *o = QJSValuePrivate::asManagedType<QV4::Object>(jsval: &v);
26 if (!o)
27 return;
28
29 engine = e;
30 object.set(engine: e, value: o->asReturnedValue());
31 iterator.reset(other: o->ownPropertyKeys(target: object.valueRef()));
32 next();
33}
34
35void QJSValueIteratorPrivate::next()
36{
37 QV4::Object *o = object.as<QV4::Object>();
38 if (!o || !iterator)
39 return;
40
41 QV4::PropertyKey key;
42 while (1) {
43 key = iterator->next(o);
44 if (!key.isSymbol())
45 break;
46 }
47 currentKey = nextKey;
48 nextKey.set(engine, value: key.id());
49}
50
51bool QJSValueIteratorPrivate::isValid() const
52{
53 if (!engine || !iterator)
54 return false;
55 QV4::Value *val = object.valueRef();
56 return (val && val->isObject());
57}
58
59/*!
60 \class QJSValueIterator
61
62 \brief The QJSValueIterator class provides a Java-style iterator for QJSValue.
63
64 \ingroup qtjavascript
65 \inmodule QtQml
66
67
68 The QJSValueIterator constructor takes a QJSValue as
69 argument. After construction, the iterator is located at the very
70 beginning of the sequence of properties. Here's how to iterate over
71 all the properties of a QJSValue:
72
73 \snippet code/src_script_qjsvalueiterator.cpp 0
74
75 The next() advances the iterator. The name() and value()
76 functions return the name and value of the last item that was
77 jumped over.
78
79 Note that QJSValueIterator only iterates over the QJSValue's
80 own properties; i.e. it does not follow the prototype chain. You can
81 use a loop like this to follow the prototype chain:
82
83 \snippet code/src_script_qjsvalueiterator.cpp 1
84
85 \sa QJSValue::property()
86*/
87
88/*!
89 Constructs an iterator for traversing \a object. The iterator is
90 set to be at the front of the sequence of properties (before the
91 first property).
92*/
93QJSValueIterator::QJSValueIterator(const QJSValue& object)
94 : d_ptr(new QJSValueIteratorPrivate(object))
95{
96}
97
98/*!
99 Destroys the iterator.
100*/
101QJSValueIterator::~QJSValueIterator()
102{
103}
104
105/*!
106 Returns true if there is at least one item ahead of the iterator
107 (i.e. the iterator is \e not at the back of the property sequence);
108 otherwise returns false.
109
110 \sa next()
111*/
112bool QJSValueIterator::hasNext() const
113{
114 if (!d_ptr->isValid())
115 return false;
116 return QV4::PropertyKey::fromId(id: d_ptr->nextKey.value()).isValid();
117}
118
119/*!
120 Advances the iterator by one position.
121 Returns true if there was at least one item ahead of the iterator
122 (i.e. the iterator was \e not already at the back of the property sequence);
123 otherwise returns false.
124
125 \sa hasNext(), name()
126*/
127bool QJSValueIterator::next()
128{
129 if (!d_ptr->isValid())
130 return false;
131 d_ptr->next();
132 return QV4::PropertyKey::fromId(id: d_ptr->currentKey.value()).isValid();
133}
134
135/*!
136 Returns the name of the last property that was jumped over using
137 next().
138
139 \sa value()
140*/
141QString QJSValueIterator::name() const
142{
143 if (!d_ptr->isValid())
144 return QString();
145 QV4::Scope scope(d_ptr->engine);
146 QV4::ScopedPropertyKey key(scope, QV4::PropertyKey::fromId(id: d_ptr->currentKey.value()));
147 if (!key->isValid())
148 return QString();
149 Q_ASSERT(!key->isSymbol());
150 return key->toStringOrSymbol(e: d_ptr->engine)->toQString();
151}
152
153
154/*!
155 Returns the value of the last property that was jumped over using
156 next().
157
158 \sa name()
159*/
160QJSValue QJSValueIterator::value() const
161{
162 if (!d_ptr->isValid())
163 return QJSValue();
164 QV4::Scope scope(d_ptr->engine);
165 QV4::ScopedPropertyKey key(scope, QV4::PropertyKey::fromId(id: d_ptr->currentKey.value()));
166 if (!key->isValid())
167 return QJSValue();
168
169 QV4::ScopedObject obj(scope, d_ptr->object.asManaged());
170 QV4::ScopedValue val(scope, obj->get(id: key));
171
172 if (scope.hasException()) {
173 scope.engine->catchException();
174 return QJSValue();
175 }
176 return QJSValuePrivate::fromReturnedValue(d: val->asReturnedValue());
177}
178
179
180/*!
181 Makes the iterator operate on \a object. The iterator is set to be
182 at the front of the sequence of properties (before the first
183 property).
184*/
185QJSValueIterator& QJSValueIterator::operator=(QJSValue& object)
186{
187 d_ptr->init(v: object);
188 return *this;
189}
190
191QT_END_NAMESPACE
192

source code of qtdeclarative/src/qml/jsapi/qjsvalueiterator.cpp