aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/ftw
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/ftw')
-rw-r--r--src/qml/qml/ftw/ftw.pri29
-rw-r--r--src/qml/qml/ftw/qbitfield_p.h165
-rw-r--r--src/qml/qml/ftw/qdeletewatcher_p.h113
-rw-r--r--src/qml/qml/ftw/qfastmetabuilder.cpp369
-rw-r--r--src/qml/qml/ftw/qfastmetabuilder_p.h206
-rw-r--r--src/qml/qml/ftw/qfieldlist_p.h426
-rw-r--r--src/qml/qml/ftw/qfinitestack_p.h186
-rw-r--r--src/qml/qml/ftw/qflagpointer_p.h338
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp490
-rw-r--r--src/qml/qml/ftw/qhashedstring_p.h1418
-rw-r--r--src/qml/qml/ftw/qhashfield_p.h120
-rw-r--r--src/qml/qml/ftw/qintrusivelist.cpp179
-rw-r--r--src/qml/qml/ftw/qintrusivelist_p.h274
-rw-r--r--src/qml/qml/ftw/qlazilyallocated_p.h146
-rw-r--r--src/qml/qml/ftw/qpodvector_p.h173
-rw-r--r--src/qml/qml/ftw/qpointervaluepair_p.h196
-rw-r--r--src/qml/qml/ftw/qqmlpool.cpp92
-rw-r--r--src/qml/qml/ftw/qqmlpool_p.h278
-rw-r--r--src/qml/qml/ftw/qqmlrefcount_p.h192
-rw-r--r--src/qml/qml/ftw/qqmlthread.cpp359
-rw-r--r--src/qml/qml/ftw/qqmlthread_p.h318
-rw-r--r--src/qml/qml/ftw/qqmltrace.cpp154
-rw-r--r--src/qml/qml/ftw/qqmltrace_p.h294
-rw-r--r--src/qml/qml/ftw/qrecursionwatcher_p.h105
-rw-r--r--src/qml/qml/ftw/qrecyclepool_p.h220
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 &parameterNames,
+ 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 &parameterNames,
+ 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 &parameterNames = StringRef(),
+ const StringRef &type = StringRef());
+ void setSignal(int index, const StringRef &signature,
+ const StringRef &parameterNames = 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