summaryrefslogtreecommitdiffstats
path: root/src/dbus
diff options
context:
space:
mode:
authorMarc Mutz <marc.mutz@kdab.com>2016-09-01 20:37:12 +0200
committerMarc Mutz <marc.mutz@kdab.com>2019-06-21 09:18:13 +0200
commit08103d3a527d32c782ba9e3f6701e6676ac81a57 (patch)
treedd8baf691bd62e2c19dd31c6bc887228046fe12a /src/dbus
parent6bcfe0453597c81573bbfb838b5ec087d74f07de (diff)
QDBusAbstractInterface: make call() and asyncCall() variadic templates
... and use a variant of the QString::multiArg() trick to pass the variable number of arguments into an out-of-line function. The idea of this patch is to make the lowly asyncCall() and call() functions the principal interface for DBus calls again. Currently, it is more efficient to build up a QList<QVariant> and pass that to the *WithArgumentList() methods. With more efficient, I mean that the equivalent calls with QList expand to less client code, probably because of the need to construct eight QVariant instances, destroy them again, and then take the hit for a function call with so many arguments, which can all but be efficient. Consequently, when porting the NM bearer plugin to use call() instead of callWithArgumentList(), text size increased by ~3KiB on my machine. So, looking for a way to avoid the overhead of so many default arguments, while at the same time allowing to pass even more arguments than the predefined eight, I considered the QString::arg() method, but discarded it because it does not scale to arbitrarily (ie. SEP-limited) many arguments. Variadic templates scale to SEP-limited many arguments, but they are templates and deduce the exact type, so constraining the template to only QVariants would have broken all users of the API which pass non-QVariants and expect an implicit con- version to resolve the call. So I decided to make a virtue of necessity, accept all argument types and convert them to QVariant when constructing the QString::multiArg()-inspired QVariant array. To bring this patch to its consequential end would require to pass the arguments as arrays instead of QLists, but to get a feeling of how much impact this new API has, I backed the new implementation by converting the array to a QList and calling the *WithArgumentList() methods. The result is, if I may say so, satisfying. Said bearer plugin drops from +3KiB (baseline: callWithArgumentList()) to -5KiB (2.0% and 3.2%, resp.); the (unmodified) connman bearer plugin, which already used call(), dropped by almost 6KiB (2.5%). While GCC can deal with the zero-sized array in a nullary call to the variadic templates, MSVC cannot, so an extra overload provides an alternative for zero arguments. [ChangeLog][QtDBus][QDBusAbstractInterface] The call() and asyncCall() methods now accept more than eight QVariant arguments. Change-Id: Ic85faca40949f9bb8c08756be3bfe945c9cdd952 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/dbus')
-rw-r--r--src/dbus/qdbusabstractinterface.cpp111
-rw-r--r--src/dbus/qdbusabstractinterface.h94
2 files changed, 158 insertions, 47 deletions
diff --git a/src/dbus/qdbusabstractinterface.cpp b/src/dbus/qdbusabstractinterface.cpp
index 220223d74d..8b62d0ac87 100644
--- a/src/dbus/qdbusabstractinterface.cpp
+++ b/src/dbus/qdbusabstractinterface.cpp
@@ -691,18 +691,20 @@ void QDBusAbstractInterface::internalPropSet(const char *propname, const QVarian
}
/*!
- Calls the method \a method on this interface and passes the parameters to this function to the
- method.
+ \fn QDBusAbstractInterface::call(const QString &message)
+ \internal
+*/
+
+/*!
+ \fn QDBusAbstractInterface::call(const QString &message, Args&&...args)
+
+ Calls the method \a method on this interface and passes \a args to the method.
+ All \a args must be convertible to QVariant.
The parameters to \c call are passed on to the remote function via D-Bus as input
arguments. Output arguments are returned in the QDBusMessage reply. If the reply is an error
reply, lastError() will also be set to the contents of the error message.
- This function can be used with up to 8 parameters, passed in arguments \a arg1, \a arg2,
- \a arg3, \a arg4, \a arg5, \a arg6, \a arg7 and \a arg8. If you need more than 8
- parameters or if you have a variable number of parameters to be passed, use
- callWithArgumentList().
-
It can be used the following way:
\snippet code/src_qdbus_qdbusabstractinterface.cpp 0
@@ -710,6 +712,19 @@ void QDBusAbstractInterface::internalPropSet(const char *propname, const QVarian
This example illustrates function calling with 0, 1 and 2 parameters and illustrates different
parameter types passed in each (the first call to \c "ProcessWorkUnicode" will contain one
Unicode string, the second call to \c "ProcessWork" will contain one string and one byte array).
+
+ \note Before Qt 5.14, this function accepted a maximum of just eight (8) arguments.
+
+ \sa callWithArgumentList()
+*/
+
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+/*!
+ \internal
+
+ This function exists for binary compatibility with Qt versions < 5.14.
+ Programs recompiled against Qt 5.14 will use the variadic template function
+ instead.
*/
QDBusMessage QDBusAbstractInterface::call(const QString &method, const QVariant &arg1,
const QVariant &arg2,
@@ -722,27 +737,44 @@ QDBusMessage QDBusAbstractInterface::call(const QString &method, const QVariant
{
return call(QDBus::AutoDetect, method, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
}
+#endif
+
+/*!
+ \fn QDBusAbstractInterface::call(QDBus::CallMode mode, const QString &message)
+ \internal
+*/
/*!
+ \fn QDBusAbstractInterface::call(QDBus::CallMode mode, const QString &message, Args&&...args)
+
\overload
- Calls the method \a method on this interface and passes the
- parameters to this function to the method. If \a mode is \c
- NoWaitForReply, then this function will return immediately after
+ Calls the method \a method on this interface and passes \a args to the method.
+ All \a args must be convertible to QVariant.
+
+ If \a mode is \c NoWaitForReply, then this function will return immediately after
placing the call, without waiting for a reply from the remote
method. Otherwise, \a mode indicates whether this function should
activate the Qt Event Loop while waiting for the reply to arrive.
- This function can be used with up to 8 parameters, passed in arguments \a arg1, \a arg2,
- \a arg3, \a arg4, \a arg5, \a arg6, \a arg7 and \a arg8. If you need more than 8
- parameters or if you have a variable number of parameters to be passed, use
- callWithArgumentList().
-
If this function reenters the Qt event loop in order to wait for the
reply, it will exclude user input. During the wait, it may deliver
signals and other method calls to your application. Therefore, it
must be prepared to handle a reentrancy whenever a call is placed
with call().
+
+ \note Before Qt 5.14, this function accepted a maximum of just eight (8) arguments.
+
+ \sa callWithArgumentList()
+*/
+
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+/*!
+ \internal
+
+ This function exists for binary compatibility with Qt versions < 5.14.
+ Programs recompiled against Qt 5.14 will use the variadic template function
+ instead.
*/
QDBusMessage QDBusAbstractInterface::call(QDBus::CallMode mode, const QString &method,
const QVariant &arg1,
@@ -787,22 +819,23 @@ QDBusMessage QDBusAbstractInterface::call(QDBus::CallMode mode, const QString &m
return callWithArgumentList(mode, method, argList);
}
+#endif // Qt 5
+/*!
+ \fn QDBusAbstractInterface::asyncCall(const QString &message)
+ \internal
+*/
/*!
- \since 4.5
- Calls the method \a method on this interface and passes the parameters to this function to the
- method.
+ \fn QDBusAbstractInterface::asyncCall(const QString &message, Args&&...args)
+
+ Calls the method \a method on this interface and passes \a args to the method.
+ All \a args must be convertible to QVariant.
The parameters to \c call are passed on to the remote function via D-Bus as input
arguments. The returned QDBusPendingCall object can be used to find out information about
the reply.
- This function can be used with up to 8 parameters, passed in arguments \a arg1, \a arg2,
- \a arg3, \a arg4, \a arg5, \a arg6, \a arg7 and \a arg8. If you need more than 8
- parameters or if you have a variable number of parameters to be passed, use
- asyncCallWithArgumentList().
-
It can be used the following way:
\snippet code/src_qdbus_qdbusabstractinterface.cpp 1
@@ -810,6 +843,19 @@ QDBusMessage QDBusAbstractInterface::call(QDBus::CallMode mode, const QString &m
This example illustrates function calling with 0, 1 and 2 parameters and illustrates different
parameter types passed in each (the first call to \c "ProcessWorkUnicode" will contain one
Unicode string, the second call to \c "ProcessWork" will contain one string and one byte array).
+
+ \note Before Qt 5.14, this function accepted a maximum of just eight (8) arguments.
+
+ \sa asyncCallWithArgumentList()
+*/
+
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+/*!
+ \internal
+
+ This function exists for binary compatibility with Qt versions < 5.14.
+ Programs recompiled against Qt 5.14 will use the variadic template function
+ instead.
*/
QDBusPendingCall QDBusAbstractInterface::asyncCall(const QString &method, const QVariant &arg1,
const QVariant &arg2,
@@ -853,6 +899,7 @@ QDBusPendingCall QDBusAbstractInterface::asyncCall(const QString &method, const
return asyncCallWithArgumentList(method, argList);
}
+#endif // Qt 5
/*!
\internal
@@ -865,6 +912,24 @@ QDBusMessage QDBusAbstractInterface::internalConstCall(QDBus::CallMode mode,
return const_cast<QDBusAbstractInterface*>(this)->callWithArgumentList(mode, method, args);
}
+QDBusMessage QDBusAbstractInterface::doCall(QDBus::CallMode mode, const QString &method, const QVariant *args, size_t numArgs)
+{
+ QList<QVariant> list;
+ list.reserve(int(numArgs));
+ for (size_t i = 0; i < numArgs; ++i)
+ list.append(args[i]);
+ return callWithArgumentList(mode, method, list);
+}
+
+QDBusPendingCall QDBusAbstractInterface::doAsyncCall(const QString &method, const QVariant *args, size_t numArgs)
+{
+ QList<QVariant> list;
+ list.reserve(int(numArgs));
+ for (size_t i = 0; i < numArgs; ++i)
+ list.append(args[i]);
+ return asyncCallWithArgumentList(method, list);
+}
+
QT_END_NAMESPACE
#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusabstractinterface.h b/src/dbus/qdbusabstractinterface.h
index d6b0870787..4f4c7430a5 100644
--- a/src/dbus/qdbusabstractinterface.h
+++ b/src/dbus/qdbusabstractinterface.h
@@ -49,6 +49,7 @@
#include <QtDBus/qdbusmessage.h>
#include <QtDBus/qdbusextratypes.h>
#include <QtDBus/qdbusconnection.h>
+#include <QtDBus/qdbuspendingcall.h>
#ifdef interface
#undef interface
@@ -98,26 +99,52 @@ public:
void setTimeout(int timeout);
int timeout() const;
+ QDBusMessage call(const QString &method)
+ {
+ return doCall(QDBus::AutoDetect, method, nullptr, 0);
+ }
+
+ template <typename...Args>
+ QDBusMessage call(const QString &method, Args &&...args)
+ {
+ const QVariant variants[] = { QVariant(std::forward<Args>(args))... };
+ return doCall(QDBus::AutoDetect, method, variants, sizeof...(args));
+ }
+
+ QDBusMessage call(QDBus::CallMode mode, const QString &method)
+ {
+ return doCall(mode, method, nullptr, 0);
+ }
+
+ template <typename...Args>
+ QDBusMessage call(QDBus::CallMode mode, const QString &method, Args &&...args)
+ {
+ const QVariant variants[] = { QVariant(std::forward<Args>(args))... };
+ return doCall(mode, method, variants, sizeof...(args));
+ }
+
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QDBusMessage call(const QString &method,
- const QVariant &arg1 = QVariant(),
- const QVariant &arg2 = QVariant(),
- const QVariant &arg3 = QVariant(),
- const QVariant &arg4 = QVariant(),
- const QVariant &arg5 = QVariant(),
- const QVariant &arg6 = QVariant(),
- const QVariant &arg7 = QVariant(),
- const QVariant &arg8 = QVariant());
+ const QVariant &arg1,
+ const QVariant &arg2,
+ const QVariant &arg3,
+ const QVariant &arg4,
+ const QVariant &arg5,
+ const QVariant &arg6,
+ const QVariant &arg7,
+ const QVariant &arg8);
QDBusMessage call(QDBus::CallMode mode,
const QString &method,
- const QVariant &arg1 = QVariant(),
- const QVariant &arg2 = QVariant(),
- const QVariant &arg3 = QVariant(),
- const QVariant &arg4 = QVariant(),
- const QVariant &arg5 = QVariant(),
- const QVariant &arg6 = QVariant(),
- const QVariant &arg7 = QVariant(),
- const QVariant &arg8 = QVariant());
+ const QVariant &arg1,
+ const QVariant &arg2,
+ const QVariant &arg3,
+ const QVariant &arg4,
+ const QVariant &arg5,
+ const QVariant &arg6,
+ const QVariant &arg7,
+ const QVariant &arg8);
+#endif // Qt 5
QDBusMessage callWithArgumentList(QDBus::CallMode mode,
const QString &method,
@@ -130,15 +157,30 @@ public:
const QList<QVariant> &args,
QObject *receiver, const char *member);
+ QDBusPendingCall asyncCall(const QString &method)
+ {
+ return doAsyncCall(method, nullptr, 0);
+ }
+
+ template <typename...Args>
+ QDBusPendingCall asyncCall(const QString &method, Args&&...args)
+ {
+ const QVariant variants[] = { QVariant(std::forward<Args>(args))... };
+ return doAsyncCall(method, variants, sizeof...(args));
+ }
+
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QDBusPendingCall asyncCall(const QString &method,
- const QVariant &arg1 = QVariant(),
- const QVariant &arg2 = QVariant(),
- const QVariant &arg3 = QVariant(),
- const QVariant &arg4 = QVariant(),
- const QVariant &arg5 = QVariant(),
- const QVariant &arg6 = QVariant(),
- const QVariant &arg7 = QVariant(),
- const QVariant &arg8 = QVariant());
+ const QVariant &arg1,
+ const QVariant &arg2,
+ const QVariant &arg3,
+ const QVariant &arg4,
+ const QVariant &arg5,
+ const QVariant &arg6,
+ const QVariant &arg7,
+ const QVariant &arg8);
+#endif // Qt 5
+
QDBusPendingCall asyncCallWithArgumentList(const QString &method,
const QList<QVariant> &args);
@@ -156,6 +198,10 @@ protected:
const QList<QVariant> &args = QList<QVariant>()) const;
private:
+ QDBusMessage doCall(QDBus::CallMode mode, const QString &method, const QVariant *args, size_t numArgs);
+ QDBusPendingCall doAsyncCall(const QString &method, const QVariant *args, size_t numArgs);
+
+private:
Q_DECLARE_PRIVATE(QDBusAbstractInterface)
Q_PRIVATE_SLOT(d_func(), void _q_serviceOwnerChanged(QString,QString,QString))
};