1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39#ifndef QV4ARRAYDATA_H
40#define QV4ARRAYDATA_H
41
42//
43// W A R N I N G
44// -------------
45//
46// This file is not part of the Qt API. It exists purely as an
47// implementation detail. This header file may change from version to
48// version without notice, or even be removed.
49//
50// We mean it.
51//
52
53#include "qv4global_p.h"
54#include "qv4managed_p.h"
55#include "qv4property_p.h"
56#include "qv4sparsearray_p.h"
57
58QT_BEGIN_NAMESPACE
59
60namespace QV4 {
61
62#define V4_ARRAYDATA(DataClass) \
63 public: \
64 Q_MANAGED_CHECK \
65 typedef QV4::Heap::DataClass Data; \
66 static const QV4::ArrayVTable static_vtbl; \
67 static inline const QV4::VTable *staticVTable() { return &static_vtbl.vTable; } \
68 V4_MANAGED_SIZE_TEST \
69 const Data *d() const { return static_cast<const Data *>(m()); } \
70 Data *d() { return static_cast<Data *>(m()); }
71
72
73struct ArrayData;
74
75struct ArrayVTable
76{
77 VTable vTable;
78 uint type;
79 Heap::ArrayData *(*reallocate)(Object *o, uint n, bool enforceAttributes);
80 ReturnedValue (*get)(const Heap::ArrayData *d, uint index);
81 bool (*put)(Object *o, uint index, const Value &value);
82 bool (*putArray)(Object *o, uint index, const Value *values, uint n);
83 bool (*del)(Object *o, uint index);
84 void (*setAttribute)(Object *o, uint index, PropertyAttributes attrs);
85 void (*push_front)(Object *o, const Value *values, uint n);
86 ReturnedValue (*pop_front)(Object *o);
87 uint (*truncate)(Object *o, uint newLen);
88 uint (*length)(const Heap::ArrayData *d);
89};
90
91namespace Heap {
92
93#define ArrayDataMembers(class, Member) \
94 Member(class, NoMark, ushort, type) \
95 Member(class, NoMark, ushort, unused) \
96 Member(class, NoMark, uint, offset) \
97 Member(class, NoMark, PropertyAttributes *, attrs) \
98 Member(class, NoMark, SparseArray *, sparse) \
99 Member(class, ValueArray, ValueArray, values)
100
101DECLARE_HEAP_OBJECT(ArrayData, Base) {
102 static void markObjects(Heap::Base *base, MarkStack *stack);
103
104 enum Type { Simple = 0, Sparse = 1, Custom = 2 };
105
106 bool isSparse() const { return type == Sparse; }
107
108 const ArrayVTable *vtable() const { return reinterpret_cast<const ArrayVTable *>(internalClass->vtable); }
109
110 inline ReturnedValue get(uint i) const {
111 return vtable()->get(this, i);
112 }
113 inline bool getProperty(uint index, Property *p, PropertyAttributes *attrs);
114 inline void setProperty(EngineBase *e, uint index, const Property *p);
115 inline PropertyIndex getValueOrSetter(uint index, PropertyAttributes *attrs);
116 inline PropertyAttributes attributes(uint i) const;
117
118 bool isEmpty(uint i) const {
119 return get(i) == Value::emptyValue().asReturnedValue();
120 }
121
122 inline uint length() const {
123 return vtable()->length(this);
124 }
125
126 void setArrayData(EngineBase *e, uint index, Value newVal) {
127 values.set(e, index, v: newVal);
128 }
129
130 uint mappedIndex(uint index) const;
131};
132Q_STATIC_ASSERT(std::is_trivial< ArrayData >::value);
133
134struct SimpleArrayData : public ArrayData {
135 uint mappedIndex(uint index) const { index += offset; if (index >= values.alloc) index -= values.alloc; return index; }
136 const Value &data(uint index) const { return values[mappedIndex(index)]; }
137 void setData(EngineBase *e, uint index, Value newVal) {
138 values.set(e, index: mappedIndex(index), v: newVal);
139 }
140
141 PropertyAttributes attributes(uint i) const {
142 return attrs ? attrs[i] : Attr_Data;
143 }
144};
145Q_STATIC_ASSERT(std::is_trivial< SimpleArrayData >::value);
146
147struct SparseArrayData : public ArrayData {
148 void destroy() {
149 delete sparse;
150 ArrayData::destroy();
151 }
152
153 uint mappedIndex(uint index) const {
154 SparseArrayNode *n = sparse->findNode(akey: index);
155 if (!n)
156 return UINT_MAX;
157 return n->value;
158 }
159
160 PropertyAttributes attributes(uint i) const {
161 if (!attrs)
162 return Attr_Data;
163 uint index = mappedIndex(index: i);
164 return index < UINT_MAX ? attrs[index] : Attr_Data;
165 }
166};
167
168}
169
170struct Q_QML_EXPORT ArrayData : public Managed
171{
172 typedef Heap::ArrayData::Type Type;
173 V4_MANAGED(ArrayData, Managed)
174 enum {
175 IsArrayData = true
176 };
177
178 uint alloc() const { return d()->values.alloc; }
179 uint &alloc() { return d()->values.alloc; }
180 void setAlloc(uint a) { d()->values.alloc = a; }
181 Type type() const { return static_cast<Type>(d()->type); }
182 void setType(Type t) { d()->type = t; }
183 PropertyAttributes *attrs() const { return d()->attrs; }
184 void setAttrs(PropertyAttributes *a) { d()->attrs = a; }
185 const Value *arrayData() const { return d()->values.data(); }
186 void setArrayData(EngineBase *e, uint index, Value newVal) {
187 d()->setArrayData(e, index, newVal);
188 }
189
190 const ArrayVTable *vtable() const { return d()->vtable(); }
191 bool isSparse() const { return type() == Heap::ArrayData::Sparse; }
192
193 uint length() const {
194 return d()->length();
195 }
196
197 bool hasAttributes() const {
198 return attrs();
199 }
200 PropertyAttributes attributes(uint i) const {
201 return d()->attributes(i);
202 }
203
204 bool isEmpty(uint i) const {
205 return d()->isEmpty(i);
206 }
207
208 ReturnedValue get(uint i) const {
209 return d()->get(i);
210 }
211
212 static void ensureAttributes(Object *o);
213 static void realloc(Object *o, Type newType, uint alloc, bool enforceAttributes);
214
215 static void sort(ExecutionEngine *engine, Object *thisObject, const Value &comparefn, uint dataLen);
216 static uint append(Object *obj, ArrayObject *otherObj, uint n);
217 static void insert(Object *o, uint index, const Value *v, bool isAccessor = false);
218};
219
220struct Q_QML_EXPORT SimpleArrayData : public ArrayData
221{
222 V4_ARRAYDATA(SimpleArrayData)
223 V4_INTERNALCLASS(SimpleArrayData)
224
225 uint mappedIndex(uint index) const { return d()->mappedIndex(index); }
226 Value data(uint index) const { return d()->data(index); }
227
228 uint &len() { return d()->values.size; }
229 uint len() const { return d()->values.size; }
230
231 static Heap::ArrayData *reallocate(Object *o, uint n, bool enforceAttributes);
232
233 static ReturnedValue get(const Heap::ArrayData *d, uint index);
234 static bool put(Object *o, uint index, const Value &value);
235 static bool putArray(Object *o, uint index, const Value *values, uint n);
236 static bool del(Object *o, uint index);
237 static void setAttribute(Object *o, uint index, PropertyAttributes attrs);
238 static void push_front(Object *o, const Value *values, uint n);
239 static ReturnedValue pop_front(Object *o);
240 static uint truncate(Object *o, uint newLen);
241 static uint length(const Heap::ArrayData *d);
242};
243
244struct Q_QML_EXPORT SparseArrayData : public ArrayData
245{
246 V4_ARRAYDATA(SparseArrayData)
247 V4_INTERNALCLASS(SparseArrayData)
248 V4_NEEDS_DESTROY
249
250 SparseArray *sparse() const { return d()->sparse; }
251 void setSparse(SparseArray *s) { d()->sparse = s; }
252
253 static uint allocate(Object *o, bool doubleSlot = false);
254 static void free(Heap::ArrayData *d, uint idx);
255
256 uint mappedIndex(uint index) const { return d()->mappedIndex(index); }
257
258 static Heap::ArrayData *reallocate(Object *o, uint n, bool enforceAttributes);
259 static ReturnedValue get(const Heap::ArrayData *d, uint index);
260 static bool put(Object *o, uint index, const Value &value);
261 static bool putArray(Object *o, uint index, const Value *values, uint n);
262 static bool del(Object *o, uint index);
263 static void setAttribute(Object *o, uint index, PropertyAttributes attrs);
264 static void push_front(Object *o, const Value *values, uint n);
265 static ReturnedValue pop_front(Object *o);
266 static uint truncate(Object *o, uint newLen);
267 static uint length(const Heap::ArrayData *d);
268};
269
270namespace Heap {
271
272inline uint ArrayData::mappedIndex(uint index) const
273{
274 if (isSparse())
275 return static_cast<const SparseArrayData *>(this)->mappedIndex(index);
276 if (index >= values.size)
277 return UINT_MAX;
278 uint idx = static_cast<const SimpleArrayData *>(this)->mappedIndex(index);
279 return values[idx].isEmpty() ? UINT_MAX : idx;
280}
281
282bool ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs)
283{
284 uint mapped = mappedIndex(index);
285 if (mapped == UINT_MAX) {
286 *attrs = Attr_Invalid;
287 return false;
288 }
289
290 *attrs = attributes(i: index);
291 if (p) {
292 p->value = *(PropertyIndex{ .base: this, .slot: values.values + mapped });
293 if (attrs->isAccessor())
294 p->set = *(PropertyIndex{ .base: this, .slot: values.values + mapped + 1 /*Object::SetterOffset*/ });
295 }
296 return true;
297}
298
299void ArrayData::setProperty(QV4::EngineBase *e, uint index, const Property *p)
300{
301 uint mapped = mappedIndex(index);
302 Q_ASSERT(mapped != UINT_MAX);
303 values.set(e, index: mapped, v: p->value);
304 if (attributes(i: index).isAccessor())
305 values.set(e, index: mapped + 1 /*QV4::Object::SetterOffset*/, v: p->set);
306}
307
308inline PropertyAttributes ArrayData::attributes(uint i) const
309{
310 if (isSparse())
311 return static_cast<const SparseArrayData *>(this)->attributes(i);
312 return static_cast<const SimpleArrayData *>(this)->attributes(i);
313}
314
315PropertyIndex ArrayData::getValueOrSetter(uint index, PropertyAttributes *attrs)
316{
317 uint idx = mappedIndex(index);
318 if (idx == UINT_MAX) {
319 *attrs = Attr_Invalid;
320 return { .base: nullptr, .slot: nullptr };
321 }
322
323 *attrs = attributes(i: index);
324 if (attrs->isAccessor())
325 ++idx;
326 return { .base: this, .slot: values.values + idx };
327}
328
329
330
331}
332
333}
334
335QT_END_NAMESPACE
336
337#endif
338

source code of qtdeclarative/src/qml/jsruntime/qv4arraydata_p.h