summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMilian Wolff <milian.wolff@kdab.com>2013-12-19 16:46:40 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-12-27 15:50:36 +0100
commit25568c9d01e5ace5557c9aebc42d0de3cf2873e4 (patch)
treeab176384dee0c4c8e55dbe9d7e67190e883f597a /src
parent85fb9ea87356d28c2ba05fcb2b2018f6a0a91842 (diff)
downloadqtwebchannel-25568c9d01e5ace5557c9aebc42d0de3cf2873e4.tar.gz
Port MetaObjectPublisher benchmarks to C++.
This allows us to remove the public API for the tests and allows for more tests and benchmarks in the future. To achieve this, we re-use the new qmetaobjectpublisher_p.h, which then also must be exported. Change-Id: I3c33b2f5be6cc674cd3092667151dd8da2263cf5 Reviewed-by: Zeno Albisser <zeno.albisser@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/webchannel/qmetaobjectpublisher.cpp176
-rw-r--r--src/webchannel/qmetaobjectpublisher.h5
-rw-r--r--src/webchannel/qmetaobjectpublisher_p.h176
-rw-r--r--src/webchannel/signalhandler_p.h2
4 files changed, 195 insertions, 164 deletions
diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp
index fcf809a..375cf1b 100644
--- a/src/webchannel/qmetaobjectpublisher.cpp
+++ b/src/webchannel/qmetaobjectpublisher.cpp
@@ -41,20 +41,14 @@
****************************************************************************/
#include "qmetaobjectpublisher.h"
+#include "qmetaobjectpublisher_p.h"
#include "qwebchannel.h"
-#include "variantargument_p.h"
-#include "signalhandler_p.h"
-
-#include <QStringList>
-#include <QMetaObject>
-#include <QJsonObject>
-#include <QJsonArray>
-#include <QBasicTimer>
-#include <QDebug>
-#include <QPointer>
#include <QEvent>
#include <QJsonDocument>
+#include <QDebug>
+#include <QJsonObject>
+#include <QJsonArray>
namespace {
const QString KEY_SIGNALS = QStringLiteral("signals");
@@ -95,130 +89,15 @@ const int s_destroyedSignalIndex = QObject::staticMetaObject.indexOfMethod("dest
const int PROPERTY_UPDATE_INTERVAL = 50;
}
-struct QMetaObjectPublisherPrivate
+QMetaObjectPublisherPrivate::QMetaObjectPublisherPrivate(QMetaObjectPublisher *q)
+ : q(q)
+ , signalHandler(this)
+ , clientIsIdle(false)
+ , blockUpdates(false)
+ , pendingInit(false)
+ , propertyUpdatesInitialized(false)
{
- QMetaObjectPublisherPrivate(QMetaObjectPublisher *q)
- : q(q)
- , signalHandler(this)
- , clientIsIdle(false)
- , blockUpdates(false)
- , pendingInit(false)
- , propertyUpdatesInitialized(false)
- {
- }
-
- /**
- * Set the client to idle or busy, based on the value of @p isIdle.
- *
- * When the value changed, start/stop the property update timer accordingly.
- */
- void setClientIsIdle(bool isIdle);
-
- /**
- * Initialize clients by sending them the class information of the registered objects.
- *
- * Furthermore, if that was not done already, connect to their property notify signals.
- */
- void initializeClients();
-
- /**
- * Go through all properties of the given object and connect to their notify signal.
- *
- * When receiving a notify signal, it will store the information in pendingPropertyUpdates which
- * gets send via a Qt.propertyUpdate message to the server when the grouping timer timeouts.
- */
- void initializePropertyUpdates(const QObject *const object, const QVariantMap &objectInfo);
-
- /**
- * Send the clients the new property values since the last time this function was invoked.
- *
- * This is a grouped batch of all properties for which their notify signal was emitted.
- * The list of signals as well as the arguments they contained, are also transmitted to
- * the remote clients.
- *
- * @sa timer, initializePropertyUpdates
- */
- void sendPendingPropertyUpdates();
-
- /**
- * Invoke the method of index @p methodIndex on @p object with the arguments @p args.
- *
- * The return value of the method invocation is then transmitted to the calling client
- * via a webchannel response to the message identified by @p id.
- */
- bool invokeMethod(QObject *const object, const int methodIndex, const QJsonArray &args, const QJsonValue &id);
-
- /**
- * Callback of the signalHandler which forwards the signal invocation to the webchannel clients.
- */
- void signalEmitted(const QObject *object, const int signalIndex, const QVariantList &arguments);
-
- /**
- * Callback for registered or wrapped objects which erases all data related to @p object.
- *
- * @sa signalEmitted
- */
- void objectDestroyed(const QObject *object);
-
- /**
- * Given a QVariant containing a QObject*, wrap the object and register for property updates
- * return the objects class information.
- *
- * All other input types are returned as-is.
- *
- * TODO: support wrapping of initially-registered objects
- */
- QVariant wrapResult(const QVariant &result);
-
- /**
- * Invoke delete later on @p object.
- */
- void deleteWrappedObject(QObject *object) const;
-
- QMetaObjectPublisher *q;
- QPointer<QWebChannel> webChannel;
- SignalHandler<QMetaObjectPublisherPrivate> signalHandler;
-
- // true when the client is idle, false otherwise
- bool clientIsIdle;
-
- // true when no property updates should be sent, false otherwise
- bool blockUpdates;
-
- // true when at least one client needs to be initialized,
- // i.e. when a Qt.init came in which was not handled yet.
- bool pendingInit;
-
- // true when at least one client was initialized and thus
- // the property updates have been initialized and the
- // object info map set.
- bool propertyUpdatesInitialized;
-
- // Map of registered objects indexed by their id.
- QHash<QString, QObject *> registeredObjects;
-
- // Map the registered objects to their id.
- QHash<const QObject *, QString> registeredObjectIds;
-
- // Map of object names to maps of signal indices to a set of all their properties.
- // The last value is a set as a signal can be the notify signal of multiple properties.
- typedef QHash<int, QSet<QString> > SignalToPropertyNameMap;
- QHash<const QObject *, SignalToPropertyNameMap> signalToPropertyMap;
-
- // Objects that changed their properties and are waiting for idle client.
- // map of object name to map of signal index to arguments
- typedef QHash<int, QVariantList> SignalToArgumentsMap;
- typedef QHash<const QObject *, SignalToArgumentsMap> PendingPropertyUpdates;
- PendingPropertyUpdates pendingPropertyUpdates;
-
- // Maps wrapped object to class info
- QHash<const QObject *, QVariantMap> wrappedObjects;
-
- // Aggregate property updates since we get multiple Qt.idle message when we have multiple
- // clients. They all share the same QWebProcess though so we must take special care to
- // prevent message flooding.
- QBasicTimer timer;
-};
+}
void QMetaObjectPublisherPrivate::setClientIsIdle(bool isIdle)
{
@@ -235,6 +114,10 @@ void QMetaObjectPublisherPrivate::setClientIsIdle(bool isIdle)
void QMetaObjectPublisherPrivate::initializeClients()
{
+ if (!webChannel) {
+ return;
+ }
+
QJsonObject objectInfos;
{
const QHash<QString, QObject *>::const_iterator end = registeredObjects.constEnd();
@@ -700,33 +583,6 @@ void QMetaObjectPublisher::setBlockUpdates(bool block)
emit blockUpdatesChanged(block);
}
-void QMetaObjectPublisher::bench_ensureUpdatesInitialized()
-{
- if (!d->propertyUpdatesInitialized) {
- d->initializeClients();
- }
-}
-
-void QMetaObjectPublisher::bench_sendPendingPropertyUpdates()
-{
- d->clientIsIdle = true;
- d->sendPendingPropertyUpdates();
-}
-
-void QMetaObjectPublisher::bench_initializeClients()
-{
- d->propertyUpdatesInitialized = false;
- d->signalToPropertyMap.clear();
- d->signalHandler.clear();
- d->initializeClients();
-}
-
-void QMetaObjectPublisher::bench_registerObjects(const QVariantMap &objects)
-{
- d->propertyUpdatesInitialized = false;
- registerObjects(objects);
-}
-
bool QMetaObjectPublisher::test_clientIsIdle() const
{
return d->clientIsIdle;
diff --git a/src/webchannel/qmetaobjectpublisher.h b/src/webchannel/qmetaobjectpublisher.h
index 684be1d..f4763a7 100644
--- a/src/webchannel/qmetaobjectpublisher.h
+++ b/src/webchannel/qmetaobjectpublisher.h
@@ -93,10 +93,6 @@ public:
void setBlockUpdates(bool block);
/// TODO: cleanup: rewrite tests in C++ and access PIMPL data from there
- Q_INVOKABLE void bench_ensureUpdatesInitialized();
- Q_INVOKABLE void bench_sendPendingPropertyUpdates();
- Q_INVOKABLE void bench_registerObjects(const QVariantMap &objects);
- Q_INVOKABLE void bench_initializeClients();
Q_INVOKABLE bool test_clientIsIdle() const;
signals:
@@ -118,6 +114,7 @@ protected:
private:
QScopedPointer<QMetaObjectPublisherPrivate> d;
friend struct QMetaObjectPublisherPrivate;
+ friend class TestWebChannel;
};
#endif // QMETAOBJECTPUBLISHER_H
diff --git a/src/webchannel/qmetaobjectpublisher_p.h b/src/webchannel/qmetaobjectpublisher_p.h
new file mode 100644
index 0000000..e364510
--- /dev/null
+++ b/src/webchannel/qmetaobjectpublisher_p.h
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2013 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
+** Contact: http://www.qt-project.org/legal
+*
+** This file is part of the QtWebChannel module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMETAOBJECTPUBLISHER_P_H
+#define QMETAOBJECTPUBLISHER_P_H
+
+#include "variantargument_p.h"
+#include "signalhandler_p.h"
+
+#include <QStringList>
+#include <QMetaObject>
+#include <QBasicTimer>
+#include <QPointer>
+
+class QMetaObjectPublisher;
+class QWebChannel;
+
+#include "qwebchannelglobal.h"
+
+struct Q_WEBCHANNEL_EXPORT QMetaObjectPublisherPrivate
+{
+ QMetaObjectPublisherPrivate(QMetaObjectPublisher *q);
+
+ /**
+ * Set the client to idle or busy, based on the value of @p isIdle.
+ *
+ * When the value changed, start/stop the property update timer accordingly.
+ */
+ void setClientIsIdle(bool isIdle);
+
+ /**
+ * Initialize clients by sending them the class information of the registered objects.
+ *
+ * Furthermore, if that was not done already, connect to their property notify signals.
+ */
+ void initializeClients();
+
+ /**
+ * Go through all properties of the given object and connect to their notify signal.
+ *
+ * When receiving a notify signal, it will store the information in pendingPropertyUpdates which
+ * gets send via a Qt.propertyUpdate message to the server when the grouping timer timeouts.
+ */
+ void initializePropertyUpdates(const QObject *const object, const QVariantMap &objectInfo);
+
+ /**
+ * Send the clients the new property values since the last time this function was invoked.
+ *
+ * This is a grouped batch of all properties for which their notify signal was emitted.
+ * The list of signals as well as the arguments they contained, are also transmitted to
+ * the remote clients.
+ *
+ * @sa timer, initializePropertyUpdates
+ */
+ void sendPendingPropertyUpdates();
+
+ /**
+ * Invoke the method of index @p methodIndex on @p object with the arguments @p args.
+ *
+ * The return value of the method invocation is then transmitted to the calling client
+ * via a webchannel response to the message identified by @p id.
+ */
+ bool invokeMethod(QObject *const object, const int methodIndex, const QJsonArray &args, const QJsonValue &id);
+
+ /**
+ * Callback of the signalHandler which forwards the signal invocation to the webchannel clients.
+ */
+ void signalEmitted(const QObject *object, const int signalIndex, const QVariantList &arguments);
+
+ /**
+ * Callback for registered or wrapped objects which erases all data related to @p object.
+ *
+ * @sa signalEmitted
+ */
+ void objectDestroyed(const QObject *object);
+
+ /**
+ * Given a QVariant containing a QObject*, wrap the object and register for property updates
+ * return the objects class information.
+ *
+ * All other input types are returned as-is.
+ *
+ * TODO: support wrapping of initially-registered objects
+ */
+ QVariant wrapResult(const QVariant &result);
+
+ /**
+ * Invoke delete later on @p object.
+ */
+ void deleteWrappedObject(QObject *object) const;
+
+ QMetaObjectPublisher *q;
+ QPointer<QWebChannel> webChannel;
+ SignalHandler<QMetaObjectPublisherPrivate> signalHandler;
+
+ // true when the client is idle, false otherwise
+ bool clientIsIdle;
+
+ // true when no property updates should be sent, false otherwise
+ bool blockUpdates;
+
+ // true when at least one client needs to be initialized,
+ // i.e. when a Qt.init came in which was not handled yet.
+ bool pendingInit;
+
+ // true when at least one client was initialized and thus
+ // the property updates have been initialized and the
+ // object info map set.
+ bool propertyUpdatesInitialized;
+
+ // Map of registered objects indexed by their id.
+ QHash<QString, QObject *> registeredObjects;
+
+ // Map the registered objects to their id.
+ QHash<const QObject *, QString> registeredObjectIds;
+
+ // Map of object names to maps of signal indices to a set of all their properties.
+ // The last value is a set as a signal can be the notify signal of multiple properties.
+ typedef QHash<int, QSet<QString> > SignalToPropertyNameMap;
+ QHash<const QObject *, SignalToPropertyNameMap> signalToPropertyMap;
+
+ // Objects that changed their properties and are waiting for idle client.
+ // map of object name to map of signal index to arguments
+ typedef QHash<int, QVariantList> SignalToArgumentsMap;
+ typedef QHash<const QObject *, SignalToArgumentsMap> PendingPropertyUpdates;
+ PendingPropertyUpdates pendingPropertyUpdates;
+
+ // Maps wrapped object to class info
+ QHash<const QObject *, QVariantMap> wrappedObjects;
+
+ // Aggregate property updates since we get multiple Qt.idle message when we have multiple
+ // clients. They all share the same QWebProcess though so we must take special care to
+ // prevent message flooding.
+ QBasicTimer timer;
+};
+
+#endif // QMETAOBJECTPUBLISHER_P_H
diff --git a/src/webchannel/signalhandler_p.h b/src/webchannel/signalhandler_p.h
index 2613f92..5bc1f4d 100644
--- a/src/webchannel/signalhandler_p.h
+++ b/src/webchannel/signalhandler_p.h
@@ -272,7 +272,9 @@ void SignalHandler<Receiver>::clear()
}
}
m_connectionsCounter.clear();
+ const SignalArgumentHash keep = m_signalArgumentTypes.take(&QObject::staticMetaObject);
m_signalArgumentTypes.clear();
+ m_signalArgumentTypes[&QObject::staticMetaObject] = keep;
}
#endif // SIGNALHANDLER_H