diff options
author | Jesus Fernandez <jesus.fernandez@qt.io> | 2016-10-24 21:01:09 +0200 |
---|---|---|
committer | Jesus Fernandez <jesus.fernandez@qt.io> | 2017-01-24 20:54:07 +0000 |
commit | ad5eb297e179a164e297a7c2eb3b9674a1196605 (patch) | |
tree | 925a52ab653dfb0f63c422959f209ea89aae1e48 /src/network | |
parent | 21f27c9a4d0f2ab0976c144f631c9171c899014b (diff) |
Add QHostInfo::lookupHost overload with modern connect syntax
Task-number: QTBUG-56424
Change-Id: I49053ac2859e6c6c07e4a704b8b5f0d6a2d0b8a4
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/kernel/qhostinfo.cpp | 148 | ||||
-rw-r--r-- | src/network/kernel/qhostinfo.h | 63 | ||||
-rw-r--r-- | src/network/kernel/qhostinfo_p.h | 42 |
3 files changed, 252 insertions, 1 deletions
diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp index 88df65dbcb..193c990d8c 100644 --- a/src/network/kernel/qhostinfo.cpp +++ b/src/network/kernel/qhostinfo.cpp @@ -95,6 +95,38 @@ std::pair<OutputIt1, OutputIt2> separate_if(InputIt first, InputIt last, OutputI } return std::make_pair(dest1, dest2); } + +int get_signal_index() +{ + static auto senderMetaObject = &QHostInfoResult::staticMetaObject; + static auto signal = &QHostInfoResult::resultsReady; + int signal_index = -1; + void *args[] = { &signal_index, &signal }; + senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args); + return signal_index + QMetaObjectPrivate::signalOffset(senderMetaObject); +} + +void emit_results_ready(const QHostInfo &hostInfo, const QObject *receiver, + QtPrivate::QSlotObjectBase *slotObj) +{ + static const int signal_index = get_signal_index(); + auto result = new QHostInfoResult(receiver, slotObj); + Q_CHECK_PTR(result); + const int nargs = 2; + auto types = reinterpret_cast<int *>(malloc(nargs * sizeof(int))); + Q_CHECK_PTR(types); + types[0] = QMetaType::type("void"); + types[1] = QMetaType::type("QHostInfo"); + auto args = reinterpret_cast<void **>(malloc(nargs * sizeof(void *))); + Q_CHECK_PTR(args); + args[0] = 0; + args[1] = QMetaType::create(types[1], &hostInfo); + Q_CHECK_PTR(args[1]); + auto metaCallEvent = new QMetaCallEvent(slotObj, nullptr, signal_index, nargs, types, args); + Q_CHECK_PTR(metaCallEvent); + qApp->postEvent(result, metaCallEvent); +} + } /*! @@ -243,6 +275,67 @@ int QHostInfo::lookupHost(const QString &name, QObject *receiver, } /*! + \fn int QHostInfo::lookupHost(const QString &name, const QObject *receiver, PointerToMemberFunction function) + + \since 5.9 + + \overload + + Looks up the IP address(es) associated with host name \a name, and + returns an ID for the lookup. When the result of the lookup is + ready, the slot or signal \a function in \a receiver is called with + a QHostInfo argument. The QHostInfo object can then be inspected + to get the results of the lookup. + + \note There is no guarantee on the order the signals will be emitted + if you start multiple requests with lookupHost(). + + \sa abortHostLookup(), addresses(), error(), fromName() +*/ + +/*! + \fn int QHostInfo::lookupHost(const QString &name, Functor functor) + + \since 5.9 + + \overload + + Looks up the IP address(es) associated with host name \a name, and + returns an ID for the lookup. When the result of the lookup is + ready, the \a functor is called with a QHostInfo argument. The + QHostInfo object can then be inspected to get the results of the + lookup. + \note There is no guarantee on the order the signals will be emitted + if you start multiple requests with lookupHost(). + + \sa abortHostLookup(), addresses(), error(), fromName() +*/ + +/*! + \fn int QHostInfo::lookupHost(const QString &name, const QObject *context, Functor functor) + + \since 5.9 + + \overload + + Looks up the IP address(es) associated with host name \a name, and + returns an ID for the lookup. When the result of the lookup is + ready, the \a functor is called with a QHostInfo argument. The + QHostInfo object can then be inspected to get the results of the + lookup. + + If \a context is destroyed before the lookup completes, the + \a functor will not be called. The \a functor will be run in the + thread of \a context. The context's thread must have a running Qt + event loop. + + \note There is no guarantee on the order the signals will be emitted + if you start multiple requests with lookupHost(). + + \sa abortHostLookup(), addresses(), error(), fromName() +*/ + +/*! Aborts the host lookup with the ID \a id, as returned by lookupHost(). \sa lookupHost(), lookupId() @@ -487,11 +580,66 @@ QString QHostInfo::localHostName() \sa hostName() */ +int QHostInfo::lookupHostImpl(const QString &name, + const QObject *receiver, + QtPrivate::QSlotObjectBase *slotObj) +{ +#if defined QHOSTINFO_DEBUG + qDebug("QHostInfo::lookupHost(\"%s\", %p, %p)", + name.toLatin1().constData(), receiver, slotObj); +#endif + + if (!QAbstractEventDispatcher::instance(QThread::currentThread())) { + qWarning("QHostInfo::lookupHost() called with no event dispatcher"); + return -1; + } + + qRegisterMetaType<QHostInfo>(); + + int id = theIdCounter.fetchAndAddRelaxed(1); // generate unique ID + + if (Q_UNLIKELY(name.isEmpty())) { + QHostInfo hostInfo(id); + hostInfo.setError(QHostInfo::HostNotFound); + hostInfo.setErrorString(QCoreApplication::translate("QHostInfo", "No host name given")); + emit_results_ready(hostInfo, receiver, slotObj); + return id; + } + + QHostInfoLookupManager *manager = theHostInfoLookupManager(); + + if (Q_LIKELY(manager)) { + // the application is still alive + if (manager->cache.isEnabled()) { + // check cache first + bool valid = false; + QHostInfo info = manager->cache.get(name, &valid); + if (valid) { + info.setLookupId(id); + emit_results_ready(info, receiver, slotObj); + return id; + } + } + + // cache is not enabled or it was not in the cache, do normal lookup + QHostInfoRunnable* runnable = new QHostInfoRunnable(name, id, receiver, slotObj); + manager->scheduleLookup(runnable); + } + return id; +} + QHostInfoRunnable::QHostInfoRunnable(const QString &hn, int i) : toBeLookedUp(hn), id(i) { setAutoDelete(true); } +QHostInfoRunnable::QHostInfoRunnable(const QString &hn, int i, const QObject *receiver, + QtPrivate::QSlotObjectBase *slotObj) : + toBeLookedUp(hn), id(i), resultEmitter(receiver, slotObj) +{ + setAutoDelete(true); +} + // the QHostInfoLookupManager will at some point call this via a QThreadPool void QHostInfoRunnable::run() { diff --git a/src/network/kernel/qhostinfo.h b/src/network/kernel/qhostinfo.h index 9b4a4853d9..4484d718bd 100644 --- a/src/network/kernel/qhostinfo.h +++ b/src/network/kernel/qhostinfo.h @@ -87,8 +87,71 @@ public: static QString localHostName(); static QString localDomainName(); +#ifdef Q_QDOC + template<typename PointerToMemberFunction> + static int QHostInfo::lookupHost(const QString &name, const QObject *receiver, + PointerToMemberFunction function); + template<typename Functor> + static int QHostInfo::lookupHost(const QString &name, Functor functor); + template<typename Functor> + static int QHostInfo::lookupHost(const QString &name, const QObject *context, Functor functor); +#else + // lookupHost to a QObject slot + template <typename Func> + static inline int lookupHost(const QString &name, + const typename QtPrivate::FunctionPointer<Func>::Object *receiver, + Func slot) + { + typedef QtPrivate::FunctionPointer<Func> SlotType; + + typedef QtPrivate::FunctionPointer<void (*)(QHostInfo)> SignalType; + Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount), + "The slot requires more arguments than the signal provides."); + Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, + typename SlotType::Arguments>::value), + "Signal and slot arguments are not compatible."); + Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, + typename SignalType::ReturnType>::value), + "Return type of the slot is not compatible " + "with the return type of the signal."); + + auto slotObj = new QtPrivate::QSlotObject<Func, typename SlotType::Arguments, void>(slot); + return lookupHostImpl(name, receiver, slotObj); + } + + // lookupHost to a callable (without context) + template <typename Func> + static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction && + !std::is_same<const char *, Func>::value, int>::type + lookupHost(const QString &name, Func slot) + { + return lookupHost(name, nullptr, slot); + } + + // lookupHost to a functor or function pointer (with context) + template <typename Func1> + static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction && + !std::is_same<const char*, Func1>::value, int>::type + lookupHost(const QString &name, QObject *context, Func1 slot) + { + typedef QtPrivate::FunctionPointer<Func1> SlotType; + + Q_STATIC_ASSERT_X(int(SlotType::ArgumentCount) <= 1, + "The slot must not require more than one argument"); + + auto slotObj = new QtPrivate::QFunctorSlotObject<Func1, 1, + typename QtPrivate::List<QHostInfo>, + void>(slot); + return lookupHostImpl(name, context, slotObj); + } +#endif // Q_QDOC + private: QScopedPointer<QHostInfoPrivate> d; + + static int lookupHostImpl(const QString &name, + const QObject *receiver, + QtPrivate::QSlotObjectBase *slotObj); }; QT_END_NAMESPACE diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h index ba342bf533..dd46818a19 100644 --- a/src/network/kernel/qhostinfo_p.h +++ b/src/network/kernel/qhostinfo_p.h @@ -54,6 +54,7 @@ #include <QtNetwork/private/qtnetworkglobal_p.h> #include "QtCore/qcoreapplication.h" #include "private/qcoreapplication_p.h" +#include "private/qmetaobject_p.h" #include "QtNetwork/qhostinfo.h" #include "QtCore/qmutex.h" #include "QtCore/qwaitcondition.h" @@ -77,10 +78,47 @@ QT_BEGIN_NAMESPACE class QHostInfoResult : public QObject { Q_OBJECT + + QPointer<const QObject> receiver = nullptr; + QtPrivate::QSlotObjectBase *slotObj = nullptr; + +public: + QHostInfoResult() = default; + QHostInfoResult(const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj) : + receiver(receiver), + slotObj(slotObj) + { + connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, + &QObject::deleteLater); + if (slotObj && receiver) + moveToThread(receiver->thread()); + } + public Q_SLOTS: inline void emitResultsReady(const QHostInfo &info) { - emit resultsReady(info); + if (slotObj) { + QHostInfo copy = info; + void *args[2] = { 0, reinterpret_cast<void *>(©) }; + slotObj->call(const_cast<QObject*>(receiver.data()), args); + slotObj->destroyIfLastRef(); + } else { + emit resultsReady(info); + } + } + +protected: + bool event(QEvent *event) + { + if (event->type() == QEvent::MetaCall) { + auto metaCallEvent = static_cast<QMetaCallEvent *>(event); + auto args = metaCallEvent->args(); + auto hostInfo = reinterpret_cast<QHostInfo *>(args[1]); + emitResultsReady(*hostInfo); + deleteLater(); + return true; + } + return QObject::event(event); } Q_SIGNALS: @@ -154,6 +192,8 @@ class QHostInfoRunnable : public QRunnable { public: QHostInfoRunnable(const QString &hn, int i); + QHostInfoRunnable(const QString &hn, int i, const QObject *receiver, + QtPrivate::QSlotObjectBase *slotObj); void run() Q_DECL_OVERRIDE; QString toBeLookedUp; |