From f8b3c1f0a764988e0319adaea81d912a68e37ae5 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 28 Aug 2024 17:05:19 +0200 Subject: [PATCH] QChronoTimer: remove static singleShot() functions They match what QTimer already provides these days, and we want to minimize porting for users come Qt 7, so we don't want users to first write QChronoTimer::singleShot() (because it exists) and then back to QTimer::singleShot(); we want them to continue to use QTimer. The only reason QChronoTimer is a separate class from QTimer is that the latter has an int interval property and we can't just port it to milli- or nanoseconds chrono types if we want users to actually access the extra range or precision afforded by the chrono types. But that's not an issue for the singleShot() static methods, as they never return an object that could be asked for its timeout. (No ChangeLog needed, as QChronoTimer is new in 6.8) Found in API-review. Fixes: QTBUG-128426 Change-Id: Ief8b7c8d25380c0e9e9c5c36c90ce34c147557ae Reviewed-by: Thiago Macieira Reviewed-by: Volker Hilsheimer (cherry picked from commit 6e5eb082c934cb94c45f3e13b3f7c2deb2e7b2e6) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/kernel/qchronotimer.cpp | 95 +------------------ src/corelib/kernel/qchronotimer.h | 46 --------- .../kernel/qchronotimer/tst_qchronotimer.cpp | 20 ++-- 3 files changed, 12 insertions(+), 149 deletions(-) diff --git a/src/corelib/kernel/qchronotimer.cpp b/src/corelib/kernel/qchronotimer.cpp index 6aeb99cfa8e..b6926666363 100644 --- a/src/corelib/kernel/qchronotimer.cpp +++ b/src/corelib/kernel/qchronotimer.cpp @@ -38,9 +38,8 @@ QT_BEGIN_NAMESPACE You can set a timer to time out only once by calling setSingleShot(true). - QChronoTimer also has singleShot() static methods: - - \snippet timers/timers.cpp qchronotimer-singleshot + \note QChronoTimer has no singleShot() static methods, as the ones on + QTimer already work with chrono types and nanoseconds resolution. In multithreaded applications, you can use QChronoTimer in any thread that has an event loop. To start an event loop from a non-GUI @@ -360,96 +359,6 @@ QBindable QChronoTimer::bindableTimerType() return {&d_func()->type}; } -/*! - \overload - \reentrant - - This static function calls the slot \a member, on object \a receiver, after - time interval \a interval. \a timerType affects the precision of the timer - - \a member has to be a member function of \a receiver; you need to use the - \c SLOT() macro to get this parameter. - - This function is provided as a convenience to save the need to use a - \l{QObject::timerEvent()}{timerEvent} or create a local QChronoTimer - object. - - \sa start(), Qt::TimerType -*/ -void QChronoTimer::singleShot(std::chrono::nanoseconds interval, Qt::TimerType timerType, - const QObject *receiver, const char *member) -{ - if (Q_UNLIKELY(interval < 0ns)) { - qWarning("QChronoTimer::singleShot: Timers cannot have negative timeouts"); - return; - } - if (receiver && member) { - if (interval == 0ns) { - // special code shortpath for 0-timers - const char* bracketPosition = strchr(member, '('); - if (!bracketPosition || !(member[0] >= '0' && member[0] <= '2')) { - qWarning("QChronoTimer::singleShot: Invalid slot specification"); - return; - } - const auto methodName = QByteArrayView(member + 1, // extract method name - bracketPosition - 1 - member).trimmed(); - QMetaObject::invokeMethod(const_cast(receiver), - methodName.toByteArray().constData(), - Qt::QueuedConnection); - return; - } - (void) new QSingleShotTimer(interval, timerType, receiver, member); - } -} - -/*! - \internal - - \list - \li \a interval the time interval - \li \a timerType the type of the timer; this affects the precision of - the timer - \li \a receiver the receiver or context object; if this is \c nullptr, - this method will figure out a context object to use, see code - comments below - \li \a slotObj a callable, for example a lambda - \endlist -*/ -void QChronoTimer::singleShotImpl(std::chrono::nanoseconds interval, Qt::TimerType timerType, - const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj) -{ - if (interval == 0ns) { - bool deleteReceiver = false; - // Optimize: set a receiver context when none is given, such that we can use - // QMetaObject::invokeMethod which is more efficient than going through a timer. - // We need a QObject living in the current thread. But the QThread itself lives - // in a different thread - with the exception of the main QThread which lives in - // itself. And QThread::currentThread() is among the few QObjects we know that will - // most certainly be there. Note that one can actually call singleShot before the - // QApplication is created! - if (!receiver && QThread::currentThread() == QCoreApplicationPrivate::mainThread()) { - // reuse main thread as context object - receiver = QThread::currentThread(); - } else if (!receiver) { - // Create a receiver context object on-demand. According to the benchmarks, - // this is still more efficient than going through a timer. - receiver = new QObject; - deleteReceiver = true; - } - - auto h = QtPrivate::invokeMethodHelper({}); - QMetaObject::invokeMethodImpl(const_cast(receiver), slotObj, - Qt::QueuedConnection, h.parameterCount(), h.parameters.data(), h.typeNames.data(), - h.metaTypes.data()); - - if (deleteReceiver) - const_cast(receiver)->deleteLater(); - return; - } - - new QSingleShotTimer(interval, timerType, receiver, slotObj); -} - QT_END_NAMESPACE #include "moc_qchronotimer.cpp" diff --git a/src/corelib/kernel/qchronotimer.h b/src/corelib/kernel/qchronotimer.h index 136edb06a2e..79f66f89c71 100644 --- a/src/corelib/kernel/qchronotimer.h +++ b/src/corelib/kernel/qchronotimer.h @@ -55,49 +55,6 @@ public: bool isSingleShot() const; QBindable bindableSingleShot(); - // singleShot with context -#ifdef Q_QDOC - template - static inline void singleShot(std::chrono::nanoseconds interval, - const QObject *receiver, Functor &&slot); - template - static inline void singleShot(std::chrono::nanoseconds interval interval, - Qt::TimerType timerType, - const QObject *receiver, Functor &&slot); -#else - template - static void singleShot(std::chrono::nanoseconds interval, - const FunctorContext *receiver, Functor &&slot) - { - singleShot(interval, QTimer::defaultTypeFor(interval), receiver, std::forward(slot)); - } - template - static void singleShot(std::chrono::nanoseconds interval, Qt::TimerType timerType, - const FunctorContext *receiver, Functor &&slot) - { - using Prototype = void(*)(); - auto *slotObj = QtPrivate::makeCallableObject(std::forward(slot)); - singleShotImpl(interval, timerType, receiver, slotObj); - } -#endif - - template - static void singleShot(std::chrono::nanoseconds interval, Qt::TimerType timerType, - Functor &&slot) - { singleShot(interval, timerType, nullptr, std::forward(slot)); } - - template - static void singleShot(std::chrono::nanoseconds interval, Functor &&slot) - { - singleShot(interval, QTimer::defaultTypeFor(interval), nullptr, std::forward(slot)); - } - - static void singleShot(std::chrono::nanoseconds interval, Qt::TimerType timerType, - const QObject *receiver, const char *member); - static void singleShot(std::chrono::nanoseconds interval, const QObject *receiver, - const char *member) - { singleShot(interval, QTimer::defaultTypeFor(interval), receiver, member); } - #ifdef Q_QDOC template QMetaObject::Connection callOnTimeout(const QObject *context, Functor &&slot, @@ -132,9 +89,6 @@ private: // These two functions are inherited from QObject int startTimer(std::chrono::nanoseconds) = delete; void killTimer(int) = delete; - - static void singleShotImpl(std::chrono::nanoseconds interval, Qt::TimerType timerType, - const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj); }; QT_END_NAMESPACE diff --git a/tests/auto/corelib/kernel/qchronotimer/tst_qchronotimer.cpp b/tests/auto/corelib/kernel/qchronotimer/tst_qchronotimer.cpp index 62c402ae24d..9b8980c8abd 100644 --- a/tests/auto/corelib/kernel/qchronotimer/tst_qchronotimer.cpp +++ b/tests/auto/corelib/kernel/qchronotimer/tst_qchronotimer.cpp @@ -472,8 +472,8 @@ public: inTimerEvent = true; QEventLoop eventLoop; - QChronoTimer::singleShot(std::max(100ms, interval * 2), - &eventLoop, &QEventLoop::quit); + QTimer::singleShot(std::max(100ms, interval * 2), + &eventLoop, &QEventLoop::quit); eventLoop.exec(); inTimerEvent = false; @@ -501,8 +501,8 @@ void tst_QChronoTimer::timerInfiniteRecursion() (void) object.startTimer(interval); QEventLoop eventLoop; - QChronoTimer::singleShot(std::max(100ms, interval * 2), &eventLoop, - &QEventLoop::quit); + QTimer::singleShot(std::max(100ms, interval * 2), + &eventLoop, &QEventLoop::quit); eventLoop.exec(); QVERIFY(!object.timerEventRecursed); @@ -527,7 +527,7 @@ public: Q_EMIT done(); } if (recurse) { QEventLoop eventLoop; - QChronoTimer::singleShot(100ms, &eventLoop, &QEventLoop::quit); + QTimer::singleShot(100ms, &eventLoop, &QEventLoop::quit); eventLoop.exec(); } } @@ -804,7 +804,7 @@ public slots: void tst_QChronoTimer::recurseOnTimeoutAndStopTimer() { QEventLoop eventLoop; - QChronoTimer::singleShot(1s, &eventLoop, &QEventLoop::quit); + QTimer::singleShot(1s, &eventLoop, &QEventLoop::quit); RecursOnTimeoutAndStopTimerTimer t; t.one = new QChronoTimer(&t); @@ -1173,16 +1173,16 @@ public: switch (callType) { case String: - QChronoTimer::singleShot(0ns, this, SLOT(stringSlot())); + QTimer::singleShot(0ns, this, SLOT(stringSlot())); break; case PMF: - QChronoTimer::singleShot(0ns, this, &OrderHelper::pmfSlot); + QTimer::singleShot(0ns, this, &OrderHelper::pmfSlot); break; case Functor: - QChronoTimer::singleShot(0ns, this, [this]() { functorSlot(); }); + QTimer::singleShot(0ns, this, [this]() { functorSlot(); }); break; case FunctorNoCtx: - QChronoTimer::singleShot(0ns, [this]() { functorNoCtxSlot(); }); + QTimer::singleShot(0ns, [this]() { functorNoCtxSlot(); }); break; } }