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 | |
11 | QT_BEGIN_NAMESPACE |
12 | |
13 | QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValue &v) |
14 | { |
15 | init(v); |
16 | } |
17 | |
18 | void 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 | |
35 | void 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 | |
51 | bool 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 | */ |
93 | QJSValueIterator::QJSValueIterator(const QJSValue& object) |
94 | : d_ptr(new QJSValueIteratorPrivate(object)) |
95 | { |
96 | } |
97 | |
98 | /*! |
99 | Destroys the iterator. |
100 | */ |
101 | QJSValueIterator::~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 | */ |
112 | bool 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 | */ |
127 | bool 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 | */ |
141 | QString 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 | */ |
160 | QJSValue 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 | */ |
185 | QJSValueIterator& QJSValueIterator::operator=(QJSValue& object) |
186 | { |
187 | d_ptr->init(v: object); |
188 | return *this; |
189 | } |
190 | |
191 | QT_END_NAMESPACE |
192 |