diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2011-09-05 17:31:41 +1000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2011-09-29 06:12:49 +0200 |
commit | 703c808a5649169dd6b9605af273374cd62951d1 (patch) | |
tree | 7248cc72bfa632a51c814d6622f0b12a7f2bd443 /src/declarative/qml/ftw | |
parent | 600e56ad053362dd5d4150f5dec6b93c2fee575b (diff) |
Asynchronous component instantiation
This introduces two main:
* the QML compiler executes in a separate thread
* item instantiation can be interrupted and resumed to
allow it to be split across multiple frames.
Task-number: QTBUG-21151
Change-Id: I9631c62bb77da3a2e0c37f0da3719533fdce4fef
Reviewed-on: http://codereview.qt-project.org/5676
Reviewed-by: Martin Jones <martin.jones@nokia.com>
Diffstat (limited to 'src/declarative/qml/ftw')
-rw-r--r-- | src/declarative/qml/ftw/ftw.pri | 4 | ||||
-rw-r--r-- | src/declarative/qml/ftw/qdeclarativerefcount.cpp | 70 | ||||
-rw-r--r-- | src/declarative/qml/ftw/qdeclarativerefcount_p.h | 58 | ||||
-rw-r--r-- | src/declarative/qml/ftw/qdeclarativethread.cpp | 359 | ||||
-rw-r--r-- | src/declarative/qml/ftw/qdeclarativethread_p.h | 318 | ||||
-rw-r--r-- | src/declarative/qml/ftw/qfieldlist_p.h | 29 | ||||
-rw-r--r-- | src/declarative/qml/ftw/qfinitestack_p.h | 186 |
7 files changed, 947 insertions, 77 deletions
diff --git a/src/declarative/qml/ftw/ftw.pri b/src/declarative/qml/ftw/ftw.pri index d6e7df53b2..2d6729bd79 100644 --- a/src/declarative/qml/ftw/ftw.pri +++ b/src/declarative/qml/ftw/ftw.pri @@ -11,12 +11,14 @@ HEADERS += \ $$PWD/qfieldlist_p.h \ $$PWD/qfastmetabuilder_p.h \ $$PWD/qhashfield_p.h \ + $$PWD/qdeclarativethread_p.h \ + $$PWD/qfinitestack_p.h \ SOURCES += \ $$PWD/qintrusivelist.cpp \ $$PWD/qmetaobjectbuilder.cpp \ $$PWD/qhashedstring.cpp \ - $$PWD/qdeclarativerefcount.cpp \ $$PWD/qdeclarativepool.cpp \ $$PWD/qfastmetabuilder.cpp \ + $$PWD/qdeclarativethread.cpp \ diff --git a/src/declarative/qml/ftw/qdeclarativerefcount.cpp b/src/declarative/qml/ftw/qdeclarativerefcount.cpp deleted file mode 100644 index a17d5b7142..0000000000 --- a/src/declarative/qml/ftw/qdeclarativerefcount.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative 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 "private/qdeclarativerefcount_p.h" - -QT_BEGIN_NAMESPACE - -QDeclarativeRefCount::QDeclarativeRefCount() -: refCount(1) -{ -} - -QDeclarativeRefCount::~QDeclarativeRefCount() -{ -} - -void QDeclarativeRefCount::addref() -{ - Q_ASSERT(refCount > 0); - ++refCount; -} - -void QDeclarativeRefCount::release() -{ - Q_ASSERT(refCount > 0); - --refCount; - if (refCount == 0) - delete this; -} - -QT_END_NAMESPACE - diff --git a/src/declarative/qml/ftw/qdeclarativerefcount_p.h b/src/declarative/qml/ftw/qdeclarativerefcount_p.h index 381327098c..8ae9618f30 100644 --- a/src/declarative/qml/ftw/qdeclarativerefcount_p.h +++ b/src/declarative/qml/ftw/qdeclarativerefcount_p.h @@ -54,6 +54,7 @@ // #include <QtCore/qglobal.h> +#include <QtCore/qatomic.h> QT_BEGIN_HEADER @@ -61,16 +62,19 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class Q_DECLARATIVE_EXPORT QDeclarativeRefCount +class QDeclarativeRefCount { public: - QDeclarativeRefCount(); - virtual ~QDeclarativeRefCount(); - void addref(); - void release(); + inline QDeclarativeRefCount(); + inline virtual ~QDeclarativeRefCount(); + inline void addref(); + inline void release(); + +protected: + inline virtual void destroy(); private: - int refCount; + QAtomicInt refCount; }; template<class T> @@ -92,10 +96,40 @@ public: inline operator T*() const { return o; } inline T* data() const { return o; } + inline QDeclarativeRefPointer<T> &take(T *); + private: T *o; }; +QDeclarativeRefCount::QDeclarativeRefCount() +: refCount(1) +{ +} + +QDeclarativeRefCount::~QDeclarativeRefCount() +{ + Q_ASSERT(refCount == 0); +} + +void QDeclarativeRefCount::addref() +{ + Q_ASSERT(refCount > 0); + refCount.ref(); +} + +void QDeclarativeRefCount::release() +{ + Q_ASSERT(refCount > 0); + if (!refCount.deref()) + destroy(); +} + +void QDeclarativeRefCount::destroy() +{ + delete this; +} + template<class T> QDeclarativeRefPointer<T>::QDeclarativeRefPointer() : o(0) @@ -140,6 +174,18 @@ QDeclarativeRefPointer<T> &QDeclarativeRefPointer<T>::operator=(T *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> +QDeclarativeRefPointer<T> &QDeclarativeRefPointer<T>::take(T *other) +{ + if (o) o->release(); + o = other; + return *this; +} + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/declarative/qml/ftw/qdeclarativethread.cpp b/src/declarative/qml/ftw/qdeclarativethread.cpp new file mode 100644 index 0000000000..4a21c90bf1 --- /dev/null +++ b/src/declarative/qml/ftw/qdeclarativethread.cpp @@ -0,0 +1,359 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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 "qdeclarativethread_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 QDeclarativeThreadPrivate : public QThread +{ +public: + QDeclarativeThreadPrivate(QDeclarativeThread *); + QDeclarativeThread *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<QDeclarativeThread::Message, &QDeclarativeThread::Message::next> MessageList; + MessageList threadList; + MessageList mainList; + + QDeclarativeThread::Message *mainSync; + + void triggerMainEvent(); + void triggerThreadEvent(); + + void mainEvent(); + void threadEvent(); + +protected: + virtual bool event(QEvent *); + +private: + struct MainObject : public QObject { + MainObject(QDeclarativeThreadPrivate *p); + virtual bool event(QEvent *e); + QDeclarativeThreadPrivate *p; + }; + MainObject m_mainObject; + + QMutex _mutex; + QWaitCondition _wait; +}; + +QDeclarativeThreadPrivate::MainObject::MainObject(QDeclarativeThreadPrivate *p) +: p(p) +{ +} + +// Trigger mainEvent in main thread. Must be called from thread. +void QDeclarativeThreadPrivate::triggerMainEvent() +{ + Q_ASSERT(q->isThisThread()); + QCoreApplication::postEvent(&m_mainObject, new QEvent(QEvent::User)); +} + +// Trigger even in thread. Must be called from main thread. +void QDeclarativeThreadPrivate::triggerThreadEvent() +{ + Q_ASSERT(!q->isThisThread()); + QCoreApplication::postEvent(this, new QEvent(QEvent::User)); +} + +bool QDeclarativeThreadPrivate::MainObject::event(QEvent *e) +{ + if (e->type() == QEvent::User) + p->mainEvent(); + return QObject::event(e); +} + +QDeclarativeThreadPrivate::QDeclarativeThreadPrivate(QDeclarativeThread *q) +: q(q), m_threadProcessing(false), m_mainProcessing(false), m_shutdown(false), + m_mainThreadWaiting(false), mainSync(0), m_mainObject(this) +{ +} + +bool QDeclarativeThreadPrivate::event(QEvent *e) +{ + if (e->type() == QEvent::User) + threadEvent(); + return QThread::event(e); +} + +void QDeclarativeThreadPrivate::run() +{ + lock(); + + wakeOne(); + + unlock(); + + q->startupThread(); + exec(); +} + +void QDeclarativeThreadPrivate::mainEvent() +{ + lock(); + + m_mainProcessing = true; + + while (!mainList.isEmpty() || mainSync) { + bool isSync = mainSync != 0; + QDeclarativeThread::Message *message = isSync?mainSync:mainList.takeFirst(); + unlock(); + + message->call(q); + delete message; + + lock(); + + if (isSync) { + mainSync = 0; + wakeOne(); + } + } + + m_mainProcessing = false; + + unlock(); +} + +void QDeclarativeThreadPrivate::threadEvent() +{ + lock(); + + if (m_shutdown) { + quit(); + wakeOne(); + unlock(); + q->shutdownThread(); + } else { + m_threadProcessing = true; + + while (!threadList.isEmpty()) { + QDeclarativeThread::Message *message = threadList.first(); + + unlock(); + + message->call(q); + + lock(); + + delete threadList.takeFirst(); + } + + wakeOne(); + + m_threadProcessing = false; + + unlock(); + } +} + +QDeclarativeThread::QDeclarativeThread() +: d(new QDeclarativeThreadPrivate(this)) +{ + d->lock(); + d->start(); + d->wait(); + d->unlock(); + d->moveToThread(d); + +} + +QDeclarativeThread::~QDeclarativeThread() +{ + delete d; +} + +void QDeclarativeThread::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 QDeclarativeThread::lock() +{ + d->lock(); +} + +void QDeclarativeThread::unlock() +{ + d->unlock(); +} + +void QDeclarativeThread::wakeOne() +{ + d->wakeOne(); +} + +void QDeclarativeThread::wakeAll() +{ + d->wakeAll(); +} + +void QDeclarativeThread::wait() +{ + d->wait(); +} + +bool QDeclarativeThread::isThisThread() const +{ + return QThread::currentThread() == d; +} + +QThread *QDeclarativeThread::thread() const +{ + return const_cast<QThread *>(static_cast<const QThread *>(d)); +} + +// Called when the thread starts. Do startup stuff in here. +void QDeclarativeThread::startupThread() +{ +} + +// Called when the thread shuts down. Do cleanup in here. +void QDeclarativeThread::shutdownThread() +{ +} + +void QDeclarativeThread::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) { + QDeclarativeThread::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 QDeclarativeThread::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 QDeclarativeThread::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 QDeclarativeThread::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/declarative/qml/ftw/qdeclarativethread_p.h b/src/declarative/qml/ftw/qdeclarativethread_p.h new file mode 100644 index 0000000000..2f5815568e --- /dev/null +++ b/src/declarative/qml/ftw/qdeclarativethread_p.h @@ -0,0 +1,318 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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 QDECLARATIVETHREAD_P_H +#define QDECLARATIVETHREAD_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 QDeclarativeThreadPrivate; +class QDeclarativeThread +{ +public: + QDeclarativeThread(); + virtual ~QDeclarativeThread(); + 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 QDeclarativeThreadPrivate; + + struct Message { + Message() : next(0) {} + virtual ~Message() {} + Message *next; + virtual void call(QDeclarativeThread *) = 0; + }; + void internalCallMethodInThread(Message *); + void internalCallMethodInMain(Message *); + void internalPostMethodToThread(Message *); + void internalPostMethodToMain(Message *); + QDeclarativeThreadPrivate *d; +}; + +template<class O> +void QDeclarativeThread::callMethodInThread(void (O::*Member)()) +{ + struct I : public Message { + void (O::*Member)(); + I(void (O::*Member)()) : Member(Member) {} + virtual void call(QDeclarativeThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(); + } + }; + internalCallMethodInThread(new I(Member)); +} + +template<typename T, class V, class O> +void QDeclarativeThread::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(QDeclarativeThread *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 QDeclarativeThread::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(QDeclarativeThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(arg, arg2); + } + }; + internalCallMethodInThread(new I(Member, arg, arg2)); +} + +template<class O> +void QDeclarativeThread::callMethodInMain(void (O::*Member)()) +{ + struct I : public Message { + void (O::*Member)(); + I(void (O::*Member)()) : Member(Member) {} + virtual void call(QDeclarativeThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(); + } + }; + internalCallMethodInMain(new I(Member)); +} + +template<typename T, class V, class O> +void QDeclarativeThread::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(QDeclarativeThread *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 QDeclarativeThread::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(QDeclarativeThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(arg, arg2); + } + }; + internalCallMethodInMain(new I(Member, arg, arg2)); +} + +template<class O> +void QDeclarativeThread::postMethodToThread(void (O::*Member)()) +{ + struct I : public Message { + void (O::*Member)(); + I(void (O::*Member)()) : Member(Member) {} + virtual void call(QDeclarativeThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(); + } + }; + internalPostMethodToThread(new I(Member)); +} + +template<typename T, class V, class O> +void QDeclarativeThread::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(QDeclarativeThread *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 QDeclarativeThread::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(QDeclarativeThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(arg, arg2); + } + }; + internalPostMethodToThread(new I(Member, arg, arg2)); +} + +template<class O> +void QDeclarativeThread::postMethodToMain(void (O::*Member)()) +{ + struct I : public Message { + void (O::*Member)(); + I(void (O::*Member)()) : Member(Member) {} + virtual void call(QDeclarativeThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(); + } + }; + internalPostMethodToMain(new I(Member)); +} + +template<typename T, class V, class O> +void QDeclarativeThread::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(QDeclarativeThread *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 QDeclarativeThread::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(QDeclarativeThread *thread) { + O *me = static_cast<O *>(thread); + (me->*Member)(arg, arg2); + } + }; + internalPostMethodToMain(new I(Member, arg, arg2)); +} + +QT_END_NAMESPACE + +#endif // QDECLARATIVETHREAD_P_H diff --git a/src/declarative/qml/ftw/qfieldlist_p.h b/src/declarative/qml/ftw/qfieldlist_p.h index ff6b89b96f..f0efd16a20 100644 --- a/src/declarative/qml/ftw/qfieldlist_p.h +++ b/src/declarative/qml/ftw/qfieldlist_p.h @@ -61,6 +61,8 @@ class QFieldList public: inline QFieldList(); inline N *first() const; + inline N *takeFirst(); + inline void append(N *); inline void prepend(N *); @@ -73,6 +75,8 @@ public: inline void prepend(QFieldList<N, nextMember> &); inline void insertAfter(N *, QFieldList<N, nextMember> &); + inline void copyAndClear(QFieldList<N, nextMember> &); + static inline N *next(N *v); private: @@ -94,6 +98,21 @@ N *QFieldList<N, nextMember>::first() const } 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; + } + --_count; + } + return value; +} + +template<class N, N *N::*nextMember> void QFieldList<N, nextMember>::append(N *v) { Q_ASSERT(v->*nextMember == 0); @@ -207,4 +226,14 @@ void QFieldList<N, nextMember>::insertAfter(N *after, QFieldList<N, nextMember> } } +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; +} + #endif // QFIELDLIST_P_H diff --git a/src/declarative/qml/ftw/qfinitestack_p.h b/src/declarative/qml/ftw/qfinitestack_p.h new file mode 100644 index 0000000000..de9d833762 --- /dev/null +++ b/src/declarative/qml/ftw/qfinitestack_p.h @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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 + |