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 <thiago.macieira@intel.com>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
(cherry picked from commit 6e5eb082c934cb94c45f3e13b3f7c2deb2e7b2e6)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Marc Mutz 2024-08-28 17:05:19 +02:00 committed by Qt Cherry-pick Bot
parent 2fb422828e
commit f8b3c1f0a7
3 changed files with 12 additions and 149 deletions

View File

@ -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<Qt::TimerType> 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<QObject *>(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<QObject *>(receiver), slotObj,
Qt::QueuedConnection, h.parameterCount(), h.parameters.data(), h.typeNames.data(),
h.metaTypes.data());
if (deleteReceiver)
const_cast<QObject *>(receiver)->deleteLater();
return;
}
new QSingleShotTimer(interval, timerType, receiver, slotObj);
}
QT_END_NAMESPACE
#include "moc_qchronotimer.cpp"

View File

@ -55,49 +55,6 @@ public:
bool isSingleShot() const;
QBindable<bool> bindableSingleShot();
// singleShot with context
#ifdef Q_QDOC
template <typename Functor>
static inline void singleShot(std::chrono::nanoseconds interval,
const QObject *receiver, Functor &&slot);
template <typename Functor>
static inline void singleShot(std::chrono::nanoseconds interval interval,
Qt::TimerType timerType,
const QObject *receiver, Functor &&slot);
#else
template <typename Functor>
static void singleShot(std::chrono::nanoseconds interval,
const FunctorContext<Functor> *receiver, Functor &&slot)
{
singleShot(interval, QTimer::defaultTypeFor(interval), receiver, std::forward<Functor>(slot));
}
template <typename Functor>
static void singleShot(std::chrono::nanoseconds interval, Qt::TimerType timerType,
const FunctorContext<Functor> *receiver, Functor &&slot)
{
using Prototype = void(*)();
auto *slotObj = QtPrivate::makeCallableObject<Prototype>(std::forward<Functor>(slot));
singleShotImpl(interval, timerType, receiver, slotObj);
}
#endif
template <typename Functor>
static void singleShot(std::chrono::nanoseconds interval, Qt::TimerType timerType,
Functor &&slot)
{ singleShot(interval, timerType, nullptr, std::forward<Functor>(slot)); }
template <typename Functor>
static void singleShot(std::chrono::nanoseconds interval, Functor &&slot)
{
singleShot(interval, QTimer::defaultTypeFor(interval), nullptr, std::forward<Functor>(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 <typename Functor>
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

View File

@ -472,8 +472,8 @@ public:
inTimerEvent = true;
QEventLoop eventLoop;
QChronoTimer::singleShot(std::max<std::chrono::nanoseconds>(100ms, interval * 2),
&eventLoop, &QEventLoop::quit);
QTimer::singleShot(std::max<std::chrono::nanoseconds>(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<std::chrono::nanoseconds>(100ms, interval * 2), &eventLoop,
&QEventLoop::quit);
QTimer::singleShot(std::max<std::chrono::nanoseconds>(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;
}
}