From e6ab7847a76237e4a391ffa6080368321569f152 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 28 Aug 2024 15:44:39 +0200 Subject: [PATCH] QTimer: make singleShot() have nanoseconds resolution [1/2]: old-style Port the string-based singleShot() static methods from milliseconds to nanoseconds resolution. This matches what QChronoTimer provides, but we want to minimize porting for users come Qt 7, so we don't want users to first have to port to QChronoTimer::singleShot() 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. The new-style static methods will be ported in a second step. [ChangeLog][QtCore][QTimer] The singleShot() static methods now operate with nanoseconds resolution, like QChronoTimer. The rest of QTimer remains milliseconds; use QChronoTimer if you need a QTimer with nanoseconds resolution of more than INT_MAX milliseconds range. Beware overflow that may occur when passing large milliseconds objects that may overflow nanoseconds::rep when converted. Task-number: QTBUG-128426 Change-Id: I11e1ad8529c67b4018f6325ac408686799475823 Reviewed-by: Thiago Macieira (cherry picked from commit 4e911bda295b53bc74cf1af26008b3e60181668d) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/compat/removed_api.cpp | 6 ++++++ src/corelib/kernel/qtimer.cpp | 24 ++++++++++++++++-------- src/corelib/kernel/qtimer.h | 8 ++++++++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/corelib/compat/removed_api.cpp b/src/corelib/compat/removed_api.cpp index e9e4e7edeeb..8f4d3042a9d 100644 --- a/src/corelib/compat/removed_api.cpp +++ b/src/corelib/compat/removed_api.cpp @@ -1168,6 +1168,12 @@ auto QStringConverter::encodingForName(const char *name) noexcept -> std::option #include "qtimer.h" // inlined API +void QTimer::singleShot(std::chrono::milliseconds interval, Qt::TimerType timerType, + const QObject *receiver, const char *member) +{ + singleShot(from_msecs(interval), timerType, receiver, member); +} + #include "qurl.h" bool QUrl::operator<(const QUrl &url) const diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp index 93a2ad6d07d..3a9571a9d85 100644 --- a/src/corelib/kernel/qtimer.cpp +++ b/src/corelib/kernel/qtimer.cpp @@ -395,15 +395,15 @@ void QTimer::singleShotImpl(std::chrono::milliseconds msec, Qt::TimerType timerT \sa start() */ -void QTimer::singleShot(std::chrono::milliseconds msec, Qt::TimerType timerType, +void QTimer::singleShot(std::chrono::nanoseconds ns, Qt::TimerType timerType, const QObject *receiver, const char *member) { - if (Q_UNLIKELY(msec < 0ms)) { + if (ns < 0ns) { qWarning("QTimer::singleShot: Timers cannot have negative timeouts"); return; } if (receiver && member) { - if (msec == 0ms) { + if (ns == 0ns) { // special code shortpath for 0-timers const char* bracketPosition = strchr(member, '('); if (!bracketPosition || !(member[0] >= '0' && member[0] <= '2')) { @@ -416,7 +416,7 @@ void QTimer::singleShot(std::chrono::milliseconds msec, Qt::TimerType timerType, Qt::QueuedConnection); return; } - (void) new QSingleShotTimer(from_msecs(msec), timerType, receiver, member); + (void) new QSingleShotTimer(ns, timerType, receiver, member); } } @@ -447,7 +447,7 @@ void QTimer::singleShot(std::chrono::milliseconds msec, Qt::TimerType timerType, */ /*! - \fn void QTimer::singleShot(std::chrono::milliseconds msec, const QObject *receiver, const char *member) + \fn void QTimer::singleShot(std::chrono::nanoseconds nsec, const QObject *receiver, const char *member) \since 5.8 \overload \reentrant @@ -459,13 +459,19 @@ void QTimer::singleShot(std::chrono::milliseconds msec, Qt::TimerType timerType, create a local QTimer object. The \a receiver is the receiving object and the \a member is the slot. The - time interval is given in the duration object \a msec. + time interval is given in the duration object \a nsec. + +//! [qtimer-ns-overflow] + \note In Qt versions prior to 6.8, this function took chrono::milliseconds, + not chrono::nanoseconds. The compiler will automatically convert for you, + but the conversion may overflow for extremely large milliseconds counts. +//! [qtimer-ns-overflow] \sa start() */ /*! - \fn void QTimer::singleShot(std::chrono::milliseconds msec, Qt::TimerType timerType, const QObject *receiver, const char *member) + \fn void QTimer::singleShot(std::chrono::nanoseconds nsec, Qt::TimerType timerType, const QObject *receiver, const char *member) \since 5.8 \overload \reentrant @@ -477,9 +483,11 @@ void QTimer::singleShot(std::chrono::milliseconds msec, Qt::TimerType timerType, create a local QTimer object. The \a receiver is the receiving object and the \a member is the slot. The - time interval is given in the duration object \a msec. The \a timerType affects the + time interval is given in the duration object \a nsec. The \a timerType affects the accuracy of the timer. + \include qtimer.cpp qtimer-ns-overflow + \sa start() */ diff --git a/src/corelib/kernel/qtimer.h b/src/corelib/kernel/qtimer.h index cc4720a3d05..2403b963487 100644 --- a/src/corelib/kernel/qtimer.h +++ b/src/corelib/kernel/qtimer.h @@ -127,12 +127,20 @@ public: return std::chrono::milliseconds(remainingTime()); } +#if QT_CORE_REMOVED_SINCE(6, 8) static void singleShot(std::chrono::milliseconds value, const QObject *receiver, const char *member) { singleShot(value, defaultTypeFor(value), receiver, member); } static void singleShot(std::chrono::milliseconds interval, Qt::TimerType timerType, const QObject *receiver, const char *member); +#endif // QT_CORE_REMOVED_SINCE(6, 8) + static void singleShot(std::chrono::nanoseconds value, const QObject *receiver, const char *member) + { + singleShot(value, defaultTypeFor(value), receiver, member); + } + static void singleShot(std::chrono::nanoseconds interval, Qt::TimerType timerType, + const QObject *receiver, const char *member); void start(std::chrono::milliseconds value);