diff options
Diffstat (limited to 'src/qml/qml/ftw')
25 files changed, 6840 insertions, 0 deletions
diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri new file mode 100644 index 0000000000..f2fec4e2dd --- /dev/null +++ b/src/qml/qml/ftw/ftw.pri @@ -0,0 +1,29 @@ +HEADERS += \ + $$PWD/qbitfield_p.h \ + $$PWD/qintrusivelist_p.h \ + $$PWD/qpodvector_p.h \ + $$PWD/qhashedstring_p.h \ + $$PWD/qqmlrefcount_p.h \ + $$PWD/qqmlpool_p.h \ + $$PWD/qfieldlist_p.h \ + $$PWD/qfastmetabuilder_p.h \ + $$PWD/qhashfield_p.h \ + $$PWD/qqmlthread_p.h \ + $$PWD/qfinitestack_p.h \ + $$PWD/qrecursionwatcher_p.h \ + $$PWD/qdeletewatcher_p.h \ + $$PWD/qrecyclepool_p.h \ + $$PWD/qflagpointer_p.h \ + $$PWD/qqmltrace_p.h \ + $$PWD/qpointervaluepair_p.h \ + $$PWD/qlazilyallocated_p.h \ + +SOURCES += \ + $$PWD/qintrusivelist.cpp \ + $$PWD/qhashedstring.cpp \ + $$PWD/qqmlpool.cpp \ + $$PWD/qfastmetabuilder.cpp \ + $$PWD/qqmlthread.cpp \ + $$PWD/qqmltrace.cpp \ + +contains(QT_CONFIG, clock-gettime):include($$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri) diff --git a/src/qml/qml/ftw/qbitfield_p.h b/src/qml/qml/ftw/qbitfield_p.h new file mode 100644 index 0000000000..75f80dd896 --- /dev/null +++ b/src/qml/qml/ftw/qbitfield_p.h @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBITFIELD_P_H +#define QBITFIELD_P_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 <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QBitField +{ +public: + inline QBitField(); + inline QBitField(const quint32 *, int bits); + inline QBitField(const QBitField &); + inline ~QBitField(); + + inline QBitField &operator=(const QBitField &); + + inline quint32 size() const; + inline QBitField united(const QBitField &); + inline bool testBit(int) const; + +private: + quint32 bits:31; + quint32 *ownData; + const quint32 *data; +}; + +QBitField::QBitField() +: bits(0), ownData(0), data(0) +{ +} + +QBitField::QBitField(const quint32 *bitData, int bitCount) +: bits((quint32)bitCount), ownData(0), data(bitData) +{ +} + +QBitField::QBitField(const QBitField &other) +: bits(other.bits), ownData(other.ownData), data(other.data) +{ + if (ownData) + ++(*ownData); +} + +QBitField::~QBitField() +{ + if (ownData) + if(0 == --(*ownData)) delete [] ownData; +} + +QBitField &QBitField::operator=(const QBitField &other) +{ + if (other.data == data) + return *this; + + if (ownData) + if(0 == --(*ownData)) delete [] ownData; + + bits = other.bits; + ownData = other.ownData; + data = other.data; + + if (ownData) + ++(*ownData); + + return *this; +} + +inline quint32 QBitField::size() const +{ + return bits; +} + +QBitField QBitField::united(const QBitField &o) +{ + if (o.bits == 0) { + return *this; + } else if (bits == 0) { + return o; + } else { + int max = (bits > o.bits)?bits:o.bits; + int length = (max + 31) / 32; + QBitField rv; + rv.bits = max; + rv.ownData = new quint32[length + 1]; + *(rv.ownData) = 1; + rv.data = rv.ownData + 1; + if (bits > o.bits) { + ::memcpy((quint32 *)rv.data, data, length * sizeof(quint32)); + for (quint32 ii = 0; ii < (o.bits + quint32(31)) / 32; ++ii) + ((quint32 *)rv.data)[ii] |= o.data[ii]; + } else { + ::memcpy((quint32 *)rv.data, o.data, length * sizeof(quint32)); + for (quint32 ii = 0; ii < (bits + quint32(31)) / 32; ++ii) + ((quint32 *)rv.data)[ii] |= data[ii]; + } + return rv; + } +} + +bool QBitField::testBit(int b) const +{ + Q_ASSERT(b >= 0); + if ((quint32)b < bits) { + return data[b / 32] & (1 << (b % 32)); + } else { + return false; + } +} + +QT_END_NAMESPACE + +#endif // QBITFIELD_P_H diff --git a/src/qml/qml/ftw/qdeletewatcher_p.h b/src/qml/qml/ftw/qdeletewatcher_p.h new file mode 100644 index 0000000000..9f7b100429 --- /dev/null +++ b/src/qml/qml/ftw/qdeletewatcher_p.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDELETEWATCHER_P_H +#define QDELETEWATCHER_P_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 <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QDeleteWatchable +{ +public: + inline QDeleteWatchable(); + inline ~QDeleteWatchable(); +private: + friend class QDeleteWatcher; + bool *_w; +}; + +class QDeleteWatcher { +public: + inline QDeleteWatcher(QDeleteWatchable *data); + inline ~QDeleteWatcher(); + inline bool wasDeleted() const; +private: + void *operator new(size_t); + bool *_w; + bool _s; + QDeleteWatchable *m_d; +}; + +QDeleteWatchable::QDeleteWatchable() +: _w(0) +{ +} + +QDeleteWatchable::~QDeleteWatchable() +{ + if (_w) *_w = true; +} + +QDeleteWatcher::QDeleteWatcher(QDeleteWatchable *data) +: _s(false), m_d(data) +{ + if (!m_d->_w) + m_d->_w = &_s; + _w = m_d->_w; +} + +QDeleteWatcher::~QDeleteWatcher() +{ + if (false == *_w && &_s == m_d->_w) + m_d->_w = 0; +} + +bool QDeleteWatcher::wasDeleted() const +{ + return *_w; +} + +QT_END_NAMESPACE + +#endif // QDELETEWATCHER_P_H diff --git a/src/qml/qml/ftw/qfastmetabuilder.cpp b/src/qml/qml/ftw/qfastmetabuilder.cpp new file mode 100644 index 0000000000..9663c1e944 --- /dev/null +++ b/src/qml/qml/ftw/qfastmetabuilder.cpp @@ -0,0 +1,369 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfastmetabuilder_p.h" + +#include <QtCore/qmetaobject.h> + +QT_BEGIN_NAMESPACE + +struct QFastMetaBuilderHeader +{ + int fieldCount; +}; + +struct QMetaObjectPrivate +{ + int revision; + int className; + int classInfoCount, classInfoData; + int methodCount, methodData; + int propertyCount, propertyData; + int enumeratorCount, enumeratorData; + int constructorCount, constructorData; //since revision 2 + int flags; //since revision 3 + int signalCount; //since revision 4 +}; + +enum MetaObjectFlag { + DynamicMetaObject = 0x01 +}; + +enum PropertyFlags { + Invalid = 0x00000000, + Readable = 0x00000001, + Writable = 0x00000002, + Resettable = 0x00000004, + EnumOrFlag = 0x00000008, + StdCppSet = 0x00000100, +// Override = 0x00000200, + Constant = 0x00000400, + Final = 0x00000800, + Designable = 0x00001000, + ResolveDesignable = 0x00002000, + Scriptable = 0x00004000, + ResolveScriptable = 0x00008000, + Stored = 0x00010000, + ResolveStored = 0x00020000, + Editable = 0x00040000, + ResolveEditable = 0x00080000, + User = 0x00100000, + ResolveUser = 0x00200000, + Notify = 0x00400000, + Revisioned = 0x00800000 +}; + +enum MethodFlags { + AccessPrivate = 0x00, + AccessProtected = 0x01, + AccessPublic = 0x02, + AccessMask = 0x03, //mask + + MethodMethod = 0x00, + MethodSignal = 0x04, + MethodSlot = 0x08, + MethodConstructor = 0x0c, + MethodTypeMask = 0x0c, + + MethodCompatibility = 0x10, + MethodCloned = 0x20, + MethodScriptable = 0x40, + MethodRevisioned = 0x80 +}; + +#define FMBHEADER_FIELD_COUNT 1 + +#define HEADER_FIELD_COUNT 14 +#define CLASSINFO_FIELD_COUNT 2 +#define METHOD_FIELD_COUNT 5 +#define PROPERTY_FIELD_COUNT 3 +#define PROPERTY_NOTIFY_FIELD_COUNT 1 + +static inline uint *fieldPointer(QByteArray &data) +{ return reinterpret_cast<uint *>(data.data()) + FMBHEADER_FIELD_COUNT; } + +static inline const uint *fieldPointer(const QByteArray &data) +{ return reinterpret_cast<const uint *>(data.constData()) + FMBHEADER_FIELD_COUNT; } + +static inline QMetaObjectPrivate *priv(QByteArray &data) +{ return reinterpret_cast<QMetaObjectPrivate*>(fieldPointer(data)); } + +static inline const QMetaObjectPrivate *priv(const QByteArray &data) +{ return reinterpret_cast<const QMetaObjectPrivate*>(fieldPointer(data)); } + +static inline QFastMetaBuilderHeader *header(QByteArray &data) +{ return reinterpret_cast<QFastMetaBuilderHeader*>(data.data()); } + +static inline const QFastMetaBuilderHeader *header(const QByteArray &data) +{ return reinterpret_cast<const QFastMetaBuilderHeader*>(data.constData()); } + +QFastMetaBuilder::QFastMetaBuilder() +: m_zeroPtr(0), m_stringData(0), m_stringDataLength(0), m_stringDataAllocated(0) +{ +} + +QFastMetaBuilder::~QFastMetaBuilder() +{ +} + +QFastMetaBuilder::StringRef QFastMetaBuilder::init(int classNameLength, + int propertyCount, int methodCount, + int signalCount, int classInfoCount) +{ + Q_ASSERT(m_data.isEmpty()); + Q_ASSERT(classNameLength > 0); + Q_ASSERT(propertyCount >= 0); + Q_ASSERT(methodCount >= 0); + Q_ASSERT(signalCount >= 0); + Q_ASSERT(classInfoCount >= 0); + + int fieldCount = FMBHEADER_FIELD_COUNT + + HEADER_FIELD_COUNT + + propertyCount * (PROPERTY_FIELD_COUNT + PROPERTY_NOTIFY_FIELD_COUNT) + + methodCount * (METHOD_FIELD_COUNT) + + signalCount * (METHOD_FIELD_COUNT) + + classInfoCount * CLASSINFO_FIELD_COUNT; + + m_data.resize(fieldCount * sizeof(uint) + classNameLength + 1); + m_stringData = m_data.data() + m_data.size() - classNameLength - 1; + m_stringDataLength = classNameLength + 1; + m_stringDataAllocated = classNameLength + 1; + m_stringData[classNameLength] = 0; + m_zeroPtr = classNameLength; + + header(m_data)->fieldCount = fieldCount; + + QMetaObjectPrivate *p = priv(m_data); + + int dataIndex = HEADER_FIELD_COUNT; + + p->revision = 4; + p->className = 0; + + // Class infos + p->classInfoCount = classInfoCount; + if (p->classInfoCount) { + p->classInfoData = dataIndex; + dataIndex += p->classInfoCount * CLASSINFO_FIELD_COUNT; + } else { + p->classInfoData = 0; + } + + // Methods + p->methodCount = methodCount + signalCount; + if (p->methodCount) { + p->methodData = dataIndex; + dataIndex += p->methodCount * METHOD_FIELD_COUNT; + } else { + p->methodData = 0; + } + p->signalCount = signalCount; + + // Properties + p->propertyCount = propertyCount; + if (p->propertyCount) { + p->propertyData = dataIndex; + dataIndex += p->propertyCount * (PROPERTY_FIELD_COUNT + PROPERTY_NOTIFY_FIELD_COUNT); + } else { + p->propertyData = 0; + } + + // Flags + p->flags = DynamicMetaObject; // Always dynamic + + // Enums and constructors not supported + p->enumeratorCount = 0; + p->enumeratorData = 0; + p->constructorCount = 0; + p->constructorData = 0; + + StringRef className; + className._b = this; + className._o = 0; + className._l = classNameLength; + return className; +} + +// Allocate a string of \a length. \a length should *not* include the null terminator. +QFastMetaBuilder::StringRef QFastMetaBuilder::newString(int length) +{ + Q_ASSERT(length > 0); + + StringRef sr; + sr._b = this; + sr._o = m_stringDataLength; + sr._l = length; + + m_stringDataLength += length + 1 /* for null terminator */; + + return sr; +} + +void QFastMetaBuilder::setClassInfo(int index, const StringRef &key, const StringRef &value) +{ + Q_ASSERT(!m_data.isEmpty()); + Q_ASSERT(!key.isEmpty() && !value.isEmpty()); + + QMetaObjectPrivate *p = priv(m_data); + Q_ASSERT(index < p->classInfoCount); + + uint *ptr = fieldPointer(m_data) + p->classInfoData + index * CLASSINFO_FIELD_COUNT; + // classinfo: key, value + ptr[0] = key.offset(); ptr[1] = value.offset(); +} + +void QFastMetaBuilder::setProperty(int index, const StringRef &name, const StringRef &type, + QMetaType::Type mtype, PropertyFlag flags, int notifySignal) +{ + Q_ASSERT(!m_data.isEmpty()); + Q_ASSERT(!name.isEmpty() && !type.isEmpty()); + + QMetaObjectPrivate *p = priv(m_data); + Q_ASSERT(index < p->propertyCount); + + uint *ptr = fieldPointer(m_data) + p->propertyData + index * PROPERTY_FIELD_COUNT; + // properties: name, type, flags + ptr[0] = name.offset(); + ptr[1] = type.offset(); + if (notifySignal == -1) { + ptr[2] = mtype << 24; + ptr[2] |= flags | Scriptable | Readable; + *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = 0; + } else { + ptr[2] = mtype << 24; + ptr[2] |= flags | Scriptable | Readable | Notify; + *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = notifySignal; + } +} + +void QFastMetaBuilder::setProperty(int index, const StringRef &name, const StringRef &type, + QFastMetaBuilder::PropertyFlag flags, int notifySignal) +{ + Q_ASSERT(!m_data.isEmpty()); + Q_ASSERT(!name.isEmpty() && !type.isEmpty()); + + QMetaObjectPrivate *p = priv(m_data); + Q_ASSERT(index < p->propertyCount); + + uint *ptr = fieldPointer(m_data) + p->propertyData + index * PROPERTY_FIELD_COUNT; + // properties: name, type, flags + ptr[0] = name.offset(); + ptr[1] = type.offset(); + if (notifySignal == -1) { + ptr[2] = flags | Scriptable | Readable; + *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = 0; + } else { + ptr[2] = flags | Scriptable | Readable | Notify; + *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = notifySignal; + } +} + +void QFastMetaBuilder::setSignal(int index, const StringRef &signature, + const StringRef ¶meterNames, + const StringRef &type) +{ + Q_ASSERT(!m_data.isEmpty()); + Q_ASSERT(!signature.isEmpty()); + + QMetaObjectPrivate *p = priv(m_data); + int mindex = metaObjectIndexForSignal(index); + + uint *ptr = fieldPointer(m_data) + p->methodData + mindex * METHOD_FIELD_COUNT; + // methods: signature, parameters, type, tag, flags + ptr[0] = signature.offset(); + ptr[1] = parameterNames.isEmpty()?m_zeroPtr:parameterNames.offset(); + ptr[2] = type.isEmpty()?m_zeroPtr:type.offset(); + ptr[3] = m_zeroPtr; + ptr[4] = AccessProtected | MethodSignal; +} + +void QFastMetaBuilder::setMethod(int index, const StringRef &signature, + const StringRef ¶meterNames, + const StringRef &type) +{ + Q_ASSERT(!m_data.isEmpty()); + Q_ASSERT(!signature.isEmpty()); + + QMetaObjectPrivate *p = priv(m_data); + int mindex = metaObjectIndexForMethod(index); + + uint *ptr = fieldPointer(m_data) + p->methodData + mindex * METHOD_FIELD_COUNT; + // methods: signature, parameters, type, tag, flags + ptr[0] = signature.offset(); + ptr[1] = parameterNames.isEmpty()?m_zeroPtr:parameterNames.offset(); + ptr[2] = type.isEmpty()?m_zeroPtr:type.offset(); + ptr[3] = m_zeroPtr; + ptr[4] = AccessProtected | MethodSlot; +} + +int QFastMetaBuilder::metaObjectIndexForSignal(int index) const +{ + Q_ASSERT(!m_data.isEmpty()); + Q_ASSERT(index < priv(m_data)->signalCount); + return index; +} + +int QFastMetaBuilder::metaObjectIndexForMethod(int index) const +{ + Q_ASSERT(!m_data.isEmpty()); + + const QMetaObjectPrivate *p = priv(m_data); + Q_ASSERT(index < (p->methodCount - p->signalCount)); + return index + p->signalCount; +} + +void QFastMetaBuilder::allocateStringData() +{ + if (m_stringDataAllocated < m_stringDataLength) { + m_data.resize(m_data.size() + m_stringDataLength - m_stringDataAllocated); + m_stringDataAllocated = m_stringDataLength; + m_stringData = m_data.data() + header(m_data)->fieldCount * sizeof(uint); + } +} + +void QFastMetaBuilder::fromData(QMetaObject *output, const QMetaObject *parent, const QByteArray &data) +{ + output->d.superdata = parent; + output->d.stringdata = data.constData() + header(data)->fieldCount * sizeof(uint); + output->d.data = fieldPointer(data); +} + +QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qfastmetabuilder_p.h b/src/qml/qml/ftw/qfastmetabuilder_p.h new file mode 100644 index 0000000000..c1f6a3de5c --- /dev/null +++ b/src/qml/qml/ftw/qfastmetabuilder_p.h @@ -0,0 +1,206 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFASTMETABUILDER_P_H +#define QFASTMETABUILDER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of moc. This header file may change from version to version without notice, +// or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> +#include <QtCore/qmetatype.h> +#include <QtCore/qmetaobject.h> + +#include <private/qhashedstring_p.h> + +QT_BEGIN_NAMESPACE + +struct QMetaObject; +class QFastMetaBuilder +{ +public: + QFastMetaBuilder(); + ~QFastMetaBuilder(); + + struct StringRef { + public: + inline StringRef(); + inline StringRef(const StringRef &); + inline StringRef &operator=(const StringRef &); + + inline void load(const QHashedStringRef &); + inline void load(const QByteArray &); + inline void load(const char *); + + inline bool isEmpty() const; + inline QFastMetaBuilder *builder() const; + inline int offset() const; + inline char *data(); + inline int length() const; + private: + friend class QFastMetaBuilder; + + QFastMetaBuilder *_b; + int _o; + int _l; + }; + StringRef newString(int length); + + // Returns class name + StringRef init(int classNameLength, + int propertyCount, int methodCount, + int signalCount, int classInfoCount); + + void setClassInfo(int index, const StringRef &key, const StringRef &value); + + enum PropertyFlag { + None = 0x00000000, + Writable = 0x00000002, + Resettable = 0x00000004, + Constant = 0x00000400, + Final = 0x00000800 + }; + // void setProperty(int index, const StringRef &name, QMetaType::Type type, int notifySignal = -1); + void setProperty(int index, const StringRef &name, const StringRef &type, + QMetaType::Type mtype, PropertyFlag flags, int notifySignal = -1); + void setProperty(int index, const StringRef &name, const StringRef &type, + PropertyFlag flags, int notifySignal = -1); + void setMethod(int index, const StringRef &signature, + const StringRef ¶meterNames = StringRef(), + const StringRef &type = StringRef()); + void setSignal(int index, const StringRef &signature, + const StringRef ¶meterNames = StringRef(), + const StringRef &type = StringRef()); + + int metaObjectIndexForSignal(int) const; + int metaObjectIndexForMethod(int) const; + + QByteArray toData() const { return m_data; } + static void fromData(QMetaObject *, const QMetaObject *parent, const QByteArray &); +private: + friend struct StringRef; + + QByteArray m_data; + int m_zeroPtr; + + void allocateStringData(); + char *m_stringData; + int m_stringDataLength; + int m_stringDataAllocated; +}; + +QFastMetaBuilder::StringRef::StringRef() +: _b(0), _o(0), _l(0) +{ +} + +QFastMetaBuilder::StringRef::StringRef(const StringRef &o) +: _b(o._b), _o(o._o), _l(o._l) +{ +} + +QFastMetaBuilder::StringRef &QFastMetaBuilder::StringRef::operator=(const StringRef &o) +{ + _b = o._b; + _o = o._o; + _l = o._l; + return *this; +} + +bool QFastMetaBuilder::StringRef::isEmpty() const +{ + return _l == 0; +} + +QFastMetaBuilder *QFastMetaBuilder::StringRef::builder() const +{ + return _b; +} + +int QFastMetaBuilder::StringRef::offset() const +{ + return _o; +} + +char *QFastMetaBuilder::StringRef::data() +{ + Q_ASSERT(_b); + if (_b->m_stringDataLength != _b->m_stringDataAllocated) + _b->allocateStringData(); + return _b->m_stringData + _o; +} + +int QFastMetaBuilder::StringRef::length() const +{ + return _l; +} + +void QFastMetaBuilder::StringRef::load(const QHashedStringRef &str) +{ + Q_ASSERT(str.utf8length() == _l); + str.writeUtf8(data()); + *(data() + _l) = 0; +} + +void QFastMetaBuilder::StringRef::load(const QByteArray &str) +{ + Q_ASSERT(str.length() == _l); + strcpy(data(), str.constData()); +} + +void QFastMetaBuilder::StringRef::load(const char *str) +{ + Q_ASSERT(strlen(str) == (uint)_l); + strcpy(data(), str); +} + +QT_END_NAMESPACE + +#endif // QFASTMETABUILDER_P_H + diff --git a/src/qml/qml/ftw/qfieldlist_p.h b/src/qml/qml/ftw/qfieldlist_p.h new file mode 100644 index 0000000000..da5074b3cd --- /dev/null +++ b/src/qml/qml/ftw/qfieldlist_p.h @@ -0,0 +1,426 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFIELDLIST_P_H +#define QFIELDLIST_P_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 <QtCore/qglobal.h> + +#include <private/qflagpointer_p.h> + +// QForwardFieldList is a super simple linked list that can only prepend +template<class N, N *N::*nextMember> +class QForwardFieldList +{ +public: + inline QForwardFieldList(); + inline N *first() const; + inline N *takeFirst(); + + inline void prepend(N *); + + inline bool isEmpty() const; + inline bool isOne() const; + inline bool isMany() const; + + static inline N *next(N *v); + + inline bool flag() const; + inline void setFlag(); + inline void clearFlag(); + inline void setFlagValue(bool); + + inline bool flag2() const; + inline void setFlag2(); + inline void clearFlag2(); + inline void setFlag2Value(bool); +private: + QFlagPointer<N> _first; +}; + +// QFieldList is a simple linked list, that can append and prepend and also +// maintains a count +template<class N, N *N::*nextMember> +class QFieldList +{ +public: + inline QFieldList(); + inline N *first() const; + inline N *takeFirst(); + + inline void append(N *); + inline void prepend(N *); + + inline bool isEmpty() const; + inline bool isOne() const; + inline bool isMany() const; + inline int count() const; + + inline void append(QFieldList<N, nextMember> &); + inline void prepend(QFieldList<N, nextMember> &); + inline void insertAfter(N *, QFieldList<N, nextMember> &); + + inline void copyAndClear(QFieldList<N, nextMember> &); + inline void copyAndClearAppend(QForwardFieldList<N, nextMember> &); + inline void copyAndClearPrepend(QForwardFieldList<N, nextMember> &); + + static inline N *next(N *v); + + inline bool flag() const; + inline void setFlag(); + inline void clearFlag(); + inline void setFlagValue(bool); +private: + N *_first; + N *_last; + quint32 _flag:1; + quint32 _count:31; +}; + +template<class N, N *N::*nextMember> +QForwardFieldList<N, nextMember>::QForwardFieldList() +{ +} + +template<class N, N *N::*nextMember> +N *QForwardFieldList<N, nextMember>::first() const +{ + return *_first; +} + +template<class N, N *N::*nextMember> +N *QForwardFieldList<N, nextMember>::takeFirst() +{ + N *value = *_first; + if (value) { + _first = next(value); + value->*nextMember = 0; + } + return value; +} + +template<class N, N *N::*nextMember> +void QForwardFieldList<N, nextMember>::prepend(N *v) +{ + Q_ASSERT(v->*nextMember == 0); + v->*nextMember = *_first; + _first = v; +} + +template<class N, N *N::*nextMember> +bool QForwardFieldList<N, nextMember>::isEmpty() const +{ + return _first.isNull(); +} + +template<class N, N *N::*nextMember> +bool QForwardFieldList<N, nextMember>::isOne() const +{ + return *_first && _first->*nextMember == 0; +} + +template<class N, N *N::*nextMember> +bool QForwardFieldList<N, nextMember>::isMany() const +{ + return *_first && _first->*nextMember != 0; +} + +template<class N, N *N::*nextMember> +N *QForwardFieldList<N, nextMember>::next(N *v) +{ + Q_ASSERT(v); + return v->*nextMember; +} + +template<class N, N *N::*nextMember> +bool QForwardFieldList<N, nextMember>::flag() const +{ + return _first.flag(); +} + +template<class N, N *N::*nextMember> +void QForwardFieldList<N, nextMember>::setFlag() +{ + _first.setFlag(); +} + +template<class N, N *N::*nextMember> +void QForwardFieldList<N, nextMember>::clearFlag() +{ + _first.clearFlag(); +} + +template<class N, N *N::*nextMember> +void QForwardFieldList<N, nextMember>::setFlagValue(bool v) +{ + _first.setFlagValue(v); +} + +template<class N, N *N::*nextMember> +bool QForwardFieldList<N, nextMember>::flag2() const +{ + return _first.flag2(); +} + +template<class N, N *N::*nextMember> +void QForwardFieldList<N, nextMember>::setFlag2() +{ + _first.setFlag2(); +} + +template<class N, N *N::*nextMember> +void QForwardFieldList<N, nextMember>::clearFlag2() +{ + _first.clearFlag2(); +} + +template<class N, N *N::*nextMember> +void QForwardFieldList<N, nextMember>::setFlag2Value(bool v) +{ + _first.setFlag2Value(v); +} + +template<class N, N *N::*nextMember> +QFieldList<N, nextMember>::QFieldList() +: _first(0), _last(0), _flag(0), _count(0) +{ +} + +template<class N, N *N::*nextMember> +N *QFieldList<N, nextMember>::first() const +{ + return _first; +} + +template<class N, N *N::*nextMember> +N *QFieldList<N, nextMember>::takeFirst() +{ + N *value = _first; + if (value) { + _first = next(value); + if (_last == value) { + Q_ASSERT(_first == 0); + _last = 0; + } + value->*nextMember = 0; + --_count; + } + return value; +} + +template<class N, N *N::*nextMember> +void QFieldList<N, nextMember>::append(N *v) +{ + Q_ASSERT(v->*nextMember == 0); + if (isEmpty()) { + _first = v; + _last = v; + } else { + _last->*nextMember = v; + _last = v; + } + ++_count; +} + +template<class N, N *N::*nextMember> +void QFieldList<N, nextMember>::prepend(N *v) +{ + Q_ASSERT(v->*nextMember == 0); + if (isEmpty()) { + _first = v; + _last = v; + } else { + v->*nextMember = _first; + _first = v; + } + ++_count; +} + +template<class N, N *N::*nextMember> +bool QFieldList<N, nextMember>::isEmpty() const +{ + return _count == 0; +} + +template<class N, N *N::*nextMember> +bool QFieldList<N, nextMember>::isOne() const +{ + return _count == 1; +} + +template<class N, N *N::*nextMember> +bool QFieldList<N, nextMember>::isMany() const +{ + return _count > 1; +} + +template<class N, N *N::*nextMember> +int QFieldList<N, nextMember>::count() const +{ + return _count; +} + +template<class N, N *N::*nextMember> +N *QFieldList<N, nextMember>::next(N *v) +{ + Q_ASSERT(v); + return v->*nextMember; +} + +template<class N, N *N::*nextMember> +void QFieldList<N, nextMember>::append(QFieldList<N, nextMember> &o) +{ + if (!o.isEmpty()) { + if (isEmpty()) { + _first = o._first; + _last = o._last; + _count = o._count; + } else { + _last->*nextMember = o._first; + _last = o._last; + _count += o._count; + } + o._first = o._last = 0; o._count = 0; + } +} + +template<class N, N *N::*nextMember> +void QFieldList<N, nextMember>::prepend(QFieldList<N, nextMember> &o) +{ + if (!o.isEmpty()) { + if (isEmpty()) { + _first = o._first; + _last = o._last; + _count = o._count; + } else { + o._last->*nextMember = _first; + _first = o._first; + _count += o._count; + } + o._first = o._last = 0; o._count = 0; + } +} + +template<class N, N *N::*nextMember> +void QFieldList<N, nextMember>::insertAfter(N *after, QFieldList<N, nextMember> &o) +{ + if (after == 0) { + prepend(o); + } else if (after == _last) { + append(o); + } else if (!o.isEmpty()) { + if (isEmpty()) { + _first = o._first; + _last = o._last; + _count = o._count; + } else { + o._last->*nextMember = after->*nextMember; + after->*nextMember = o._first; + _count += o._count; + } + o._first = o._last = 0; o._count = 0; + } +} + +template<class N, N *N::*nextMember> +void QFieldList<N, nextMember>::copyAndClear(QFieldList<N, nextMember> &o) +{ + _first = o._first; + _last = o._last; + _count = o._count; + o._first = o._last = 0; + o._count = 0; +} + +template<class N, N *N::*nextMember> +void QFieldList<N, nextMember>::copyAndClearAppend(QForwardFieldList<N, nextMember> &o) +{ + _first = 0; + _last = 0; + _count = 0; + while (N *n = o.takeFirst()) append(n); +} + +template<class N, N *N::*nextMember> +void QFieldList<N, nextMember>::copyAndClearPrepend(QForwardFieldList<N, nextMember> &o) +{ + _first = 0; + _last = 0; + _count = 0; + while (N *n = o.takeFirst()) prepend(n); +} + +template<class N, N *N::*nextMember> +bool QFieldList<N, nextMember>::flag() const +{ + return _flag; +} + +template<class N, N *N::*nextMember> +void QFieldList<N, nextMember>::setFlag() +{ + _flag = true; +} + +template<class N, N *N::*nextMember> +void QFieldList<N, nextMember>::clearFlag() +{ + _flag = false; +} + +template<class N, N *N::*nextMember> +void QFieldList<N, nextMember>::setFlagValue(bool v) +{ + _flag = v; +} + +#endif // QFIELDLIST_P_H diff --git a/src/qml/qml/ftw/qfinitestack_p.h b/src/qml/qml/ftw/qfinitestack_p.h new file mode 100644 index 0000000000..c5a9fbaedb --- /dev/null +++ b/src/qml/qml/ftw/qfinitestack_p.h @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFINITESTACK_P_H +#define QFINITESTACK_P_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 <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +template<typename T> +struct QFiniteStack { + inline QFiniteStack(); + inline ~QFiniteStack(); + + inline void deallocate(); + inline void allocate(int size); + + inline bool isEmpty() const; + inline const T &top() const; + inline T &top(); + inline void push(const T &o); + inline T pop(); + inline int count() const; + inline const T &at(int index) const; + inline T &operator[](int index); +private: + T *_array; + int _alloc; + int _size; +}; + +template<typename T> +QFiniteStack<T>::QFiniteStack() +: _array(0), _alloc(0), _size(0) +{ +} + +template<typename T> +QFiniteStack<T>::~QFiniteStack() +{ + deallocate(); +} + +template<typename T> +bool QFiniteStack<T>::isEmpty() const +{ + return _size == 0; +} + +template<typename T> +const T &QFiniteStack<T>::top() const +{ + return _array[_size - 1]; +} + +template<typename T> +T &QFiniteStack<T>::top() +{ + return _array[_size - 1]; +} + +template<typename T> +void QFiniteStack<T>::push(const T &o) +{ + if (QTypeInfo<T>::isComplex) { + new (_array + _size++) T(o); + } else { + _array[_size++] = o; + } +} + +template<typename T> +T QFiniteStack<T>::pop() +{ + --_size; + + if (QTypeInfo<T>::isComplex) { + T rv = _array[_size]; + (_array + _size)->~T(); + return rv; + } else { + return _array[_size]; + } +} + +template<typename T> +int QFiniteStack<T>::count() const +{ + return _size; +} + +template<typename T> +const T &QFiniteStack<T>::at(int index) const +{ + return _array[index]; +} + +template<typename T> +T &QFiniteStack<T>::operator[](int index) +{ + return _array[index]; +} + +template<typename T> +void QFiniteStack<T>::allocate(int size) +{ + Q_ASSERT(_array == 0); + Q_ASSERT(_alloc == 0); + Q_ASSERT(_size == 0); + + if (!size) return; + + _array = (T *)qMalloc(size * sizeof(T)); + _alloc = size; +} + +template<typename T> +void QFiniteStack<T>::deallocate() +{ + if (QTypeInfo<T>::isComplex) { + T *i = _array + _size; + while (i != _array) + (--i)->~T(); + } + + qFree(_array); + + _array = 0; + _alloc = 0; + _size = 0; +} + +QT_END_NAMESPACE + +#endif // QFINITESTACK_P_H + diff --git a/src/qml/qml/ftw/qflagpointer_p.h b/src/qml/qml/ftw/qflagpointer_p.h new file mode 100644 index 0000000000..a4b20d9e2a --- /dev/null +++ b/src/qml/qml/ftw/qflagpointer_p.h @@ -0,0 +1,338 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFLAGPOINTER_P_H +#define QFLAGPOINTER_P_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 <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +template<typename T> +class QFlagPointer { +public: + inline QFlagPointer(); + inline QFlagPointer(T *); + inline QFlagPointer(const QFlagPointer<T> &o); + + inline bool isNull() const; + + inline bool flag() const; + inline void setFlag(); + inline void clearFlag(); + inline void setFlagValue(bool); + + inline bool flag2() const; + inline void setFlag2(); + inline void clearFlag2(); + inline void setFlag2Value(bool); + + inline QFlagPointer<T> &operator=(const QFlagPointer &o); + inline QFlagPointer<T> &operator=(T *); + + inline T *operator->() const; + inline T *operator*() const; + +private: + quintptr ptr_value; + + static const quintptr FlagBit = 0x1; + static const quintptr Flag2Bit = 0x2; + static const quintptr FlagsMask = FlagBit | Flag2Bit; +}; + +template<typename T, typename T2> +class QBiPointer { +public: + inline QBiPointer(); + inline QBiPointer(T *); + inline QBiPointer(T2 *); + inline QBiPointer(const QBiPointer<T, T2> &o); + + inline bool isNull() const; + inline bool isT1() const; + inline bool isT2() const; + + inline bool flag() const; + inline void setFlag(); + inline void clearFlag(); + inline void setFlagValue(bool); + + inline QBiPointer<T, T2> &operator=(const QBiPointer<T, T2> &o); + inline QBiPointer<T, T2> &operator=(T *); + inline QBiPointer<T, T2> &operator=(T2 *); + + inline T *asT1() const; + inline T2 *asT2() const; + +private: + quintptr ptr_value; + + static const quintptr FlagBit = 0x1; + static const quintptr Flag2Bit = 0x2; + static const quintptr FlagsMask = FlagBit | Flag2Bit; +}; + +template<typename T> +QFlagPointer<T>::QFlagPointer() +: ptr_value(0) +{ +} + +template<typename T> +QFlagPointer<T>::QFlagPointer(T *v) +: ptr_value(quintptr(v)) +{ + Q_ASSERT((ptr_value & FlagsMask) == 0); +} + +template<typename T> +QFlagPointer<T>::QFlagPointer(const QFlagPointer<T> &o) +: ptr_value(o.ptr_value) +{ +} + +template<typename T> +bool QFlagPointer<T>::isNull() const +{ + return 0 == (ptr_value & (~FlagsMask)); +} + +template<typename T> +bool QFlagPointer<T>::flag() const +{ + return ptr_value & FlagBit; +} + +template<typename T> +void QFlagPointer<T>::setFlag() +{ + ptr_value |= FlagBit; +} + +template<typename T> +void QFlagPointer<T>::clearFlag() +{ + ptr_value &= ~FlagBit; +} + +template<typename T> +void QFlagPointer<T>::setFlagValue(bool v) +{ + if (v) setFlag(); + else clearFlag(); +} + +template<typename T> +bool QFlagPointer<T>::flag2() const +{ + return ptr_value & Flag2Bit; +} + +template<typename T> +void QFlagPointer<T>::setFlag2() +{ + ptr_value|= Flag2Bit; +} + +template<typename T> +void QFlagPointer<T>::clearFlag2() +{ + ptr_value &= ~Flag2Bit; +} + +template<typename T> +void QFlagPointer<T>::setFlag2Value(bool v) +{ + if (v) setFlag2(); + else clearFlag2(); +} + +template<typename T> +QFlagPointer<T> &QFlagPointer<T>::operator=(const QFlagPointer &o) +{ + ptr_value = o.ptr_value; + return *this; +} + +template<typename T> +QFlagPointer<T> &QFlagPointer<T>::operator=(T *o) +{ + Q_ASSERT((quintptr(o) & FlagsMask) == 0); + + ptr_value = quintptr(o) | (ptr_value & FlagsMask); + return *this; +} + +template<typename T> +T *QFlagPointer<T>::operator->() const +{ + return (T *)(ptr_value & ~FlagsMask); +} + +template<typename T> +T *QFlagPointer<T>::operator*() const +{ + return (T *)(ptr_value & ~FlagsMask); +} + +template<typename T, typename T2> +QBiPointer<T, T2>::QBiPointer() +: ptr_value(0) +{ +} + +template<typename T, typename T2> +QBiPointer<T, T2>::QBiPointer(T *v) +: ptr_value(quintptr(v)) +{ + Q_ASSERT((quintptr(v) & FlagsMask) == 0); +} + +template<typename T, typename T2> +QBiPointer<T, T2>::QBiPointer(T2 *v) +: ptr_value(quintptr(v) | Flag2Bit) +{ + Q_ASSERT((quintptr(v) & FlagsMask) == 0); +} + +template<typename T, typename T2> +QBiPointer<T, T2>::QBiPointer(const QBiPointer<T, T2> &o) +: ptr_value(o.ptr_value) +{ +} + +template<typename T, typename T2> +bool QBiPointer<T, T2>::isNull() const +{ + return 0 == (ptr_value & (~FlagsMask)); +} + +template<typename T, typename T2> +bool QBiPointer<T, T2>::isT1() const +{ + return !(ptr_value & Flag2Bit); +} + +template<typename T, typename T2> +bool QBiPointer<T, T2>::isT2() const +{ + return ptr_value & Flag2Bit; +} + +template<typename T, typename T2> +bool QBiPointer<T, T2>::flag() const +{ + return ptr_value & FlagBit; +} + +template<typename T, typename T2> +void QBiPointer<T, T2>::setFlag() +{ + ptr_value |= FlagBit; +} + +template<typename T, typename T2> +void QBiPointer<T, T2>::clearFlag() +{ + ptr_value &= ~FlagBit; +} + +template<typename T, typename T2> +void QBiPointer<T, T2>::setFlagValue(bool v) +{ + if (v) setFlag(); + else clearFlag(); +} + +template<typename T, typename T2> +QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(const QBiPointer<T, T2> &o) +{ + ptr_value = o.ptr_value; + return *this; +} + +template<typename T, typename T2> +QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(T *o) +{ + Q_ASSERT((quintptr(o) & FlagsMask) == 0); + + ptr_value = quintptr(o) | (ptr_value & FlagBit); + return *this; +} + +template<typename T, typename T2> +QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(T2 *o) +{ + Q_ASSERT((quintptr(o) & FlagsMask) == 0); + + ptr_value = quintptr(o) | (ptr_value & FlagBit) | Flag2Bit; + return *this; +} + +template<typename T, typename T2> +T *QBiPointer<T, T2>::asT1() const +{ + Q_ASSERT(isT1()); + return (T *)(ptr_value & ~FlagsMask); +} + +template<typename T, typename T2> +T2 *QBiPointer<T, T2>::asT2() const +{ + Q_ASSERT(isT2()); + return (T2 *)(ptr_value & ~FlagsMask); +} + +QT_END_NAMESPACE + +#endif // QFLAGPOINTER_P_H diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp new file mode 100644 index 0000000000..1f09d50ed3 --- /dev/null +++ b/src/qml/qml/ftw/qhashedstring.cpp @@ -0,0 +1,490 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhashedstring_p.h" + +// This is a reimplementation of V8's string hash algorithm. It is significantly +// faster to do it here than call into V8, but it adds the maintainence burden of +// ensuring that the two hashes are identical. We Q_ASSERT() that the two return +// the same value. If these asserts start to fail, the hash code needs to be +// synced with V8. +namespace String { + static const int kMaxArrayIndexSize = 10; + static const int kMaxHashCalcLength = 16383; + static const int kNofHashBitFields = 2; + static const int kHashShift = kNofHashBitFields; + static const int kIsNotArrayIndexMask = 1 << 1; + static const int kArrayIndexValueBits = 24; + static const int kArrayIndexHashLengthShift = kArrayIndexValueBits + kNofHashBitFields; + static const int kMaxCachedArrayIndexLength = 7; +}; + +template <typename schar> +uint32_t calculateHash(const schar* chars, int length) { + if (length > String::kMaxHashCalcLength) { + // V8 trivial hash + return (length << String::kHashShift) | String::kIsNotArrayIndexMask; + } + + uint32_t raw_running_hash = 0; + uint32_t array_index = 0; + bool is_array_index = (0 < length && length <= String::kMaxArrayIndexSize); + bool is_first_char = true; + + int ii = 0; + for (;is_array_index && ii < length; ++ii) { + quint32 c = *chars++; + + raw_running_hash += c; + raw_running_hash += (raw_running_hash << 10); + raw_running_hash ^= (raw_running_hash >> 6); + + if (c < '0' || c > '9') { + is_array_index = false; + } else { + int d = c - '0'; + if (is_first_char) { + is_first_char = false; + if (c == '0' && length > 1) { + is_array_index = false; + continue; + } + } + if (array_index > 429496729U - ((d + 2) >> 3)) { + is_array_index = false; + } else { + array_index = array_index * 10 + d; + } + } + } + + for (;ii < length; ++ii) { + raw_running_hash += *chars++; + raw_running_hash += (raw_running_hash << 10); + raw_running_hash ^= (raw_running_hash >> 6); + } + + if (is_array_index) { + array_index <<= String::kHashShift; + array_index |= length << String::kArrayIndexHashLengthShift; + return array_index; + } else { + raw_running_hash += (raw_running_hash << 3); + raw_running_hash ^= (raw_running_hash >> 11); + raw_running_hash += (raw_running_hash << 15); + if (raw_running_hash == 0) { + raw_running_hash = 27; + } + + return (raw_running_hash << String::kHashShift) | String::kIsNotArrayIndexMask; + } +} + +inline quint32 stringHash(const QChar* data, int length) +{ + quint32 rv = calculateHash<quint16>((quint16*)data, length) >> String::kHashShift; + Q_ASSERT(rv == v8::String::ComputeHash((uint16_t*)data, length)); + return rv; +} + +inline quint32 stringHash(const char *data, int length) +{ + quint32 rv = calculateHash<quint8>((quint8*)data, length) >> String::kHashShift; + Q_ASSERT(rv == v8::String::ComputeHash((char *)data, length)); + return rv; +} + +void QHashedString::computeHash() const +{ + m_hash = stringHash(constData(), length()); +} + +void QHashedStringRef::computeHash() const +{ + m_hash = stringHash(m_data, m_length); +} + +void QHashedCStringRef::computeHash() const +{ + m_hash = stringHash(m_data, m_length); +} + +/* + A QHash has initially around pow(2, MinNumBits) buckets. For + example, if MinNumBits is 4, it has 17 buckets. +*/ +const int MinNumBits = 4; + +/* + The prime_deltas array is a table of selected prime values, even + though it doesn't look like one. The primes we are using are 1, + 2, 5, 11, 17, 37, 67, 131, 257, ..., i.e. primes in the immediate + surrounding of a power of two. + + The primeForNumBits() function returns the prime associated to a + power of two. For example, primeForNumBits(8) returns 257. +*/ + +static const uchar prime_deltas[] = { + 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3, + 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0 +}; + +static inline int primeForNumBits(int numBits) +{ + return (1 << numBits) + prime_deltas[numBits]; +} + +void QStringHashData::rehashToSize(int size, IteratorData first, + IteratorData (*Iterate)(const IteratorData &), + QStringHashNode *skip) +{ + short bits = qMax(MinNumBits, (int)numBits); + while (primeForNumBits(bits) < size) bits++; + + if (bits > numBits) + rehashToBits(bits, first, Iterate, skip); +} + +void QStringHashData::rehashToBits(short bits, IteratorData first, + IteratorData (*Iterate)(const IteratorData &), + QStringHashNode *skip) +{ + numBits = qMax(MinNumBits, (int)bits); + + int nb = primeForNumBits(numBits); + if (nb == numBuckets && buckets) + return; + + numBuckets = nb; + +#ifdef QSTRINGHASH_LINK_DEBUG + if (linkCount) + qFatal("QStringHash: Illegal attempt to rehash a linked hash."); +#endif + + delete [] buckets; + buckets = new QStringHashNode *[numBuckets]; + ::memset(buckets, 0, sizeof(QStringHashNode *) * numBuckets); + + IteratorData nodeList = first; + while (nodeList.n) { + if (nodeList.n != skip) { + int bucket = nodeList.n->hash % numBuckets; + nodeList.n->next = buckets[bucket]; + buckets[bucket] = nodeList.n; + } + + nodeList = Iterate(nodeList); + } +} + +// Copy of QString's qMemCompare +bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length) +{ + Q_ASSERT(lhs && rhs); + const quint16 *a = (const quint16 *)lhs; + const quint16 *b = (const quint16 *)rhs; + + if (a == b || !length) + return true; + + register union { + const quint16 *w; + const quint32 *d; + quintptr value; + } sa, sb; + sa.w = a; + sb.w = b; + + // check alignment + if ((sa.value & 2) == (sb.value & 2)) { + // both addresses have the same alignment + if (sa.value & 2) { + // both addresses are not aligned to 4-bytes boundaries + // compare the first character + if (*sa.w != *sb.w) + return false; + --length; + ++sa.w; + ++sb.w; + + // now both addresses are 4-bytes aligned + } + + // both addresses are 4-bytes aligned + // do a fast 32-bit comparison + register const quint32 *e = sa.d + (length >> 1); + for ( ; sa.d != e; ++sa.d, ++sb.d) { + if (*sa.d != *sb.d) + return false; + } + + // do we have a tail? + return (length & 1) ? *sa.w == *sb.w : true; + } else { + // one of the addresses isn't 4-byte aligned but the other is + register const quint16 *e = sa.w + length; + for ( ; sa.w != e; ++sa.w, ++sb.w) { + if (*sa.w != *sb.w) + return false; + } + } + return true; +} + +// Unicode stuff +static inline bool isUnicodeNonCharacter(uint ucs4) +{ + // Unicode has a couple of "non-characters" that one can use internally, + // but are not allowed to be used for text interchange. + // + // Those are the last two entries each Unicode Plane (U+FFFE, U+FFFF, + // U+1FFFE, U+1FFFF, etc.) as well as the entries between U+FDD0 and + // U+FDEF (inclusive) + + return (ucs4 & 0xfffe) == 0xfffe + || (ucs4 - 0xfdd0U) < 16; +} + +static int utf8LengthFromUtf16(const QChar *uc, int len) +{ + int length = 0; + + int surrogate_high = -1; + + const QChar *ch = uc; + int invalid = 0; + + const QChar *end = ch + len; + while (ch < end) { + uint u = ch->unicode(); + if (surrogate_high >= 0) { + if (u >= 0xdc00 && u < 0xe000) { + u = (surrogate_high - 0xd800)*0x400 + (u - 0xdc00) + 0x10000; + surrogate_high = -1; + } else { + // high surrogate without low + ++ch; + ++invalid; + surrogate_high = -1; + continue; + } + } else if (u >= 0xdc00 && u < 0xe000) { + // low surrogate without high + ++ch; + ++invalid; + continue; + } else if (u >= 0xd800 && u < 0xdc00) { + surrogate_high = u; + ++ch; + continue; + } + + if (u < 0x80) { + ++length; + } else { + if (u < 0x0800) { + ++length; + } else { + // is it one of the Unicode non-characters? + if (isUnicodeNonCharacter(u)) { + ++length; + ++ch; + ++invalid; + continue; + } + + if (u > 0xffff) { + ++length; + ++length; + } else { + ++length; + } + ++length; + } + ++length; + } + ++ch; + } + + return length; +} + +// Writes the utf8 version of uc to output. uc is of length len. +// There must be at least utf8LengthFromUtf16(uc, len) bytes in output. +// A null terminator is not written. +static void utf8FromUtf16(char *output, const QChar *uc, int len) +{ + uchar replacement = '?'; + int surrogate_high = -1; + + uchar* cursor = (uchar*)output; + const QChar *ch = uc; + int invalid = 0; + + const QChar *end = ch + len; + while (ch < end) { + uint u = ch->unicode(); + if (surrogate_high >= 0) { + if (u >= 0xdc00 && u < 0xe000) { + u = (surrogate_high - 0xd800)*0x400 + (u - 0xdc00) + 0x10000; + surrogate_high = -1; + } else { + // high surrogate without low + *cursor = replacement; + ++ch; + ++invalid; + surrogate_high = -1; + continue; + } + } else if (u >= 0xdc00 && u < 0xe000) { + // low surrogate without high + *cursor = replacement; + ++ch; + ++invalid; + continue; + } else if (u >= 0xd800 && u < 0xdc00) { + surrogate_high = u; + ++ch; + continue; + } + + if (u < 0x80) { + *cursor++ = (uchar)u; + } else { + if (u < 0x0800) { + *cursor++ = 0xc0 | ((uchar) (u >> 6)); + } else { + // is it one of the Unicode non-characters? + if (isUnicodeNonCharacter(u)) { + *cursor++ = replacement; + ++ch; + ++invalid; + continue; + } + + if (u > 0xffff) { + *cursor++ = 0xf0 | ((uchar) (u >> 18)); + *cursor++ = 0x80 | (((uchar) (u >> 12)) & 0x3f); + } else { + *cursor++ = 0xe0 | (((uchar) (u >> 12)) & 0x3f); + } + *cursor++ = 0x80 | (((uchar) (u >> 6)) & 0x3f); + } + *cursor++ = 0x80 | ((uchar) (u&0x3f)); + } + ++ch; + } +} + +void QHashedStringRef::computeUtf8Length() const +{ + if (m_length) + m_utf8length = utf8LengthFromUtf16(m_data, m_length); + else + m_utf8length = 0; +} + +QHashedStringRef QHashedStringRef::mid(int offset, int length) const +{ + Q_ASSERT(offset < m_length); + return QHashedStringRef(m_data + offset, + (length == -1 || (offset + length) > m_length)?(m_length - offset):length); +} + +bool QHashedStringRef::endsWith(const QString &s) const +{ + return s.length() < m_length && + QHashedString::compare(s.constData(), m_data + m_length - s.length(), s.length()); +} + +bool QHashedStringRef::startsWith(const QString &s) const +{ + return s.length() < m_length && + QHashedString::compare(s.constData(), m_data, s.length()); +} + +QString QHashedStringRef::toString() const +{ + if (m_length == 0) + return QString(); + return QString(m_data, m_length); +} + +QByteArray QHashedStringRef::toUtf8() const +{ + if (m_length == 0) + return QByteArray(); + + QByteArray result; + result.resize(utf8length()); + writeUtf8(result.data()); + return result; +} + +void QHashedStringRef::writeUtf8(char *output) const +{ + if (m_length) { + int ulen = utf8length(); + if (ulen == m_length) { + // Must be a latin1 string + uchar *o = (uchar *)output; + const QChar *c = m_data; + while (ulen--) + *o++ = (uchar)((*c++).unicode()); + } else { + utf8FromUtf16(output, m_data, m_length); + } + } +} + +QString QHashedCStringRef::toUtf16() const +{ + if (m_length == 0) + return QString(); + + QString rv; + rv.resize(m_length); + writeUtf16((uint16_t*)rv.data()); + return rv; +} + diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h new file mode 100644 index 0000000000..f575285ff6 --- /dev/null +++ b/src/qml/qml/ftw/qhashedstring_p.h @@ -0,0 +1,1418 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHASHEDSTRING_P_H +#define QHASHEDSTRING_P_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 <QtCore/qglobal.h> +#include <QtCore/qstring.h> +#include <private/qv8_p.h> + +#include <private/qflagpointer_p.h> + +QT_BEGIN_NAMESPACE + +// Enable this to debug hash linking assumptions. +// #define QSTRINGHASH_LINK_DEBUG + +class QHashedStringRef; +class Q_AUTOTEST_EXPORT QHashedString : public QString +{ +public: + inline QHashedString(); + inline QHashedString(const QString &string); + inline QHashedString(const QString &string, quint32); + inline QHashedString(const QHashedString &string); + + inline QHashedString &operator=(const QHashedString &string); + inline bool operator==(const QHashedString &string) const; + inline bool operator==(const QHashedStringRef &string) const; + + inline quint32 hash() const; + inline quint32 existingHash() const; + + static inline bool isUpper(const QChar &); + + static bool compare(const QChar *lhs, const QChar *rhs, int length); + static inline bool compare(const QChar *lhs, const char *rhs, int length); + static inline bool compare(const char *lhs, const char *rhs, int length); +private: + friend class QHashedStringRef; + friend class QStringHashNode; + + void computeHash() const; + mutable quint32 m_hash; +}; + +class Q_AUTOTEST_EXPORT QHashedV8String +{ +public: + inline QHashedV8String(); + explicit inline QHashedV8String(v8::Handle<v8::String>); + inline QHashedV8String(const QHashedV8String &string); + inline QHashedV8String &operator=(const QHashedV8String &other); + + inline bool operator==(const QHashedV8String &string); + + inline quint32 hash() const; + inline int length() const; + inline quint32 symbolId() const; + + inline v8::Handle<v8::String> string() const; + + inline QString toString() const; + +private: + v8::String::CompleteHashData m_hash; + v8::Handle<v8::String> m_string; +}; + +class QHashedCStringRef; +class Q_AUTOTEST_EXPORT QHashedStringRef +{ +public: + inline QHashedStringRef(); + inline QHashedStringRef(const QString &); + inline QHashedStringRef(const QStringRef &); + inline QHashedStringRef(const QChar *, int); + inline QHashedStringRef(const QChar *, int, quint32); + inline QHashedStringRef(const QHashedString &); + inline QHashedStringRef(const QHashedStringRef &); + inline QHashedStringRef &operator=(const QHashedStringRef &); + + inline bool operator==(const QString &string) const; + inline bool operator==(const QHashedString &string) const; + inline bool operator==(const QHashedStringRef &string) const; + inline bool operator==(const QHashedCStringRef &string) const; + inline bool operator!=(const QString &string) const; + inline bool operator!=(const QHashedString &string) const; + inline bool operator!=(const QHashedStringRef &string) const; + inline bool operator!=(const QHashedCStringRef &string) const; + + inline quint32 hash() const; + + inline const QChar &at(int) const; + inline const QChar *constData() const; + bool startsWith(const QString &) const; + bool endsWith(const QString &) const; + QHashedStringRef mid(int, int) const; + + inline bool isEmpty() const; + inline int length() const; + inline bool startsWithUpper() const; + + QString toString() const; + + inline int utf8length() const; + QByteArray toUtf8() const; + void writeUtf8(char *) const; +private: + friend class QHashedString; + + void computeHash() const; + void computeUtf8Length() const; + + const QChar *m_data; + int m_length; + mutable int m_utf8length; + mutable quint32 m_hash; +}; + +class Q_AUTOTEST_EXPORT QHashedCStringRef +{ +public: + inline QHashedCStringRef(); + inline QHashedCStringRef(const char *, int); + inline QHashedCStringRef(const char *, int, quint32); + inline QHashedCStringRef(const QHashedCStringRef &); + + inline quint32 hash() const; + + inline const char *constData() const; + inline int length() const; + + QString toUtf16() const; + inline int utf16length() const; + inline void writeUtf16(QChar *) const; + inline void writeUtf16(uint16_t *) const; +private: + friend class QHashedStringRef; + + void computeHash() const; + + const char *m_data; + int m_length; + mutable quint32 m_hash; +}; + +class QStringHashData; +class Q_AUTOTEST_EXPORT QStringHashNode +{ +public: + QStringHashNode() + : length(0), hash(0), symbolId(0), ckey(0) + { + } + + QStringHashNode(const QHashedString &key) + : length(key.length()), hash(key.hash()), symbolId(0) + { + strData = const_cast<QHashedString &>(key).data_ptr(); + setQString(true); + strData->ref.ref(); + } + + QStringHashNode(const QHashedCStringRef &key) + : length(key.length()), hash(key.hash()), symbolId(0), ckey(key.constData()) + { + } + + QStringHashNode(const QStringHashNode &o) + : length(o.length), hash(o.hash), symbolId(o.symbolId), ckey(o.ckey) + { + setQString(o.isQString()); + if (isQString()) { strData->ref.ref(); } + } + + ~QStringHashNode() + { + if (isQString()) { if (!strData->ref.deref()) free(strData); } + } + + QFlagPointer<QStringHashNode> next; + + qint32 length; + quint32 hash; + quint32 symbolId; + + union { + const char *ckey; + QStringData *strData; + }; + + bool isQString() const { return next.flag(); } + void setQString(bool v) { if (v) next.setFlag(); else next.clearFlag(); } + + inline char *cStrData() const { return (char *)ckey; } + inline uint16_t *utf16Data() const { return (uint16_t *)strData->data(); } + + inline bool equals(v8::Handle<v8::String> string) { + return isQString()?string->Equals(utf16Data(), length): + string->Equals(cStrData(), length); + } + + inline bool symbolEquals(const QHashedV8String &string) { + Q_ASSERT(string.symbolId() != 0); + return length == string.length() && hash == string.hash() && + (string.symbolId() == symbolId || equals(string.string())); + } + + inline bool equals(const QHashedV8String &string) { + return length == string.length() && hash == string.hash() && + equals(string.string()); + } + + inline bool equals(const QHashedStringRef &string) { + return length == string.length() && + hash == string.hash() && + (isQString()?QHashedString::compare(string.constData(), (QChar *)utf16Data(), length): + QHashedString::compare(string.constData(), cStrData(), length)); + } + + inline bool equals(const QHashedCStringRef &string) { + return length == string.length() && + hash == string.hash() && + (isQString()?QHashedString::compare((QChar *)utf16Data(), string.constData(), length): + QHashedString::compare(string.constData(), cStrData(), length)); + } +}; + +class Q_AUTOTEST_EXPORT QStringHashData +{ +public: + QStringHashData() + : buckets(0), numBuckets(0), size(0), numBits(0) +#ifdef QSTRINGHASH_LINK_DEBUG + , linkCount(0) +#endif + {} + + QStringHashNode **buckets; + int numBuckets; + int size; + short numBits; +#ifdef QSTRINGHASH_LINK_DEBUG + int linkCount; +#endif + + struct IteratorData { + IteratorData() : n(0), p(0) {} + QStringHashNode *n; + void *p; + }; + void rehashToBits(short, IteratorData, IteratorData (*Iterate)(const IteratorData &), + QStringHashNode *skip = 0); + void rehashToSize(int, IteratorData, IteratorData (*Iterate)(const IteratorData &), + QStringHashNode *skip = 0); + +private: + QStringHashData(const QStringHashData &); + QStringHashData &operator=(const QStringHashData &); +}; + +template<class T> +class QStringHash +{ +public: + struct Node : public QStringHashNode { + Node(const QHashedString &key, const T &value) : QStringHashNode(key), value(value) {} + Node(const QHashedCStringRef &key, const T &value) : QStringHashNode(key), value(value) {} + Node(const Node &o) : QStringHashNode(o), value(o.value) {} + Node() {} + T value; + }; + struct NewedNode : public Node { + NewedNode(const QHashedString &key, const T &value) : Node(key, value), nextNewed(0) {} + NewedNode(const QHashedCStringRef &key, const T &value) : Node(key, value), nextNewed(0) {} + NewedNode(const Node &o) : Node(o), nextNewed(0) {} + NewedNode *nextNewed; + }; + struct ReservedNodePool + { + ReservedNodePool() : count(0), used(0), nodes(0) {} + ~ReservedNodePool() { delete [] nodes; } + int count; + int used; + Node *nodes; + }; + + QStringHashData data; + NewedNode *newedNodes; + ReservedNodePool *nodePool; + const QStringHash<T> *link; + + inline Node *findNode(const QString &) const; + inline Node *findNode(const QHashedString &) const; + inline Node *findNode(const QHashedStringRef &) const; + inline Node *findNode(const QHashedCStringRef &) const; + inline Node *findNode(const QHashedV8String &) const; + inline Node *findSymbolNode(const QHashedV8String &) const; + inline Node *createNode(const Node &o); + inline Node *createNode(const QHashedString &, const T &); + inline Node *createNode(const QHashedCStringRef &, const T &); + + inline Node *takeNode(const QHashedString &key, const T &value); + inline Node *takeNode(const QHashedCStringRef &key, const T &value); + inline Node *takeNode(const Node &o); + + inline void copy(const QStringHash<T> &); + + inline QStringHashData::IteratorData iterateFirst() const; + static inline QStringHashData::IteratorData iterateNext(const QStringHashData::IteratorData &); + +public: + inline QStringHash(); + inline QStringHash(const QStringHash &); + inline ~QStringHash(); + + QStringHash &operator=(const QStringHash<T> &); + + void copyAndReserve(const QStringHash<T> &other, int additionalReserve); + void linkAndReserve(const QStringHash<T> &other, int additionalReserve); + + inline bool isEmpty() const; + inline void clear(); + inline int count() const; + + inline int numBuckets() const; + inline bool isLinked() const; + + class ConstIterator { + public: + inline ConstIterator(); + inline ConstIterator(const QStringHashData::IteratorData &); + + inline ConstIterator &operator++(); + + inline bool operator==(const ConstIterator &o) const; + inline bool operator!=(const ConstIterator &o) const; + + inline QHashedString key() const; + inline const T &value() const; + inline const T &operator*() const; + + inline Node *node() const; + private: + QStringHashData::IteratorData d; + }; + + inline void insert(const QString &, const T &); + inline void insert(const QHashedString &, const T &); + inline void insert(const QHashedStringRef &, const T &); + inline void insert(const QHashedCStringRef &, const T &); + inline void insert(const ConstIterator &); + + inline T *value(const QString &) const; + inline T *value(const QHashedString &) const; + inline T *value(const QHashedStringRef &) const; + inline T *value(const QHashedV8String &) const; + inline T *value(const QHashedCStringRef &) const; + inline T *value(const ConstIterator &) const; + + inline bool contains(const QString &) const; + inline bool contains(const QHashedString &) const; + inline bool contains(const QHashedStringRef &) const; + inline bool contains(const QHashedCStringRef &) const; + inline bool contains(const ConstIterator &) const; + + inline T &operator[](const QString &); + inline T &operator[](const QHashedString &); + inline T &operator[](const QHashedStringRef &); + inline T &operator[](const QHashedCStringRef &); + + inline ConstIterator begin() const; + inline ConstIterator end() const; + + inline void reserve(int); +}; + +template<class T> +QStringHash<T>::QStringHash() +: newedNodes(0), nodePool(0), link(0) +{ +} + +template<class T> +QStringHash<T>::QStringHash(const QStringHash<T> &other) +: newedNodes(0), nodePool(0), link(0) +{ + data.numBits = other.data.numBits; + data.size = other.data.size; + reserve(other.count()); + copy(other); +} + +template<class T> +QStringHash<T> &QStringHash<T>::operator=(const QStringHash<T> &other) +{ + if (&other == this) + return *this; + + clear(); + + data.numBits = other.data.numBits; + data.size = other.data.size; + reserve(other.count()); + copy(other); + + return *this; +} + +template<class T> +void QStringHash<T>::copyAndReserve(const QStringHash<T> &other, int additionalReserve) +{ + clear(); + data.numBits = other.data.numBits; + reserve(other.count() + additionalReserve); + copy(other); +} + +template<class T> +void QStringHash<T>::linkAndReserve(const QStringHash<T> &other, int additionalReserve) +{ + clear(); + + if (other.count()) { + data.size = other.data.size; + data.rehashToSize(other.count() + additionalReserve, iterateFirst(), iterateNext); + + if (data.numBuckets == other.data.numBuckets) { + nodePool = new ReservedNodePool; + nodePool->count = additionalReserve; + nodePool->used = 0; + nodePool->nodes = new Node[additionalReserve]; + +#ifdef QSTRINGHASH_LINK_DEBUG + data.linkCount++; + const_cast<QStringHash<T>&>(other).data.linkCount++; +#endif + + for (int ii = 0; ii < data.numBuckets; ++ii) { + data.buckets[ii] = 0; + Node *n = (Node *)other.data.buckets[ii]; + data.buckets[ii] = n; + } + + link = &other; + return; + } + + data.size = 0; + } + + data.numBits = other.data.numBits; + reserve(other.count() + additionalReserve); + copy(other); +} + +template<class T> +QStringHash<T>::~QStringHash() +{ + clear(); +} + +template<class T> +void QStringHash<T>::clear() +{ +#ifdef QSTRINGHASH_LINK_DEBUG + if (link) { + data.linkCount--; + const_cast<QStringHash<T> *>(link)->data.linkCount--; + } + + if (data.linkCount) + qFatal("QStringHash: Illegal attempt to clear a linked hash."); +#endif + + // Delete the individually allocated nodes + NewedNode *n = newedNodes; + while (n) { + NewedNode *c = n; + n = c->nextNewed; + delete c; + } + // Delete the pool allocated nodes + if (nodePool) delete nodePool; + delete [] data.buckets; + + data.buckets = 0; + data.numBuckets = 0; + data.numBits = 0; + data.size = 0; + + newedNodes = 0; + nodePool = 0; + link = 0; +} + +template<class T> +bool QStringHash<T>::isEmpty() const +{ + return data.size== 0; +} + +template<class T> +int QStringHash<T>::count() const +{ + return data.size; +} + +template<class T> +int QStringHash<T>::numBuckets() const +{ + return data.numBuckets; +} + +template<class T> +bool QStringHash<T>::isLinked() const +{ + return link != 0; +} + +template<class T> +typename QStringHash<T>::Node *QStringHash<T>::takeNode(const QHashedString &key, const T &value) +{ + if (nodePool && nodePool->used != nodePool->count) { + Node *rv = nodePool->nodes + nodePool->used++; + rv->length = key.length(); + rv->hash = key.hash(); + rv->strData = const_cast<QHashedString &>(key).data_ptr(); + rv->strData->ref.ref(); + rv->setQString(true); + rv->value = value; + return rv; + } else { + NewedNode *rv = new NewedNode(key, value); + rv->nextNewed = newedNodes; + newedNodes = rv; + return rv; + } +} + +template<class T> +typename QStringHash<T>::Node *QStringHash<T>::takeNode(const QHashedCStringRef &key, const T &value) +{ + if (nodePool && nodePool->used != nodePool->count) { + Node *rv = nodePool->nodes + nodePool->used++; + rv->length = key.length(); + rv->hash = key.hash(); + rv->ckey = key.constData(); + rv->value = value; + return rv; + } else { + NewedNode *rv = new NewedNode(key, value); + rv->nextNewed = newedNodes; + newedNodes = rv; + return rv; + } +} + +template<class T> +typename QStringHash<T>::Node *QStringHash<T>::takeNode(const Node &o) +{ + if (nodePool && nodePool->used != nodePool->count) { + Node *rv = nodePool->nodes + nodePool->used++; + rv->length = o.length; + rv->hash = o.hash; + if (o.isQString()) { + rv->strData = o.strData; + rv->strData->ref.ref(); + rv->setQString(true); + } else { + rv->ckey = o.ckey; + } + rv->symbolId = o.symbolId; + rv->value = o.value; + return rv; + } else { + NewedNode *rv = new NewedNode(o); + rv->nextNewed = newedNodes; + newedNodes = rv; + return rv; + } +} + +template<class T> +void QStringHash<T>::copy(const QStringHash<T> &other) +{ + Q_ASSERT(data.size == 0); + + data.size = other.data.size; + + // Ensure buckets array is created + data.rehashToBits(data.numBits, iterateFirst(), iterateNext); + + if (other.link) { + for (ConstIterator iter = other.begin(); iter != other.end(); ++iter) { + Node *o = iter.node(); + Node *n = o->isQString()?findNode(QHashedStringRef((QChar *)o->strData->data(), o->length, o->hash)): + findNode(QHashedCStringRef(o->ckey, o->length, o->hash)); + if (!n) { + Node *mynode = takeNode(*o); + int bucket = mynode->hash % data.numBuckets; + mynode->next = data.buckets[bucket]; + data.buckets[bucket] = mynode; + } + } + } else { + for (ConstIterator iter = other.begin(); iter != other.end(); ++iter) { + Node *o = iter.node(); + Node *mynode = takeNode(*o); + int bucket = mynode->hash % data.numBuckets; + mynode->next = data.buckets[bucket]; + data.buckets[bucket] = mynode; + } + } +} + +template<class T> +QStringHashData::IteratorData +QStringHash<T>::iterateNext(const QStringHashData::IteratorData &d) +{ + QStringHash<T> *This = (QStringHash<T> *)d.p; + Node *node = (Node *)d.n; + + if (This->nodePool && node >= This->nodePool->nodes && + node < (This->nodePool->nodes + This->nodePool->used)) { + node--; + if (node < This->nodePool->nodes) + node = 0; + } else { + NewedNode *nn = (NewedNode *)node; + node = nn->nextNewed; + + if (node == 0 && This->nodePool && This->nodePool->used) + node = This->nodePool->nodes + This->nodePool->used - 1; + } + + if (node == 0 && This->link) + return This->link->iterateFirst(); + + QStringHashData::IteratorData rv; + rv.n = node; + rv.p = d.p; + return rv; +} + +template<class T> +QStringHashData::IteratorData QStringHash<T>::iterateFirst() const +{ + Node *n = 0; + if (newedNodes) + n = newedNodes; + else if (nodePool && nodePool->used) + n = nodePool->nodes + nodePool->used - 1; + + if (n == 0 && link) + return link->iterateFirst(); + + QStringHashData::IteratorData rv; + rv.n = n; + rv.p = const_cast<QStringHash<T> *>(this); + return rv; +} + +template<class T> +typename QStringHash<T>::Node *QStringHash<T>::createNode(const Node &o) +{ + Node *n = takeNode(o); + + if (data.size >= data.numBuckets) + data.rehashToBits(data.numBits + 1, iterateFirst(), iterateNext, n); + + int bucket = n->hash % data.numBuckets; + n->next = data.buckets[bucket]; + data.buckets[bucket] = n; + + data.size++; + + return n; +} + +template<class T> +typename QStringHash<T>::Node *QStringHash<T>::createNode(const QHashedString &key, const T &value) +{ + Node *n = takeNode(key, value); + + if (data.size >= data.numBuckets) + data.rehashToBits(data.numBits + 1, iterateFirst(), iterateNext, n); + + int bucket = key.hash() % data.numBuckets; + n->next = data.buckets[bucket]; + data.buckets[bucket] = n; + + data.size++; + + return n; +} + +template<class T> +typename QStringHash<T>::Node *QStringHash<T>::createNode(const QHashedCStringRef &key, const T &value) +{ + Node *n = takeNode(key, value); + + if (data.size >= data.numBuckets) + data.rehashToBits(data.numBits + 1, iterateFirst(), iterateNext, n); + + int bucket = key.hash() % data.numBuckets; + n->next = data.buckets[bucket]; + data.buckets[bucket] = n; + + data.size++; + + return n; +} + +template<class T> +void QStringHash<T>::insert(const QString &key, const T &value) +{ + QHashedStringRef ch(key); + // If this is a linked hash, we can't rely on owning the node, so we always + // create a new one. + Node *n = link?0:findNode(key); + if (n) n->value = value; + else createNode(QHashedString(key, ch.hash()), value); +} + +template<class T> +void QStringHash<T>::insert(const QHashedString &key, const T &value) +{ + // If this is a linked hash, we can't rely on owning the node, so we always + // create a new one. + Node *n = link?0:findNode(key); + if (n) n->value = value; + else createNode(key, value); +} + +template<class T> +void QStringHash<T>::insert(const QHashedStringRef &key, const T &value) +{ + // If this is a linked hash, we can't rely on owning the node, so we always + // create a new one. + Node *n = link?0:findNode(key); + if (n) n->value = value; + else createNode(key, value); +} + +template<class T> +void QStringHash<T>::insert(const QHashedCStringRef &key, const T &value) +{ + // If this is a linked hash, we can't rely on owning the node, so we always + // create a new one. + Node *n = link?0:findNode(key); + if (n) n->value = value; + else createNode(key, value); +} + +template<class T> +void QStringHash<T>::insert(const ConstIterator &key) +{ + // If this is a linked hash, we can't rely on owning the node, so we always + // create a new one. + if (key.node()->isQString()) { + QHashedStringRef str((QChar *)key.node()->strData->data(), key.node()->length, + key.node()->hash); + + Node *n = link?0:findNode(str); + if (n) n->value = key.node()->value; + else createNode(*key.node()); + } else { + QHashedCStringRef str(key.node()->ckey, key.node()->length, key.node()->hash); + + Node *n = link?0:findNode(str); + if (n) n->value = key.node()->value; + else createNode(str, key.node()->value); + } +} + +template<class T> +typename QStringHash<T>::Node *QStringHash<T>::findNode(const QString &string) const +{ + return findNode(QHashedStringRef(string)); +} + +template<class T> +typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedString &string) const +{ + return findNode(QHashedStringRef(string.constData(), string.length(), string.hash())); +} + +template<class T> +typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedStringRef &string) const +{ + QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0; + while (node && !node->equals(string)) + node = (*node->next); + + return (Node *)node; +} + +template<class T> +typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedCStringRef &string) const +{ + QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0; + while (node && !node->equals(string)) + node = (*node->next); + + return (Node *)node; +} + +template<class T> +typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedV8String &string) const +{ + QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0; + while (node && !node->equals(string)) + node = (*node->next); + + return (Node *)node; +} + +template<class T> +typename QStringHash<T>::Node *QStringHash<T>::findSymbolNode(const QHashedV8String &string) const +{ + Q_ASSERT(string.symbolId() != 0); + + QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0; + while (node && !node->symbolEquals(string)) + node = (*node->next); + + if (node) + node->symbolId = string.symbolId(); + + return (Node *)node; +} + +template<class T> +T *QStringHash<T>::value(const QString &key) const +{ + Node *n = findNode(key); + return n?&n->value:0; +} + +template<class T> +T *QStringHash<T>::value(const QHashedString &key) const +{ + Node *n = findNode(key); + return n?&n->value:0; +} + +template<class T> +T *QStringHash<T>::value(const QHashedStringRef &key) const +{ + Node *n = findNode(key); + return n?&n->value:0; +} + +template<class T> +T *QStringHash<T>::value(const QHashedCStringRef &key) const +{ + Node *n = findNode(key); + return n?&n->value:0; +} + +template<class T> +T *QStringHash<T>::value(const ConstIterator &iter) const +{ + Node *n = iter.node(); + if (n->isQString()) + return value(QHashedStringRef((QChar *)n->strData->data(), n->length, n->hash)); + else + return value(QHashedCStringRef(n->ckey, n->length, n->hash)); +} + +template<class T> +T *QStringHash<T>::value(const QHashedV8String &string) const +{ + Node *n = string.symbolId()?findSymbolNode(string):findNode(string); + return n?&n->value:0; +} + +template<class T> +bool QStringHash<T>::contains(const QString &s) const +{ + return 0 != value(s); +} + +template<class T> +bool QStringHash<T>::contains(const QHashedString &s) const +{ + return 0 != value(s); +} + +template<class T> +bool QStringHash<T>::contains(const QHashedStringRef &s) const +{ + return 0 != value(s); +} + +template<class T> +bool QStringHash<T>::contains(const QHashedCStringRef &s) const +{ + return 0 != value(s); +} + +template<class T> +bool QStringHash<T>::contains(const ConstIterator &s) const +{ + return 0 != value(s); +} + +template<class T> +T &QStringHash<T>::operator[](const QString &key) +{ + QHashedStringRef cs(key); + Node *n = findNode(cs); + if (n) return n->value; + else return createNode(QHashedString(key, cs.hash()), T())->value; +} + +template<class T> +T &QStringHash<T>::operator[](const QHashedString &key) +{ + Node *n = findNode(key); + if (n) return n->value; + else return createNode(key, T())->value; +} + +template<class T> +T &QStringHash<T>::operator[](const QHashedStringRef &key) +{ + Node *n = findNode(key); + if (n) return n->value; + else return createNode(key, T())->value; +} + +template<class T> +T &QStringHash<T>::operator[](const QHashedCStringRef &key) +{ + Node *n = findNode(key); + if (n) return n->value; + else return createNode(key, T())->value; +} + +template<class T> +void QStringHash<T>::reserve(int n) +{ + if (nodePool || 0 == n) + return; + + nodePool = new ReservedNodePool; + nodePool->count = n; + nodePool->used = 0; + nodePool->nodes = new Node[n]; + + data.rehashToSize(n, iterateFirst(), iterateNext); +} + +template<class T> +QStringHash<T>::ConstIterator::ConstIterator() +{ +} + +template<class T> +QStringHash<T>::ConstIterator::ConstIterator(const QStringHashData::IteratorData &d) +: d(d) +{ +} + +template<class T> +typename QStringHash<T>::ConstIterator &QStringHash<T>::ConstIterator::operator++() +{ + d = QStringHash<T>::iterateNext(d); + return *this; +} + +template<class T> +bool QStringHash<T>::ConstIterator::operator==(const ConstIterator &o) const +{ + return d.n == o.d.n; +} + +template<class T> +bool QStringHash<T>::ConstIterator::operator!=(const ConstIterator &o) const +{ + return d.n != o.d.n; +} + +template<class T> +QHashedString QStringHash<T>::ConstIterator::key() const +{ + Node *n = (Node *)d.n; + if (n->isQString()) { + return QHashedString(QString((QChar *)n->strData->data(), n->length), n->hash); + } else { + return QHashedString(QString::fromLatin1(n->ckey, n->length), n->hash); + } +} +template<class T> +const T &QStringHash<T>::ConstIterator::value() const +{ + Node *n = (Node *)d.n; + return n->value; +} + +template<class T> +const T &QStringHash<T>::ConstIterator::operator*() const +{ + Node *n = (Node *)d.n; + return n->value; +} + +template<class T> +typename QStringHash<T>::Node *QStringHash<T>::ConstIterator::node() const +{ + Node *n = (Node *)d.n; + return n; +} + +template<class T> +typename QStringHash<T>::ConstIterator QStringHash<T>::begin() const +{ + return ConstIterator(iterateFirst()); +} + +template<class T> +typename QStringHash<T>::ConstIterator QStringHash<T>::end() const +{ + return ConstIterator(); +} + +inline uint qHash(const QHashedString &string) +{ + return uint(string.hash()); +} + +inline uint qHash(const QHashedStringRef &string) +{ + return uint(string.hash()); +} + +QHashedString::QHashedString() +: QString(), m_hash(0) +{ +} + +QHashedString::QHashedString(const QString &string) +: QString(string), m_hash(0) +{ +} + +QHashedString::QHashedString(const QString &string, quint32 hash) +: QString(string), m_hash(hash) +{ +} + +QHashedString::QHashedString(const QHashedString &string) +: QString(string), m_hash(string.m_hash) +{ +} + +QHashedString &QHashedString::operator=(const QHashedString &string) +{ + static_cast<QString &>(*this) = string; + m_hash = string.m_hash; + return *this; +} + +bool QHashedString::operator==(const QHashedString &string) const +{ + return (string.m_hash == m_hash || !string.m_hash || !m_hash) && + static_cast<const QString &>(*this) == static_cast<const QString &>(string); +} + +bool QHashedString::operator==(const QHashedStringRef &string) const +{ + return length() == string.m_length && + (string.m_hash == m_hash || !string.m_hash || !m_hash) && + QHashedString::compare(constData(), string.m_data, string.m_length); +} + +quint32 QHashedString::hash() const +{ + if (!m_hash) computeHash(); + return m_hash; +} + +quint32 QHashedString::existingHash() const +{ + return m_hash; +} + +bool QHashedString::isUpper(const QChar &qc) +{ + ushort c = qc.unicode(); + // Optimize for _, a-z and A-Z. + return ((c != '_' ) && (!(c >= 'a' && c <= 'z')) && + ((c >= 'A' && c <= 'Z') || QChar::category(c) == QChar::Letter_Uppercase)); +} + +QHashedV8String::QHashedV8String() +{ +} + +QHashedV8String::QHashedV8String(v8::Handle<v8::String> string) +: m_hash(string->CompleteHash()), m_string(string) +{ + Q_ASSERT(!m_string.IsEmpty()); +} + +QHashedV8String::QHashedV8String(const QHashedV8String &string) +: m_hash(string.m_hash), m_string(string.m_string) +{ +} + +QHashedV8String &QHashedV8String::operator=(const QHashedV8String &other) +{ + m_hash = other.m_hash; + m_string = other.m_string; + return *this; +} + +bool QHashedV8String::operator==(const QHashedV8String &string) +{ + return m_hash.hash == string.m_hash.hash && m_hash.length == string.m_hash.length && + m_string.IsEmpty() == m_string.IsEmpty() && + (m_string.IsEmpty() || m_string->StrictEquals(string.m_string)); +} + +quint32 QHashedV8String::hash() const +{ + return m_hash.hash; +} + +int QHashedV8String::length() const +{ + return m_hash.length; +} + +quint32 QHashedV8String::symbolId() const +{ + return m_hash.symbol_id; +} + +v8::Handle<v8::String> QHashedV8String::string() const +{ + return m_string; +} + +QString QHashedV8String::toString() const +{ + QString result; + result.reserve(m_hash.length); + + for (int i = 0; i < m_hash.length; ++i) + result.append(m_string->GetCharacter(i)); + + return result; +} + +QHashedStringRef::QHashedStringRef() +: m_data(0), m_length(0), m_utf8length(-1), m_hash(0) +{ +} + +QHashedStringRef::QHashedStringRef(const QString &str) +: m_data(str.constData()), m_length(str.length()), m_utf8length(0), m_hash(0) +{ +} + +QHashedStringRef::QHashedStringRef(const QStringRef &str) +: m_data(str.constData()), m_length(str.length()), m_utf8length(0), m_hash(0) +{ +} + +QHashedStringRef::QHashedStringRef(const QChar *data, int length) +: m_data(data), m_length(length), m_utf8length(0), m_hash(0) +{ +} + +QHashedStringRef::QHashedStringRef(const QChar *data, int length, quint32 hash) +: m_data(data), m_length(length), m_utf8length(0), m_hash(hash) +{ +} + +QHashedStringRef::QHashedStringRef(const QHashedString &string) +: m_data(string.constData()), m_length(string.length()), m_utf8length(0), m_hash(string.m_hash) +{ +} + +QHashedStringRef::QHashedStringRef(const QHashedStringRef &string) +: m_data(string.m_data), m_length(string.m_length), m_utf8length(string.m_utf8length), + m_hash(string.m_hash) +{ +} + +QHashedStringRef &QHashedStringRef::operator=(const QHashedStringRef &o) +{ + m_data = o.m_data; + m_length = o.m_length; + m_utf8length = o.m_utf8length; + m_hash = o.m_hash; + return *this; +} + +bool QHashedStringRef::operator==(const QString &string) const +{ + return m_length == string.length() && + QHashedString::compare(string.constData(), m_data, m_length); +} + +bool QHashedStringRef::operator==(const QHashedString &string) const +{ + return m_length == string.length() && + (m_hash == string.m_hash || !m_hash || !string.m_hash) && + QHashedString::compare(string.constData(), m_data, m_length); +} + +bool QHashedStringRef::operator==(const QHashedStringRef &string) const +{ + return m_length == string.m_length && + (m_hash == string.m_hash || !m_hash || !string.m_hash) && + QHashedString::compare(string.m_data, m_data, m_length); +} + +bool QHashedStringRef::operator==(const QHashedCStringRef &string) const +{ + return m_length == string.m_length && + (m_hash == string.m_hash || !m_hash || !string.m_hash) && + QHashedString::compare(m_data, string.m_data, m_length); +} + +bool QHashedStringRef::operator!=(const QString &string) const +{ + return m_length != string.length() || + !QHashedString::compare(string.constData(), m_data, m_length); +} + +bool QHashedStringRef::operator!=(const QHashedString &string) const +{ + return m_length != string.length() || + (m_hash != string.m_hash && m_hash && string.m_hash) || + !QHashedString::compare(string.constData(), m_data, m_length); +} + +bool QHashedStringRef::operator!=(const QHashedStringRef &string) const +{ + return m_length != string.m_length || + (m_hash != string.m_hash && m_hash && string.m_hash) || + QHashedString::compare(string.m_data, m_data, m_length); +} + +bool QHashedStringRef::operator!=(const QHashedCStringRef &string) const +{ + return m_length != string.m_length || + (m_hash != string.m_hash && m_hash && string.m_hash) || + QHashedString::compare(m_data, string.m_data, m_length); +} + +const QChar &QHashedStringRef::at(int index) const +{ + Q_ASSERT(index < m_length); + return m_data[index]; +} + +const QChar *QHashedStringRef::constData() const +{ + return m_data; +} + +bool QHashedStringRef::isEmpty() const +{ + return m_length == 0; +} + +int QHashedStringRef::length() const +{ + return m_length; +} + +int QHashedStringRef::utf8length() const +{ + if (m_utf8length < m_length) + computeUtf8Length(); + return m_utf8length; +} + +bool QHashedStringRef::startsWithUpper() const +{ + if (m_length < 1) return false; + return QHashedString::isUpper(m_data[0]); +} + +quint32 QHashedStringRef::hash() const +{ + if (!m_hash) computeHash(); + return m_hash; +} + +QHashedCStringRef::QHashedCStringRef() +: m_data(0), m_length(0), m_hash(0) +{ +} + +QHashedCStringRef::QHashedCStringRef(const char *data, int length) +: m_data(data), m_length(length), m_hash(0) +{ +} + +QHashedCStringRef::QHashedCStringRef(const char *data, int length, quint32 hash) +: m_data(data), m_length(length), m_hash(hash) +{ +} + +QHashedCStringRef::QHashedCStringRef(const QHashedCStringRef &o) +: m_data(o.m_data), m_length(o.m_length), m_hash(o.m_hash) +{ +} + +quint32 QHashedCStringRef::hash() const +{ + if (!m_hash) computeHash(); + return m_hash; +} + +const char *QHashedCStringRef::constData() const +{ + return m_data; +} + +int QHashedCStringRef::length() const +{ + return m_length; +} + +int QHashedCStringRef::utf16length() const +{ + return m_length; +} + +void QHashedCStringRef::writeUtf16(QChar *output) const +{ + writeUtf16((uint16_t *)output); +} + +void QHashedCStringRef::writeUtf16(uint16_t *output) const +{ + int l = m_length; + const char *d = m_data; + while (l--) + *output++ = *d++; +} + +bool QHashedString::compare(const QChar *lhs, const char *rhs, int length) +{ + Q_ASSERT(lhs && rhs); + const quint16 *l = (const quint16*)lhs; + while (length--) + if (*l++ != *rhs++) return false; + return true; +} + +bool QHashedString::compare(const char *lhs, const char *rhs, int length) +{ + Q_ASSERT(lhs && rhs); + return 0 == ::memcmp(lhs, rhs, length); +} + +QT_END_NAMESPACE + +#endif // QHASHEDSTRING_P_H diff --git a/src/qml/qml/ftw/qhashfield_p.h b/src/qml/qml/ftw/qhashfield_p.h new file mode 100644 index 0000000000..46df9a176c --- /dev/null +++ b/src/qml/qml/ftw/qhashfield_p.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHASHFIELD_P_H +#define QHASHFIELD_P_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 <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +// QHashField can be used for doing coarse grained set testing, in +// cases where you do not expect the set to contain the item. For +// example where you would write: +// QSet<QString> strings; +// for (int ii = 0; ii < mystrings.count(); ++ii) { +// if (strings.contains(mystrings.at(ii))) +// qFatal("Duplication!"); +// strings.insert(mystrings); +// } +// You may write: +// QHashField strings; +// for (int ii = 0; ii < mystrings.count(); ++ii) { +// if (strings.testAndSet(qHash(mystrings.at(ii)))) { +// // The string *might* be duplicated +// for (int jj = 0; jj < ii; ++jj) { +// if (mystrings.at(ii) == mystrings.at(jj)) +// qFatal("Duplication!"); +// } +// } +// } +// For small lists of things, where the hash is cheap to calculate +// and you don't expect duplication this will be much faster. +class QHashField { +public: + inline QHashField(); + + inline void clear(); + + inline bool test(quint32 hash); + inline bool testAndSet(quint32 hash); +private: + quint32 m_field; +}; + +QHashField::QHashField() +: m_field(0) +{ +} + +void QHashField::clear() +{ + m_field = 0; +} + +bool QHashField::test(quint32 hash) +{ + return m_field & (1 << (hash % 31)); +} + +bool QHashField::testAndSet(quint32 hash) +{ + quint32 mask = 1 << (hash % 31); + bool rv = m_field & mask; + m_field |= mask; + return rv; +} + +QT_END_NAMESPACE + +#endif // QHASHFIELD_P_H diff --git a/src/qml/qml/ftw/qintrusivelist.cpp b/src/qml/qml/ftw/qintrusivelist.cpp new file mode 100644 index 0000000000..5a1624f1f4 --- /dev/null +++ b/src/qml/qml/ftw/qintrusivelist.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qintrusivelist_p.h" + +/*! +\class QIntrusiveList +\brief The QIntrusiveList class is a template class that provides a list of objects using static storage. +\internal + +QIntrusiveList creates a linked list of objects. Adding and removing objects from the +QIntrusiveList is a constant time operation and is very quick. The list performs no memory +allocations, but does require the objects being added to the list to contain a QIntrusiveListNode +instance for the list's use. Even so, for small lists QIntrusiveList uses less memory than Qt's +other list classes. + +As QIntrusiveList uses storage inside the objects in the list, each object can only be in one +list at a time. Objects are inserted by the insert() method. If the object is already +in a list (including the one it is being inserted into) it is first removed, and then inserted +at the head of the list. QIntrusiveList is a last-in-first-out list. That is, following an +insert() the inserted object becomes the list's first() object. + +\code +struct MyObject { + MyObject(int value) : value(value) {} + + int value; + QIntrusiveListNode node; +}; +typedef QIntrusiveList<MyObject, &MyObject::node> MyObjectList; + +void foo() { + MyObjectList list; + + MyObject m0(0); + MyObject m1(1); + MyObject m2(2); + + list.insert(&m0); + list.insert(&m1); + list.insert(&m2); + + // QIntrusiveList is LIFO, so will print: 2... 1... 0... + for (MyObjectList::iterator iter = list.begin(); iter != list.end(); ++iter) { + qWarning() << iter->value; + } +} +\endcode +*/ + + +/*! +\fn QIntrusiveList::QIntrusiveList(); + +Construct an empty list. +*/ + +/*! +\fn QIntrusiveList::~QIntrusiveList(); + +Destroy the list. All entries are removed. +*/ + +/*! +\fn void QIntrusiveList::insert(N *object); + +Insert \a object into the list. If \a object is a member of this, or another list, it will be +removed and inserted at the head of this list. +*/ + +/*! +\fn void QIntrusiveList::remove(N *object); + +Remove \a object from the list. \a object must not be null. +*/ + +/*! +\fn bool QIntrusiveList::contains(N *object) const + +Returns true if the list contains \a object; otherwise returns false. +*/ + +/*! +\fn N *QIntrusiveList::first() const + +Returns the first entry in this list, or null if the list is empty. +*/ + +/*! +\fn N *QIntrusiveList::next(N *current) + +Returns the next object after \a current, or null if \a current is the last object. \a current cannot be null. +*/ + +/*! +\fn iterator QIntrusiveList::begin() + +Returns an STL-style interator pointing to the first item in the list. + +\sa end() +*/ + +/*! +\fn iterator QIntrusiveList::end() + +Returns an STL-style iterator pointing to the imaginary item after the last item in the list. + +\sa begin() +*/ + +/*! +iterator &QInplacelist::iterator::erase() + +Remove the current object from the list, and return an iterator to the next element. +*/ + + +/*! +\fn QIntrusiveListNode::QIntrusiveListNode() + +Create a QIntrusiveListNode. +*/ + +/*! +\fn QIntrusiveListNode::~QIntrusiveListNode() + +Destroy the QIntrusiveListNode. If the node is in a list, it is removed. +*/ + +/*! +\fn void QIntrusiveListNode::remove() + +If in a list, remove this node otherwise do nothing. +*/ + +/*! +\fn bool QIntrusiveListNode::isInList() const + +Returns true if this node is in a list, false otherwise. +*/ + diff --git a/src/qml/qml/ftw/qintrusivelist_p.h b/src/qml/qml/ftw/qintrusivelist_p.h new file mode 100644 index 0000000000..489b02d656 --- /dev/null +++ b/src/qml/qml/ftw/qintrusivelist_p.h @@ -0,0 +1,274 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QINTRUSIVELIST_P_H +#define QINTRUSIVELIST_P_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 <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QIntrusiveListNode; +template<class N, QIntrusiveListNode N::*member> +class QIntrusiveList +{ +public: + inline QIntrusiveList(); + inline ~QIntrusiveList(); + + inline bool isEmpty() const; + inline void insert(N *n); + inline void remove(N *n); + inline bool contains(N *) const; + + class iterator { + public: + inline iterator(); + inline iterator(N *value); + + inline N *operator*() const; + inline N *operator->() const; + inline bool operator==(const iterator &other) const; + inline bool operator!=(const iterator &other) const; + inline iterator &operator++(); + + inline iterator &erase(); + + private: + N *_value; + }; + typedef iterator Iterator; + + inline N *first() const; + static inline N *next(N *current); + + inline iterator begin(); + inline iterator end(); + +private: + static inline N *nodeToN(QIntrusiveListNode *node); + + QIntrusiveListNode *__first; +}; + +class QIntrusiveListNode +{ +public: + inline QIntrusiveListNode(); + inline ~QIntrusiveListNode(); + + inline void remove(); + inline bool isInList() const; + + QIntrusiveListNode *_next; + QIntrusiveListNode**_prev; +}; + +template<class N, QIntrusiveListNode N::*member> +QIntrusiveList<N, member>::iterator::iterator() +: _value(0) +{ +} + +template<class N, QIntrusiveListNode N::*member> +QIntrusiveList<N, member>::iterator::iterator(N *value) +: _value(value) +{ +} + +template<class N, QIntrusiveListNode N::*member> +N *QIntrusiveList<N, member>::iterator::operator*() const +{ + return _value; +} + +template<class N, QIntrusiveListNode N::*member> +N *QIntrusiveList<N, member>::iterator::operator->() const +{ + return _value; +} + +template<class N, QIntrusiveListNode N::*member> +bool QIntrusiveList<N, member>::iterator::operator==(const iterator &other) const +{ + return other._value == _value; +} + +template<class N, QIntrusiveListNode N::*member> +bool QIntrusiveList<N, member>::iterator::operator!=(const iterator &other) const +{ + return other._value != _value; +} + +template<class N, QIntrusiveListNode N::*member> +typename QIntrusiveList<N, member>::iterator &QIntrusiveList<N, member>::iterator::operator++() +{ + _value = QIntrusiveList<N, member>::next(_value); + return *this; +} + +template<class N, QIntrusiveListNode N::*member> +typename QIntrusiveList<N, member>::iterator &QIntrusiveList<N, member>::iterator::erase() +{ + N *old = _value; + _value = QIntrusiveList<N, member>::next(_value); + (old->*member).remove(); + return *this; +} + +template<class N, QIntrusiveListNode N::*member> +QIntrusiveList<N, member>::QIntrusiveList() +: __first(0) +{ +} + +template<class N, QIntrusiveListNode N::*member> +QIntrusiveList<N, member>::~QIntrusiveList() +{ + while (__first) __first->remove(); +} + +template<class N, QIntrusiveListNode N::*member> +bool QIntrusiveList<N, member>::isEmpty() const +{ + return __first == 0; +} + +template<class N, QIntrusiveListNode N::*member> +void QIntrusiveList<N, member>::insert(N *n) +{ + QIntrusiveListNode *nnode = &(n->*member); + nnode->remove(); + + nnode->_next = __first; + if (nnode->_next) nnode->_next->_prev = &nnode->_next; + __first = nnode; + nnode->_prev = &__first; +} + +template<class N, QIntrusiveListNode N::*member> +void QIntrusiveList<N, member>::remove(N *n) +{ + QIntrusiveListNode *nnode = &(n->*member); + nnode->remove(); +} + +template<class N, QIntrusiveListNode N::*member> +bool QIntrusiveList<N, member>::contains(N *n) const +{ + QIntrusiveListNode *nnode = __first; + while (nnode) { + if (nodeToN(nnode) == n) + return true; + nnode = nnode->_next; + } + return false; +} + +template<class N, QIntrusiveListNode N::*member> +N *QIntrusiveList<N, member>::first() const +{ + return __first?nodeToN(__first):0; +} + +template<class N, QIntrusiveListNode N::*member> +N *QIntrusiveList<N, member>::next(N *current) +{ + QIntrusiveListNode *nextnode = (current->*member)._next; + N *nextstruct = nextnode?nodeToN(nextnode):0; + return nextstruct; +} + +template<class N, QIntrusiveListNode N::*member> +typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::begin() +{ + return __first?iterator(nodeToN(__first)):iterator(); +} + +template<class N, QIntrusiveListNode N::*member> +typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::end() +{ + return iterator(); +} + +template<class N, QIntrusiveListNode N::*member> +N *QIntrusiveList<N, member>::nodeToN(QIntrusiveListNode *node) +{ + return (N *)((char *)node - ((char *)&(((N *)0)->*member) - (char *)0)); +} + +QIntrusiveListNode::QIntrusiveListNode() +: _next(0), _prev(0) +{ +} + +QIntrusiveListNode::~QIntrusiveListNode() +{ + remove(); +} + +void QIntrusiveListNode::remove() +{ + if (_prev) *_prev = _next; + if (_next) _next->_prev = _prev; + _prev = 0; + _next = 0; +} + +bool QIntrusiveListNode::isInList() const +{ + return _prev != 0; +} + +QT_END_NAMESPACE + +#endif // QINTRUSIVELIST_P_H diff --git a/src/qml/qml/ftw/qlazilyallocated_p.h b/src/qml/qml/ftw/qlazilyallocated_p.h new file mode 100644 index 0000000000..960d84d5e7 --- /dev/null +++ b/src/qml/qml/ftw/qlazilyallocated_p.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLAZILYALLOCATED_P_H +#define QLAZILYALLOCATED_P_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 <QtCore/qglobal.h> + +#include <private/qflagpointer_p.h> + +QT_BEGIN_NAMESPACE + +template<typename T> +class QLazilyAllocated { +public: + inline QLazilyAllocated(); + inline ~QLazilyAllocated(); + + inline bool isAllocated() const; + + inline T *operator->() const; + + inline T &value(); + inline const T &value() const; + + inline bool flag() const; + inline void setFlag(); + inline void clearFlag(); + inline void setFlagValue(bool); +private: + mutable QFlagPointer<T> d; +}; + +template<typename T> +QLazilyAllocated<T>::QLazilyAllocated() +{ +} + +template<typename T> +QLazilyAllocated<T>::~QLazilyAllocated() +{ + delete *d; +} + +template<typename T> +bool QLazilyAllocated<T>::isAllocated() const +{ + return !d.isNull(); +} + +template<typename T> +T &QLazilyAllocated<T>::value() +{ + if (d.isNull()) d = new T; + return *(*d); +} + +template<typename T> +const T &QLazilyAllocated<T>::value() const +{ + if (d.isNull()) d = new T; + return *(*d); +} + +template<typename T> +T *QLazilyAllocated<T>::operator->() const +{ + return *d; +} + +template<typename T> +bool QLazilyAllocated<T>::flag() const +{ + return d.flag(); +} + +template<typename T> +void QLazilyAllocated<T>::setFlag() +{ + d.setFlag(); +} + +template<typename T> +void QLazilyAllocated<T>::clearFlag() +{ + d.clearFlag(); +} + +template<typename T> +void QLazilyAllocated<T>::setFlagValue(bool v) +{ + d.setFlagValue(v); +} + +QT_END_NAMESPACE + +#endif // QLAZILYALLOCATED_P_H diff --git a/src/qml/qml/ftw/qpodvector_p.h b/src/qml/qml/ftw/qpodvector_p.h new file mode 100644 index 0000000000..c96692667a --- /dev/null +++ b/src/qml/qml/ftw/qpodvector_p.h @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPODVECTOR_P_H +#define QPODVECTOR_P_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 <QtCore/qglobal.h> +#include <QDebug> + +QT_BEGIN_NAMESPACE + +template<class T, int Increment=1024> +class QPODVector +{ +public: + QPODVector() + : m_count(0), m_capacity(0), m_data(0) {} + ~QPODVector() { if (m_data) ::free(m_data); } + + const T &at(int idx) const { + return m_data[idx]; + } + + T &operator[](int idx) { + return m_data[idx]; + } + + void clear() { + m_count = 0; + } + + void prepend(const T &v) { + insert(0, v); + } + + void append(const T &v) { + insert(m_count, v); + } + + void insert(int idx, const T &v) { + if (m_count == m_capacity) { + m_capacity += Increment; + m_data = (T *)realloc(m_data, m_capacity * sizeof(T)); + } + int moveCount = m_count - idx; + if (moveCount) + ::memmove(m_data + idx + 1, m_data + idx, moveCount * sizeof(T)); + m_count++; + m_data[idx] = v; + } + + void reserve(int count) { + if (count >= m_capacity) { + m_capacity = (count + (Increment-1)) & (0xFFFFFFFF - Increment + 1); + m_data = (T *)realloc(m_data, m_capacity * sizeof(T)); + } + } + + void insertBlank(int idx, int count) { + int newSize = m_count + count; + reserve(newSize); + int moveCount = m_count - idx; + if (moveCount) + ::memmove(m_data + idx + count, m_data + idx, + moveCount * sizeof(T)); + m_count = newSize; + } + + void remove(int idx, int count = 1) { + int moveCount = m_count - (idx + count); + if (moveCount) + ::memmove(m_data + idx, m_data + idx + count, + moveCount * sizeof(T)); + m_count -= count; + } + + void removeOne(const T &v) { + int idx = 0; + while (idx < m_count) { + if (m_data[idx] == v) { + remove(idx); + return; + } + ++idx; + } + } + + int find(const T &v) { + for (int idx = 0; idx < m_count; ++idx) + if (m_data[idx] == v) + return idx; + return -1; + } + + bool contains(const T &v) { + return find(v) != -1; + } + + int count() const { + return m_count; + } + + void copyAndClear(QPODVector<T,Increment> &other) { + if (other.m_data) ::free(other.m_data); + other.m_count = m_count; + other.m_capacity = m_capacity; + other.m_data = m_data; + m_count = 0; + m_capacity = 0; + m_data = 0; + } + + QPODVector<T,Increment> &operator<<(const T &v) { append(v); return *this; } +private: + QPODVector(const QPODVector &); + QPODVector &operator=(const QPODVector &); + int m_count; + int m_capacity; + T *m_data; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/qml/qml/ftw/qpointervaluepair_p.h b/src/qml/qml/ftw/qpointervaluepair_p.h new file mode 100644 index 0000000000..7b0caf49bc --- /dev/null +++ b/src/qml/qml/ftw/qpointervaluepair_p.h @@ -0,0 +1,196 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPOINTERVALUEPAIR_P_H +#define QPOINTERVALUEPAIR_P_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 <QtCore/qglobal.h> +#include <private/qflagpointer_p.h> + +QT_BEGIN_NAMESPACE + +// QPointerValuePair is intended to help reduce the memory consumption of a class. +// In the common case, QPointerValuePair behaves like a pointer. In this mode, it +// consumes the same memory as a regular pointer. +// Additionally, QPointerValuePair can store an arbitrary value type in *addition* +// to the pointer. In this case, it uses slightly more memory than the pointer and +// value type combined. +// Consequently, this class is most useful in cases where a pointer is always stored +// and a value type is rarely stored. +template<typename P, typename V> +class QPointerValuePair { +public: + inline QPointerValuePair(); + inline QPointerValuePair(P *); + inline ~QPointerValuePair(); + + inline bool isNull() const; + + inline bool flag() const; + inline void setFlag(); + inline void clearFlag(); + inline void setFlagValue(bool); + + inline QPointerValuePair<P, V> &operator=(P *); + + inline P *operator->() const; + inline P *operator*() const; + + inline bool hasValue() const; + inline V &value(); + inline const V *constValue() const; + +private: + struct Value { P *pointer; V value; }; + QBiPointer<P, Value> d; +}; + +template<typename P, typename V> +QPointerValuePair<P, V>::QPointerValuePair() +{ +} + +template<typename P, typename V> +QPointerValuePair<P, V>::QPointerValuePair(P *p) +: d(p) +{ +} + +template<typename P, typename V> +QPointerValuePair<P, V>::~QPointerValuePair() +{ + if (d.isT2()) delete d.asT2(); +} + +template<typename P, typename V> +bool QPointerValuePair<P, V>::isNull() const +{ + if (d.isT1()) return 0 == d.asT1(); + else return d.asT2()->pointer == 0; +} + +template<typename P, typename V> +bool QPointerValuePair<P, V>::flag() const +{ + return d.flag(); +} + +template<typename P, typename V> +void QPointerValuePair<P, V>::setFlag() +{ + d.setFlag(); +} + +template<typename P, typename V> +void QPointerValuePair<P, V>::clearFlag() +{ + d.clearFlag(); +} + +template<typename P, typename V> +void QPointerValuePair<P, V>::setFlagValue(bool v) +{ + d.setFlagValue(v); +} + +template<typename P, typename V> +QPointerValuePair<P, V> &QPointerValuePair<P, V>::operator=(P *o) +{ + if (d.isT1()) d = o; + else d.asT2()->pointer = o; + return *this; +} + +template<typename P, typename V> +P *QPointerValuePair<P, V>::operator->() const +{ + if (d.isT1()) return d.asT1(); + else return d.asT2()->pointer; +} + +template<typename P, typename V> +P *QPointerValuePair<P, V>::operator*() const +{ + if (d.isT1()) return d.asT1(); + else return d.asT2()->pointer; +} + +template<typename P, typename V> +bool QPointerValuePair<P, V>::hasValue() const +{ + return d.isT2(); +} + +template<typename P, typename V> +V &QPointerValuePair<P, V>::value() +{ + if (d.isT1()) { + P *p = d.asT1(); + Value *value = new Value; + value->pointer = p; + d = value; + } + + return d.asT2()->value; +} + +// Will return null if hasValue() == false +template<typename P, typename V> +const V *QPointerValuePair<P, V>::constValue() const +{ + if (d.isT2()) return &d.asT2()->value; + else return 0; +} + +QT_END_NAMESPACE + +#endif // QPOINTERVALUEPAIR_P_H diff --git a/src/qml/qml/ftw/qqmlpool.cpp b/src/qml/qml/ftw/qqmlpool.cpp new file mode 100644 index 0000000000..6fd11d4b1e --- /dev/null +++ b/src/qml/qml/ftw/qqmlpool.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlpool_p.h" + +// #define POOL_DEBUG + +QT_BEGIN_NAMESPACE + +void QQmlPool::newpage() +{ +#ifdef POOL_DEBUG + qWarning("QQmlPool: Allocating page"); +#endif + + Page *page = (Page *)malloc(sizeof(Page)); + page->header.next = _page; + page->header.free = page->memory; + _page = page; +} + +void QQmlPool::clear() +{ +#ifdef POOL_DEBUG + int count = 0; +#endif + + Class *c = _classList; + while (c) { + Class *n = c->_next; + c->_destroy(c); +#ifdef POOL_DEBUG + ++count; +#endif + c = n; + } + +#ifdef POOL_DEBUG + qWarning("QQmlPool: Destroyed %d objects", count); +#endif + + Page *p = _page; + while (p) { + Page *n = p->header.next; + free(p); + p = n; + } + + _classList = 0; + _page = 0; +} + + +QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qqmlpool_p.h b/src/qml/qml/ftw/qqmlpool_p.h new file mode 100644 index 0000000000..e4fa03ce34 --- /dev/null +++ b/src/qml/qml/ftw/qqmlpool_p.h @@ -0,0 +1,278 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLPOOL_P_H +#define QQMLPOOL_P_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 <QtQml/qtqmlglobal.h> +#include <QtCore/qstring.h> +#include <QtCore/qurl.h> + +QT_BEGIN_NAMESPACE + +// Exported for QtQuick1 +class Q_QML_EXPORT QQmlPool +{ +public: + // The class has a destructor that needs to be called + class Class { + public: + inline QQmlPool *pool() const; + + private: + void *operator new(size_t); + void *operator new(size_t, void *m) { return m; } + friend class QQmlPool; + + QQmlPool *_pool; + Class *_next; + void (*_destroy)(Class *); + }; + + // The class is plain old data and no destructor needs to + // be called + class POD { + public: + inline QQmlPool *pool() const; + + private: + void *operator new(size_t); + void *operator new(size_t, void *m) { return m; } + friend class QQmlPool; + + QQmlPool *_pool; + }; + + inline QQmlPool(); + inline ~QQmlPool(); + + void clear(); + + template<typename T> + inline T *New(); + template<typename T> + inline T *NewRaw(); + template<typename T> + inline T *NewRawArray(int length); + + inline QString *NewString(const QString &); + inline QByteArray *NewByteArray(const QByteArray &); + inline QUrl *NewUrl(const QUrl &); + + template<typename T> + struct List { + List() : m_length(0), m_data(0) {} + List(const List &o) : m_length(o.m_length), m_data(o.m_data) {} + List &operator=(const List &o) { + m_length = o.m_length; + m_data = o.m_data; + return *this; + } + + int count() const { + return m_length; + } + int length() const { + return m_length; + } + const T &at(int index) const { + Q_ASSERT(index < m_length); + return m_data[index]; + }; + T &operator[](int index) { + Q_ASSERT(index < m_length); + return m_data[index]; + }; + private: + friend class QQmlPool; + List(T *d, int l) : m_length(l), m_data(d) {} + int m_length; + T *m_data; + }; + + template<typename T> + inline List<T> NewRawList(int length); + +private: + struct StringClass : public QString, public Class { + }; + struct ByteArrayClass : public QByteArray, public Class { + }; + struct UrlClass : public QUrl, public Class { + }; + + inline void *allocate(int size); + void newpage(); + + template<typename T> + inline void initialize(POD *); + template<typename T> + inline void initialize(Class *); + template<typename T> + static void destroy(Class *c); + + struct Page { + struct Header { + Page *next; + char *free; + } header; + + static const int pageSize = 4 * 4096 - sizeof(Header); + + char memory[pageSize]; + }; + + Page *_page; + Class *_classList; +}; + +QQmlPool::QQmlPool() +: _page(0), _classList(0) +{ +} + +QQmlPool::~QQmlPool() +{ + clear(); +} + +template<typename T> +T *QQmlPool::New() +{ + T *rv = new (allocate(sizeof(T))) T; + initialize<T>(rv); + rv->_pool = this; + return rv; +} + +template<typename T> +T *QQmlPool::NewRaw() +{ + return (T*)allocate(sizeof(T)); +} + +template<typename T> +T *QQmlPool::NewRawArray(int length) +{ + return (T*)allocate(length * sizeof(T)); +} + +template<typename T> +QQmlPool::List<T> QQmlPool::NewRawList(int length) +{ + return List<T>(NewRawArray<T>(length), length); +} + +QString *QQmlPool::NewString(const QString &s) +{ + QString *rv = New<StringClass>(); + *rv = s; + return rv; +} + +QByteArray *QQmlPool::NewByteArray(const QByteArray &s) +{ + QByteArray *rv = New<ByteArrayClass>(); + *rv = s; + return rv; +} + +QUrl *QQmlPool::NewUrl(const QUrl &s) +{ + QUrl *rv = New<UrlClass>(); + *rv = s; + return rv; +} + +void *QQmlPool::allocate(int size) +{ + if (!_page || (_page->header.free + size) > (_page->memory + Page::pageSize)) + newpage(); + + void *rv = _page->header.free; + _page->header.free += size + ((8 - size) & 7); // ensure 8 byte alignment; + return rv; +} + +template<typename T> +void QQmlPool::initialize(QQmlPool::POD *) +{ +} + +template<typename T> +void QQmlPool::initialize(QQmlPool::Class *c) +{ + c->_next = _classList; + c->_destroy = &destroy<T>; + _classList = c; +} + +template<typename T> +void QQmlPool::destroy(Class *c) +{ + static_cast<T *>(c)->~T(); +} + +QQmlPool *QQmlPool::Class::pool() const +{ + return _pool; +} + +QQmlPool *QQmlPool::POD::pool() const +{ + return _pool; +} + +QT_END_NAMESPACE + +#endif // QQMLPOOL_P_H + diff --git a/src/qml/qml/ftw/qqmlrefcount_p.h b/src/qml/qml/ftw/qqmlrefcount_p.h new file mode 100644 index 0000000000..497f4ecc0f --- /dev/null +++ b/src/qml/qml/ftw/qqmlrefcount_p.h @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLREFCOUNT_P_H +#define QQMLREFCOUNT_P_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 <QtCore/qglobal.h> +#include <QtCore/qatomic.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QQmlRefCount +{ +public: + inline QQmlRefCount(); + inline virtual ~QQmlRefCount(); + inline void addref(); + inline void release(); + +protected: + inline virtual void destroy(); + +private: + QAtomicInt refCount; +}; + +template<class T> +class QQmlRefPointer +{ +public: + inline QQmlRefPointer(); + inline QQmlRefPointer(T *); + inline QQmlRefPointer(const QQmlRefPointer<T> &); + inline ~QQmlRefPointer(); + + inline QQmlRefPointer<T> &operator=(const QQmlRefPointer<T> &o); + inline QQmlRefPointer<T> &operator=(T *); + + inline bool isNull() const { return !o; } + + inline T* operator->() const { return o; } + inline T& operator*() const { return *o; } + inline operator T*() const { return o; } + inline T* data() const { return o; } + + inline QQmlRefPointer<T> &take(T *); + +private: + T *o; +}; + +QQmlRefCount::QQmlRefCount() +: refCount(1) +{ +} + +QQmlRefCount::~QQmlRefCount() +{ + Q_ASSERT(refCount.load() == 0); +} + +void QQmlRefCount::addref() +{ + Q_ASSERT(refCount.load() > 0); + refCount.ref(); +} + +void QQmlRefCount::release() +{ + Q_ASSERT(refCount.load() > 0); + if (!refCount.deref()) + destroy(); +} + +void QQmlRefCount::destroy() +{ + delete this; +} + +template<class T> +QQmlRefPointer<T>::QQmlRefPointer() +: o(0) +{ +} + +template<class T> +QQmlRefPointer<T>::QQmlRefPointer(T *o) +: o(o) +{ + if (o) o->addref(); +} + +template<class T> +QQmlRefPointer<T>::QQmlRefPointer(const QQmlRefPointer<T> &other) +: o(other.o) +{ + if (o) o->addref(); +} + +template<class T> +QQmlRefPointer<T>::~QQmlRefPointer() +{ + if (o) o->release(); +} + +template<class T> +QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(const QQmlRefPointer<T> &other) +{ + if (other.o) other.o->addref(); + if (o) o->release(); + o = other.o; + return *this; +} + +template<class T> +QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(T *other) +{ + if (other) other->addref(); + if (o) o->release(); + o = other; + return *this; +} + +/*! +Takes ownership of \a other. take() does *not* add a reference, as it assumes ownership +of the callers reference of other. +*/ +template<class T> +QQmlRefPointer<T> &QQmlRefPointer<T>::take(T *other) +{ + if (o) o->release(); + o = other; + return *this; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QQMLREFCOUNT_P_H diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp new file mode 100644 index 0000000000..423012b934 --- /dev/null +++ b/src/qml/qml/ftw/qqmlthread.cpp @@ -0,0 +1,359 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlthread_p.h" + +#include <private/qfieldlist_p.h> + +#include <QtCore/qmutex.h> +#include <QtCore/qthread.h> +#include <QtCore/qcoreevent.h> +#include <QtCore/qwaitcondition.h> +#include <QtCore/qcoreapplication.h> + +QT_BEGIN_NAMESPACE + +class QQmlThreadPrivate : public QThread +{ +public: + QQmlThreadPrivate(QQmlThread *); + QQmlThread *q; + + virtual void run(); + + inline void lock() { _mutex.lock(); } + inline void unlock() { _mutex.unlock(); } + inline void wait() { _wait.wait(&_mutex); } + inline void wakeOne() { _wait.wakeOne(); } + inline void wakeAll() { _wait.wakeAll(); } + + quint32 m_threadProcessing:1; // Set when the thread is processing messages + quint32 m_mainProcessing:1; // Set when the main thread is processing messages + quint32 m_shutdown:1; // Set by main thread to request a shutdown + quint32 m_mainThreadWaiting:1; // Set by main thread if it is waiting for the message queue to empty + + typedef QFieldList<QQmlThread::Message, &QQmlThread::Message::next> MessageList; + MessageList threadList; + MessageList mainList; + + QQmlThread::Message *mainSync; + + void triggerMainEvent(); + void triggerThreadEvent(); + + void mainEvent(); + void threadEvent(); + +protected: + virtual bool event(QEvent *); + +private: + struct MainObject : public QObject { + MainObject(QQmlThreadPrivate *p); + virtual bool event(QEvent *e); + QQmlThreadPrivate *p; + }; + MainObject m_mainObject; + + QMutex _mutex; + QWaitCondition _wait; +}; + +QQmlThreadPrivate::MainObject::MainObject(QQmlThreadPrivate *p) +: p(p) +{ +} + +// Trigger mainEvent in main thread. Must be called from thread. +void QQmlThreadPrivate::triggerMainEvent() +{ + Q_ASSERT(q->isThisThread()); + QCoreApplication::postEvent(&m_mainObject, new QEvent(QEvent::User)); +} + +// Trigger even in thread. Must be called from main thread. +void QQmlThreadPrivate::triggerThreadEvent() +{ + Q_ASSERT(!q->isThisThread()); + QCoreApplication::postEvent(this, new QEvent(QEvent::User)); +} + +bool QQmlThreadPrivate::MainObject::event(QEvent *e) +{ + if (e->type() == QEvent::User) + p->mainEvent(); + return QObject::event(e); +} + +QQmlThreadPrivate::QQmlThreadPrivate(QQmlThread *q) +: q(q), m_threadProcessing(false), m_mainProcessing(false), m_shutdown(false), + m_mainThreadWaiting(false), mainSync(0), m_mainObject(this) +{ +} + +bool QQmlThreadPrivate::event(QEvent *e) +{ + if (e->type() == QEvent::User) + threadEvent(); + return QThread::event(e); +} + +void QQmlThreadPrivate::run() +{ + lock(); + + wakeOne(); + + unlock(); + + q->startupThread(); + exec(); +} + +void QQmlThreadPrivate::mainEvent() +{ + lock(); + + m_mainProcessing = true; + + while (!mainList.isEmpty() || mainSync) { + bool isSync = mainSync != 0; + QQmlThread::Message *message = isSync?mainSync:mainList.takeFirst(); + unlock(); + + message->call(q); + delete message; + + lock(); + + if (isSync) { + mainSync = 0; + wakeOne(); + } + } + + m_mainProcessing = false; + + unlock(); +} + +void QQmlThreadPrivate::threadEvent() +{ + lock(); + + if (m_shutdown) { + quit(); + wakeOne(); + unlock(); + q->shutdownThread(); + } else { + m_threadProcessing = true; + + while (!threadList.isEmpty()) { + QQmlThread::Message *message = threadList.first(); + + unlock(); + + message->call(q); + + lock(); + + delete threadList.takeFirst(); + } + + wakeOne(); + + m_threadProcessing = false; + + unlock(); + } +} + +QQmlThread::QQmlThread() +: d(new QQmlThreadPrivate(this)) +{ + d->lock(); + d->start(); + d->wait(); + d->unlock(); + d->moveToThread(d); + +} + +QQmlThread::~QQmlThread() +{ + delete d; +} + +void QQmlThread::shutdown() +{ + d->lock(); + Q_ASSERT(!d->m_shutdown); + d->m_shutdown = true; + if (d->threadList.isEmpty() && d->m_threadProcessing == false) + d->triggerThreadEvent(); + d->wait(); + d->unlock(); + d->QThread::wait(); +} + +void QQmlThread::lock() +{ + d->lock(); +} + +void QQmlThread::unlock() +{ + d->unlock(); +} + +void QQmlThread::wakeOne() +{ + d->wakeOne(); +} + +void QQmlThread::wakeAll() +{ + d->wakeAll(); +} + +void QQmlThread::wait() +{ + d->wait(); +} + +bool QQmlThread::isThisThread() const +{ + return QThread::currentThread() == d; +} + +QThread *QQmlThread::thread() const +{ + return const_cast<QThread *>(static_cast<const QThread *>(d)); +} + +// Called when the thread starts. Do startup stuff in here. +void QQmlThread::startupThread() +{ +} + +// Called when the thread shuts down. Do cleanup in here. +void QQmlThread::shutdownThread() +{ +} + +void QQmlThread::internalCallMethodInThread(Message *message) +{ + Q_ASSERT(!isThisThread()); + d->lock(); + Q_ASSERT(d->m_mainThreadWaiting == false); + + bool wasEmpty = d->threadList.isEmpty(); + d->threadList.append(message); + if (wasEmpty && d->m_threadProcessing == false) + d->triggerThreadEvent(); + + d->m_mainThreadWaiting = true; + + do { + if (d->mainSync) { + QQmlThread::Message *message = d->mainSync; + unlock(); + message->call(this); + delete message; + lock(); + d->mainSync = 0; + wakeOne(); + } else { + d->wait(); + } + } while (d->mainSync || !d->threadList.isEmpty()); + + d->m_mainThreadWaiting = false; + d->unlock(); +} + +void QQmlThread::internalCallMethodInMain(Message *message) +{ + Q_ASSERT(isThisThread()); + + d->lock(); + + Q_ASSERT(d->mainSync == 0); + d->mainSync = message; + + if (d->m_mainThreadWaiting) { + d->wakeOne(); + } else if (d->m_mainProcessing) { + // Do nothing - it is already looping + } else { + d->triggerMainEvent(); + } + + while (d->mainSync && !d->m_shutdown) + d->wait(); + + d->unlock(); +} + +void QQmlThread::internalPostMethodToThread(Message *message) +{ + Q_ASSERT(!isThisThread()); + d->lock(); + bool wasEmpty = d->threadList.isEmpty(); + d->threadList.append(message); + if (wasEmpty && d->m_threadProcessing == false) + d->triggerThreadEvent(); + d->unlock(); +} + +void QQmlThread::internalPostMethodToMain(Message *message) +{ + Q_ASSERT(isThisThread()); + d->lock(); + bool wasEmpty = d->mainList.isEmpty(); + d->mainList.append(message); + if (wasEmpty && d->m_mainProcessing == false) + d->triggerMainEvent(); + d->unlock(); +} + +QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qqmlthread_p.h b/src/qml/qml/ftw/qqmlthread_p.h new file mode 100644 index 0000000000..8a0ec6ceaa --- /dev/null +++ b/src/qml/qml/ftw/qqmlthread_p.h @@ -0,0 +1,318 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLTHREAD_P_H +#define QQMLTHREAD_P_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 <QtCore/qglobal.h> + +#include <private/qintrusivelist_p.h> + +QT_BEGIN_NAMESPACE + +class QThread; + +class QQmlThreadPrivate; +class QQmlThread +{ +public: + QQmlThread(); + virtual ~QQmlThread(); + void shutdown(); + + void lock(); + void unlock(); + void wakeOne(); + void wakeAll(); + void wait(); + + QThread *thread() const; + bool isThisThread() const; + + // Synchronously invoke a method in the thread + template<class O> + inline void callMethodInThread(void (O::*Member)()); + template<typename T, class V, class O> + inline void callMethodInThread(void (O::*Member)(V), const T &); + template<typename T, typename T2, class V, class V2, class O> + inline void callMethodInThread(void (O::*Member)(V, V2), const T &, const T2 &); + + // Synchronously invoke a method in the main thread. If the main thread is + // blocked in a callMethodInThread() call, the call is made from within that + // call. + template<class O> + inline void callMethodInMain(void (O::*Member)()); + template<typename T, class V, class O> + inline void callMethodInMain(void (O::*Member)(V), const T &); + template<typename T, typename T2, class V, class V2, class O> + inline void callMethodInMain(void (O::*Member)(V, V2), const T &, const T2 &); + + // Asynchronously invoke a method in the thread. + template<class O> + inline void postMethodToThread(void (O::*Member)()); + template<typename T, class V, class O> + inline void postMethodToThread(void (O::*Member)(V), const T &); + template<typename T, typename T2, class V, class V2, class O> + inline void postMethodToThread(void (O::*Member)(V, V2), const T &, const T2 &); + + // Asynchronously invoke a method in the main thread. + template<class O> + inline void postMethodToMain(void (O::*Member)()); + template<typename T, class V, class O> + inline void postMethodToMain(void (O::*Member)(V), const T &); + template<typename T, typename T2, class V, class V2, class O> + inline void postMethodToMain(void (O::*Member)(V, V2), const T &, const T2 &); + +protected: + virtual void startupThread(); + virtual void shutdownThread(); + +private: + friend class QQmlThreadPrivate; + + struct Message { + Message() : next(0) {} + virtual ~Message() {} + Message *next; + virtual void call(QQmlThread *) = 0; + }; + void internalCallMethodInThread(Message *); + void internalCallMethodInMain(Message *); + void internalPostMethodToThread(Message *); + void internalPostMethodToMain(Message *); + QQmlThreadPrivate *d; +}; + +template<class O> +void QQmlThread::callMethodInThread(void (O::*Member)()) +{ + struct I : public Message { + void (O::*Member)(); + I(void (O::*Member)()) : Member(Member) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(); + } + }; + internalCallMethodInThread(new I(Member)); +} + +template<typename T, class V, class O> +void QQmlThread::callMethodInThread(void (O::*Member)(V), const T &arg) +{ + struct I : public Message { + void (O::*Member)(V); + T arg; + I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(arg); + } + }; + internalCallMethodInThread(new I(Member, arg)); +} + +template<typename T, typename T2, class V, class V2, class O> +void QQmlThread::callMethodInThread(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) +{ + struct I : public Message { + void (O::*Member)(V, V2); + T arg; + T2 arg2; + I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(arg, arg2); + } + }; + internalCallMethodInThread(new I(Member, arg, arg2)); +} + +template<class O> +void QQmlThread::callMethodInMain(void (O::*Member)()) +{ + struct I : public Message { + void (O::*Member)(); + I(void (O::*Member)()) : Member(Member) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(); + } + }; + internalCallMethodInMain(new I(Member)); +} + +template<typename T, class V, class O> +void QQmlThread::callMethodInMain(void (O::*Member)(V), const T &arg) +{ + struct I : public Message { + void (O::*Member)(V); + T arg; + I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(arg); + } + }; + internalCallMethodInMain(new I(Member, arg)); +} + +template<typename T, typename T2, class V, class V2, class O> +void QQmlThread::callMethodInMain(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) +{ + struct I : public Message { + void (O::*Member)(V, V2); + T arg; + T2 arg2; + I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(arg, arg2); + } + }; + internalCallMethodInMain(new I(Member, arg, arg2)); +} + +template<class O> +void QQmlThread::postMethodToThread(void (O::*Member)()) +{ + struct I : public Message { + void (O::*Member)(); + I(void (O::*Member)()) : Member(Member) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(); + } + }; + internalPostMethodToThread(new I(Member)); +} + +template<typename T, class V, class O> +void QQmlThread::postMethodToThread(void (O::*Member)(V), const T &arg) +{ + struct I : public Message { + void (O::*Member)(V); + T arg; + I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(arg); + } + }; + internalPostMethodToThread(new I(Member, arg)); +} + +template<typename T, typename T2, class V, class V2, class O> +void QQmlThread::postMethodToThread(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) +{ + struct I : public Message { + void (O::*Member)(V, V2); + T arg; + T2 arg2; + I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(arg, arg2); + } + }; + internalPostMethodToThread(new I(Member, arg, arg2)); +} + +template<class O> +void QQmlThread::postMethodToMain(void (O::*Member)()) +{ + struct I : public Message { + void (O::*Member)(); + I(void (O::*Member)()) : Member(Member) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(); + } + }; + internalPostMethodToMain(new I(Member)); +} + +template<typename T, class V, class O> +void QQmlThread::postMethodToMain(void (O::*Member)(V), const T &arg) +{ + struct I : public Message { + void (O::*Member)(V); + T arg; + I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(arg); + } + }; + internalPostMethodToMain(new I(Member, arg)); +} + +template<typename T, typename T2, class V, class V2, class O> +void QQmlThread::postMethodToMain(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) +{ + struct I : public Message { + void (O::*Member)(V, V2); + T arg; + T2 arg2; + I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(arg, arg2); + } + }; + internalPostMethodToMain(new I(Member, arg, arg2)); +} + +QT_END_NAMESPACE + +#endif // QQMLTHREAD_P_H diff --git a/src/qml/qml/ftw/qqmltrace.cpp b/src/qml/qml/ftw/qqmltrace.cpp new file mode 100644 index 0000000000..e044dc654f --- /dev/null +++ b/src/qml/qml/ftw/qqmltrace.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmltrace_p.h" + +#ifdef QML_ENABLE_TRACE +#include <stdio.h> +#endif + +QT_BEGIN_NAMESPACE + +#ifdef QML_ENABLE_TRACE + +QQmlTrace::Pool QQmlTrace::logPool; +QQmlTrace::Entry *QQmlTrace::first = 0; +QQmlTrace::Entry *QQmlTrace::last = 0; + +static qint64 toNsecs(QQmlTrace::TimeType time) +{ +#ifdef Q_OS_MAC + static mach_timebase_info_data_t info = {0,0}; + if (info.denom == 0) + mach_timebase_info(&info); + return time * info.numer / info.denom; +#else + qint64 rv = time.tv_sec * 1000000000 + time.tv_nsec; + return rv; +#endif +} + +QQmlTrace::Pool::Pool() +{ + first = New<Entry>(); + last = first; +} + +QQmlTrace::Pool::~Pool() +{ + char buffer[128]; + sprintf(buffer, "qml.%d.log", ::getpid()); + FILE *out = fopen(buffer, "w"); + if (!out) { + fprintf (stderr, "QML Log: Could not open %s\n", buffer); + return; + } else { + fprintf (stderr, "QML Log: Writing log to %s\n", buffer); + } + + QQmlTrace::Entry *cur = QQmlTrace::first; + QByteArray indent; + int depth = -1; + + qint64 firstTime = -1; + + while (cur) { + + switch (cur->type) { + case QQmlTrace::Entry::RangeStart: { + RangeStart *rs = static_cast<QQmlTrace::RangeStart *>(cur); + + qint64 nsecs = toNsecs(rs->time); + + if (firstTime == -1) + firstTime = nsecs; + + nsecs -= firstTime; + + depth++; + indent = QByteArray(depth * 4, ' '); + fprintf(out, "%s%s @%lld (%lld ns)\n", indent.constData(), + rs->description, nsecs, toNsecs(rs->end->time) - nsecs - firstTime); + } break; + case QQmlTrace::Entry::RangeEnd: + depth--; + indent = QByteArray(depth * 4, ' '); + break; + case QQmlTrace::Entry::Detail: + fprintf(out, "%s %s\n", indent.constData(), + static_cast<QQmlTrace::Detail *>(cur)->description); + break; + case QQmlTrace::Entry::IntDetail: + fprintf(out, "%s %s: %d\n", indent.constData(), + static_cast<QQmlTrace::Detail *>(cur)->description, + static_cast<QQmlTrace::IntDetail *>(cur)->value); + break; + case QQmlTrace::Entry::StringDetail: { + QByteArray vLatin1 = static_cast<QQmlTrace::StringDetail *>(cur)->value->toLatin1(); + fprintf(out, "%s %s: %s\n", indent.constData(), + static_cast<QQmlTrace::Detail *>(cur)->description, + vLatin1.constData()); + } break; + case QQmlTrace::Entry::UrlDetail: { + QByteArray vLatin1 = static_cast<QQmlTrace::UrlDetail *>(cur)->value->toString().toLatin1(); + fprintf(out, "%s %s: %s\n", indent.constData(), + static_cast<QQmlTrace::Detail *>(cur)->description, + vLatin1.constData()); + } break; + case QQmlTrace::Entry::Event: { + Event *ev = static_cast<QQmlTrace::Event *>(cur); + qint64 nsecs = toNsecs(ev->time) - firstTime; + fprintf(out, "%s + %s @%lld +%lld ns\n", indent.constData(), + ev->description, nsecs, nsecs - (toNsecs(ev->start->time) - firstTime)); + } break; + case QQmlTrace::Entry::Null: + default: + break; + } + cur = cur->next; + } + fclose(out); +} + +#endif + +QT_END_NAMESPACE + diff --git a/src/qml/qml/ftw/qqmltrace_p.h b/src/qml/qml/ftw/qqmltrace_p.h new file mode 100644 index 0000000000..965baff3a3 --- /dev/null +++ b/src/qml/qml/ftw/qqmltrace_p.h @@ -0,0 +1,294 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLTRACE_P_H +#define QQMLTRACE_P_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 <QtCore/qglobal.h> +#include <private/qqmlpool_p.h> + +// #define QML_ENABLE_TRACE + +#if defined(QML_ENABLE_TRACE) && defined(Q_OS_MAC) +#include <mach/mach_time.h> +#endif + +QT_BEGIN_NAMESPACE + +class QUrl; +class QQmlTrace +{ +public: + inline QQmlTrace(const char *desc); + inline ~QQmlTrace(); + + inline void addDetail(const char *); + inline void addDetail(const char *, int); + inline void addDetail(const char *, const QString &); + inline void addDetail(const char *, const QUrl &); + + inline void event(const char *desc); + +#ifdef QML_ENABLE_TRACE + +#ifdef Q_OS_MAC + typedef uint64_t TimeType; +#else + typedef timespec TimeType; +#endif + + struct Entry : public QQmlPool::POD { + enum Type { Null, RangeStart, RangeEnd, Detail, IntDetail, StringDetail, UrlDetail, Event }; + inline Entry(); + inline Entry(Type); + Type type; + Entry *next; + }; + struct RangeEnd : public Entry { + inline RangeEnd(); + TimeType time; + }; + struct RangeStart : public Entry { + inline RangeStart(); + const char *description; + TimeType time; + QQmlTrace::RangeEnd *end; + }; + struct Detail : public Entry { + inline Detail(); + inline Detail(Type t); + const char *description; + }; + struct IntDetail : public Detail { + inline IntDetail(); + int value; + }; + struct StringDetail : public Detail { + inline StringDetail(); + QString *value; + }; + struct UrlDetail : public Detail { + inline UrlDetail(); + QUrl *value; + }; + struct Event : public Entry { + inline Event(); + const char *description; + TimeType time; + QQmlTrace::RangeStart *start; + }; + + struct Pool : public QQmlPool { + Pool(); + ~Pool(); + }; + + static Pool logPool; + static Entry *first; + static Entry *last; + +private: + RangeStart *start; + + static TimeType gettime() { +#ifdef Q_OS_MAC + return mach_absolute_time(); +#else + TimeType ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts; +#endif + } +#endif +}; + +#ifdef QML_ENABLE_TRACE +QQmlTrace::Entry::Entry() +: type(Null), next(0) +{ +} + +QQmlTrace::Entry::Entry(Type type) +: type(type), next(0) +{ + QQmlTrace::last->next = this; + QQmlTrace::last = this; +} + +QQmlTrace::RangeEnd::RangeEnd() +: QQmlTrace::Entry(QQmlTrace::Entry::RangeEnd), + time(gettime()) +{ +} + +QQmlTrace::RangeStart::RangeStart() +: QQmlTrace::Entry(QQmlTrace::Entry::RangeStart), + description(0), time(gettime()) +{ +} + +QQmlTrace::Detail::Detail() +: QQmlTrace::Entry(QQmlTrace::Entry::Detail), + description(0) +{ +} + +QQmlTrace::Detail::Detail(Type type) +: QQmlTrace::Entry(type), description(0) +{ +} + +QQmlTrace::IntDetail::IntDetail() +: QQmlTrace::Detail(QQmlTrace::Entry::IntDetail), + value(0) +{ +} + +QQmlTrace::StringDetail::StringDetail() +: QQmlTrace::Detail(QQmlTrace::Entry::StringDetail), + value(0) +{ +} + +QQmlTrace::UrlDetail::UrlDetail() +: QQmlTrace::Detail(QQmlTrace::Entry::UrlDetail), + value(0) +{ +} + +QQmlTrace::Event::Event() +: QQmlTrace::Entry(QQmlTrace::Entry::Event), + description(0), time(gettime()), start(0) +{ +} +#endif + +QQmlTrace::QQmlTrace(const char *desc) +{ +#ifdef QML_ENABLE_TRACE + RangeStart *e = logPool.New<RangeStart>(); + e->description = desc; + e->end = 0; + start = e; +#else + Q_UNUSED(desc); +#endif +} + +QQmlTrace::~QQmlTrace() +{ +#ifdef QML_ENABLE_TRACE + RangeEnd *e = logPool.New<RangeEnd>(); + start->end = e; +#endif +} + +void QQmlTrace::addDetail(const char *desc) +{ +#ifdef QML_ENABLE_TRACE + Detail *e = logPool.New<Detail>(); + e->description = desc; +#else + Q_UNUSED(desc); +#endif +} + +void QQmlTrace::addDetail(const char *desc, int v) +{ +#ifdef QML_ENABLE_TRACE + IntDetail *e = logPool.New<IntDetail>(); + e->description = desc; + e->value = v; +#else + Q_UNUSED(desc); + Q_UNUSED(v); +#endif +} + +void QQmlTrace::addDetail(const char *desc, const QString &v) +{ +#ifdef QML_ENABLE_TRACE + StringDetail *e = logPool.New<StringDetail>(); + e->description = desc; + e->value = logPool.NewString(v); +#else + Q_UNUSED(desc); + Q_UNUSED(v); +#endif +} + +void QQmlTrace::addDetail(const char *desc, const QUrl &v) +{ +#ifdef QML_ENABLE_TRACE + UrlDetail *e = logPool.New<UrlDetail>(); + e->description = desc; + e->value = logPool.NewUrl(v); +#else + Q_UNUSED(desc); + Q_UNUSED(v); +#endif +} + +void QQmlTrace::event(const char *desc) +{ +#ifdef QML_ENABLE_TRACE + Event *e = logPool.New<Event>(); + e->start = start; + e->description = desc; +#else + Q_UNUSED(desc); +#endif +} + +QT_END_NAMESPACE + +#endif // QQMLTRACE_P_H diff --git a/src/qml/qml/ftw/qrecursionwatcher_p.h b/src/qml/qml/ftw/qrecursionwatcher_p.h new file mode 100644 index 0000000000..16886edf12 --- /dev/null +++ b/src/qml/qml/ftw/qrecursionwatcher_p.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRECURSIONWATCHER_P_H +#define QRECURSIONWATCHER_P_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 <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QRecursionNode; +class QRecursionNode { +public: + inline QRecursionNode(); + bool *_r; +}; + +template<class T, QRecursionNode T::*Node> +class QRecursionWatcher { +public: + inline QRecursionWatcher(T *); + inline ~QRecursionWatcher(); + inline bool hasRecursed() const; +private: + T *_t; + bool _r; +}; + +QRecursionNode::QRecursionNode() +: _r(0) +{ +} + +template<class T, QRecursionNode T::*Node> +QRecursionWatcher<T, Node>::QRecursionWatcher(T *t) +: _t(t), _r(false) +{ + if ((_t->*Node)._r) *(_t->*Node)._r = true; + (_t->*Node)._r = &_r; +} + +template<class T, QRecursionNode T::*Node> +QRecursionWatcher<T, Node>::~QRecursionWatcher() +{ + if ((_t->*Node)._r == &_r) (_t->*Node)._r = 0; +} + +template<class T, QRecursionNode T::*Node> +bool QRecursionWatcher<T, Node>::hasRecursed() const +{ + return _r; +} + +QT_END_NAMESPACE + +#endif // QRECURSIONWATCHER_P_H diff --git a/src/qml/qml/ftw/qrecyclepool_p.h b/src/qml/qml/ftw/qrecyclepool_p.h new file mode 100644 index 0000000000..8d0f060ab3 --- /dev/null +++ b/src/qml/qml/ftw/qrecyclepool_p.h @@ -0,0 +1,220 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRECYCLEPOOL_P_H +#define QRECYCLEPOOL_P_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. +// + +QT_BEGIN_NAMESPACE + +#define QRECYCLEPOOLCOOKIE 0x33218ADF + +template<typename T, int Step> +class QRecyclePoolPrivate +{ +public: + QRecyclePoolPrivate() + : recyclePoolHold(true), outstandingItems(0), cookie(QRECYCLEPOOLCOOKIE), + currentPage(0), nextAllocated(0) + { + } + + bool recyclePoolHold; + int outstandingItems; + quint32 cookie; + + struct PoolType : public T { + union { + QRecyclePoolPrivate<T, Step> *pool; + PoolType *nextAllocated; + }; + }; + + struct Page { + Page *nextPage; + unsigned int free; + union { + char array[Step * sizeof(PoolType)]; + qint64 q_for_alignment_1; + double q_for_alignment_2; + }; + }; + + Page *currentPage; + PoolType *nextAllocated; + + inline T *allocate(); + static inline void dispose(T *); + inline void releaseIfPossible(); +}; + +template<typename T, int Step = 1024> +class QRecyclePool +{ +public: + inline QRecyclePool(); + inline ~QRecyclePool(); + + inline T *New(); + template<typename T1> + inline T *New(const T1 &); + template<typename T1> + inline T *New(T1 &); + + static inline void Delete(T *); + +private: + QRecyclePoolPrivate<T, Step> *d; +}; + +template<typename T, int Step> +QRecyclePool<T, Step>::QRecyclePool() +: d(new QRecyclePoolPrivate<T, Step>()) +{ +} + +template<typename T, int Step> +QRecyclePool<T, Step>::~QRecyclePool() +{ + d->recyclePoolHold = false; + d->releaseIfPossible(); +} + +template<typename T, int Step> +T *QRecyclePool<T, Step>::New() +{ + T *rv = d->allocate(); + new (rv) T; + return rv; +} + +template<typename T, int Step> +template<typename T1> +T *QRecyclePool<T, Step>::New(const T1 &a) +{ + T *rv = d->allocate(); + new (rv) T(a); + return rv; +} + +template<typename T, int Step> +template<typename T1> +T *QRecyclePool<T, Step>::New(T1 &a) +{ + T *rv = d->allocate(); + new (rv) T(a); + return rv; +} + +template<typename T, int Step> +void QRecyclePool<T, Step>::Delete(T *t) +{ + t->~T(); + QRecyclePoolPrivate<T, Step>::dispose(t); +} + +template<typename T, int Step> +void QRecyclePoolPrivate<T, Step>::releaseIfPossible() +{ + if (recyclePoolHold || outstandingItems) + return; + + Page *p = currentPage; + while (p) { + Page *n = p->nextPage; + qFree(p); + p = n; + } + + delete this; +} + +template<typename T, int Step> +T *QRecyclePoolPrivate<T, Step>::allocate() +{ + PoolType *rv = 0; + if (nextAllocated) { + rv = nextAllocated; + nextAllocated = rv->nextAllocated; + } else if (currentPage && currentPage->free) { + rv = (PoolType *)(currentPage->array + (Step - currentPage->free) * sizeof(PoolType)); + currentPage->free--; + } else { + Page *p = (Page *)qMalloc(sizeof(Page)); + p->nextPage = currentPage; + p->free = Step; + currentPage = p; + + rv = (PoolType *)currentPage->array; + currentPage->free--; + } + + rv->pool = this; + ++outstandingItems; + return rv; +} + +template<typename T, int Step> +void QRecyclePoolPrivate<T, Step>::dispose(T *t) +{ + PoolType *pt = static_cast<PoolType *>(t); + Q_ASSERT(pt->pool && pt->pool->cookie == QRECYCLEPOOLCOOKIE); + + QRecyclePoolPrivate<T, Step> *This = pt->pool; + pt->nextAllocated = This->nextAllocated; + This->nextAllocated = pt; + --This->outstandingItems; + This->releaseIfPossible(); +} + +QT_END_NAMESPACE + +#endif // QRECYCLEPOOL_P_H |