/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QV4ARRAYDATA_H #define QV4ARRAYDATA_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include "qv4global_p.h" #include "qv4managed_p.h" #include "qv4property_p.h" #include "qv4sparsearray_p.h" QT_BEGIN_NAMESPACE namespace QV4 { #define V4_ARRAYDATA(DataClass) \ public: \ Q_MANAGED_CHECK \ typedef QV4::Heap::DataClass Data; \ static const QV4::ArrayVTable static_vtbl; \ static inline const QV4::VTable *staticVTable() { return &static_vtbl.vTable; } \ V4_MANAGED_SIZE_TEST \ const Data *d() const { return static_cast(m()); } \ Data *d() { return static_cast(m()); } struct ArrayData; struct ArrayVTable { VTable vTable; uint type; Heap::ArrayData *(*reallocate)(Object *o, uint n, bool enforceAttributes); ReturnedValue (*get)(const Heap::ArrayData *d, uint index); bool (*put)(Object *o, uint index, const Value &value); bool (*putArray)(Object *o, uint index, const Value *values, uint n); bool (*del)(Object *o, uint index); void (*setAttribute)(Object *o, uint index, PropertyAttributes attrs); void (*push_front)(Object *o, const Value *values, uint n); ReturnedValue (*pop_front)(Object *o); uint (*truncate)(Object *o, uint newLen); uint (*length)(const Heap::ArrayData *d); }; namespace Heap { #define ArrayDataMembers(class, Member) \ Member(class, NoMark, ushort, type) \ Member(class, NoMark, ushort, needsMark) \ Member(class, NoMark, uint, offset) \ Member(class, NoMark, PropertyAttributes *, attrs) \ Member(class, NoMark, SparseArray *, sparse) \ Member(class, ValueArray, ValueArray, values) DECLARE_HEAP_OBJECT(ArrayData, Base) { static void markObjects(Heap::Base *base, MarkStack *stack); enum Type { Simple = 0, Complex = 1, Sparse = 2, Custom = 3 }; struct Index { Heap::ArrayData *arrayData; uint index; void set(EngineBase *e, Value newVal) { arrayData->values.set(e, index, newVal); } const Value *operator->() const { return &arrayData->values[index]; } const Value &operator*() const { return arrayData->values[index]; } bool isNull() const { return !arrayData; } }; bool isSparse() const { return type == Sparse; } const ArrayVTable *vtable() const { return reinterpret_cast(Base::vtable()); } inline ReturnedValue get(uint i) const { return vtable()->get(this, i); } inline bool getProperty(uint index, Property *p, PropertyAttributes *attrs); inline void setProperty(EngineBase *e, uint index, const Property *p); inline Index getValueOrSetter(uint index, PropertyAttributes *attrs); inline PropertyAttributes attributes(uint i) const; bool isEmpty(uint i) const { return get(i) == Primitive::emptyValue().asReturnedValue(); } inline uint length() const { return vtable()->length(this); } void setArrayData(EngineBase *e, uint index, Value newVal) { values.set(e, index, newVal); } uint mappedIndex(uint index) const; }; Q_STATIC_ASSERT(std::is_trivial< ArrayData >::value); struct SimpleArrayData : public ArrayData { uint mappedIndex(uint index) const { index += offset; if (index >= values.alloc) index -= values.alloc; return index; } const Value &data(uint index) const { return values[mappedIndex(index)]; } void setData(EngineBase *e, uint index, Value newVal) { if (newVal.isManaged()) needsMark = true; values.set(e, mappedIndex(index), newVal); } PropertyAttributes attributes(uint i) const { return attrs ? attrs[i] : Attr_Data; } }; Q_STATIC_ASSERT(std::is_trivial< SimpleArrayData >::value); struct SparseArrayData : public ArrayData { void destroy() { delete sparse; ArrayData::destroy(); } uint mappedIndex(uint index) const { SparseArrayNode *n = sparse->findNode(index); if (!n) return UINT_MAX; return n->value; } PropertyAttributes attributes(uint i) const { if (!attrs) return Attr_Data; uint index = mappedIndex(i); return index < UINT_MAX ? attrs[index] : Attr_Data; } }; } struct Q_QML_EXPORT ArrayData : public Managed { typedef Heap::ArrayData::Type Type; V4_MANAGED(ArrayData, Managed) enum { IsArrayData = true }; typedef Heap::ArrayData::Index Index; uint alloc() const { return d()->values.alloc; } uint &alloc() { return d()->values.alloc; } void setAlloc(uint a) { d()->values.alloc = a; } Type type() const { return static_cast(d()->type); } void setType(Type t) { d()->type = t; } PropertyAttributes *attrs() const { return d()->attrs; } void setAttrs(PropertyAttributes *a) { d()->attrs = a; } const Value *arrayData() const { return d()->values.data(); } void setArrayData(EngineBase *e, uint index, Value newVal) { d()->setArrayData(e, index, newVal); } const ArrayVTable *vtable() const { return d()->vtable(); } bool isSparse() const { return type() == Heap::ArrayData::Sparse; } uint length() const { return d()->length(); } bool hasAttributes() const { return attrs(); } PropertyAttributes attributes(uint i) const { return d()->attributes(i); } bool isEmpty(uint i) const { return d()->isEmpty(i); } ReturnedValue get(uint i) const { return d()->get(i); } static void ensureAttributes(Object *o); static void realloc(Object *o, Type newType, uint alloc, bool enforceAttributes); static void sort(ExecutionEngine *engine, Object *thisObject, const Value &comparefn, uint dataLen); static uint append(Object *obj, ArrayObject *otherObj, uint n); static void insert(Object *o, uint index, const Value *v, bool isAccessor = false); }; struct Q_QML_EXPORT SimpleArrayData : public ArrayData { V4_ARRAYDATA(SimpleArrayData) V4_INTERNALCLASS(SimpleArrayData) uint mappedIndex(uint index) const { return d()->mappedIndex(index); } Value data(uint index) const { return d()->data(index); } uint &len() { return d()->values.size; } uint len() const { return d()->values.size; } static Heap::ArrayData *reallocate(Object *o, uint n, bool enforceAttributes); static ReturnedValue get(const Heap::ArrayData *d, uint index); static bool put(Object *o, uint index, const Value &value); static bool putArray(Object *o, uint index, const Value *values, uint n); static bool del(Object *o, uint index); static void setAttribute(Object *o, uint index, PropertyAttributes attrs); static void push_front(Object *o, const Value *values, uint n); static ReturnedValue pop_front(Object *o); static uint truncate(Object *o, uint newLen); static uint length(const Heap::ArrayData *d); }; struct Q_QML_EXPORT SparseArrayData : public ArrayData { V4_ARRAYDATA(SparseArrayData) V4_INTERNALCLASS(SparseArrayData) V4_NEEDS_DESTROY SparseArray *sparse() const { return d()->sparse; } void setSparse(SparseArray *s) { d()->sparse = s; } static uint allocate(Object *o, bool doubleSlot = false); static void free(Heap::ArrayData *d, uint idx); uint mappedIndex(uint index) const { return d()->mappedIndex(index); } static Heap::ArrayData *reallocate(Object *o, uint n, bool enforceAttributes); static ReturnedValue get(const Heap::ArrayData *d, uint index); static bool put(Object *o, uint index, const Value &value); static bool putArray(Object *o, uint index, const Value *values, uint n); static bool del(Object *o, uint index); static void setAttribute(Object *o, uint index, PropertyAttributes attrs); static void push_front(Object *o, const Value *values, uint n); static ReturnedValue pop_front(Object *o); static uint truncate(Object *o, uint newLen); static uint length(const Heap::ArrayData *d); }; namespace Heap { inline uint ArrayData::mappedIndex(uint index) const { if (isSparse()) return static_cast(this)->mappedIndex(index); if (index >= values.size) return UINT_MAX; uint idx = static_cast(this)->mappedIndex(index); return values[idx].isEmpty() ? UINT_MAX : idx; } bool ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs) { uint mapped = mappedIndex(index); if (mapped == UINT_MAX) { *attrs = Attr_Invalid; return false; } *attrs = attributes(index); if (p) { p->value = *(Index{ this, mapped }); if (attrs->isAccessor()) p->set = *(Index{ this, mapped + 1 /*Object::SetterOffset*/ }); } return true; } void ArrayData::setProperty(QV4::EngineBase *e, uint index, const Property *p) { uint mapped = mappedIndex(index); Q_ASSERT(mapped != UINT_MAX); values.set(e, mapped, p->value); if (attributes(index).isAccessor()) values.set(e, mapped + 1 /*QV4::Object::SetterOffset*/, p->set); } inline PropertyAttributes ArrayData::attributes(uint i) const { if (isSparse()) return static_cast(this)->attributes(i); return static_cast(this)->attributes(i); } ArrayData::Index ArrayData::getValueOrSetter(uint index, PropertyAttributes *attrs) { uint idx = mappedIndex(index); if (idx == UINT_MAX) { *attrs = Attr_Invalid; return { nullptr, 0 }; } *attrs = attributes(index); return { this, attrs->isAccessor() ? idx + 1 /* QV4::Object::SetterOffset*/ : idx }; } } } QT_END_NAMESPACE #endif