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 | |
58 | QT_BEGIN_NAMESPACE |
59 | |
60 | namespace 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 | |
73 | struct ArrayData; |
74 | |
75 | struct 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 | |
91 | namespace 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 | |
101 | DECLARE_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 | }; |
132 | Q_STATIC_ASSERT(std::is_trivial< ArrayData >::value); |
133 | |
134 | struct 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 | }; |
145 | Q_STATIC_ASSERT(std::is_trivial< SimpleArrayData >::value); |
146 | |
147 | struct 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 | |
170 | struct 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 | |
220 | struct 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 | |
244 | struct 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 | |
270 | namespace Heap { |
271 | |
272 | inline 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 | |
282 | bool 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 | |
299 | void 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 | |
308 | inline 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 | |
315 | PropertyIndex 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 | |
335 | QT_END_NAMESPACE |
336 | |
337 | #endif |
338 | |