summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2023-02-22 21:08:01 -0800
committerThiago Macieira <thiago.macieira@intel.com>2023-04-18 19:23:45 -0300
commit39be743e5cde56f6a8af55475ed39f53c6d02a51 (patch)
tree6f0f1d535da36aa282cc47bf7f6b3f1eb0c6a840
parent7ba76731ef70a54de841f5310f17cb48977c67d8 (diff)
QDeadlineTimer: remove internal TimeReference class
This removes all uses of QDeadlineTimer::t2 member in the .cpp (so it gets marked [[maybe_unused]]) and greatly simplifies the code. Change-Id: Ieec322d73c1e40ad95c8fffd17465bd50c1113ea Reviewed-by: Ahmad Samir <a.samirh78@gmail.com> Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
-rw-r--r--src/corelib/kernel/qdeadlinetimer.cpp316
-rw-r--r--tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp2
2 files changed, 47 insertions, 271 deletions
diff --git a/src/corelib/kernel/qdeadlinetimer.cpp b/src/corelib/kernel/qdeadlinetimer.cpp
index eab58df2e6..25af463f8e 100644
--- a/src/corelib/kernel/qdeadlinetimer.cpp
+++ b/src/corelib/kernel/qdeadlinetimer.cpp
@@ -8,214 +8,38 @@ QT_BEGIN_NAMESPACE
QT_IMPL_METATYPE_EXTERN(QDeadlineTimer)
-namespace {
- class TimeReference
- {
- enum : unsigned {
- umega = 1000 * 1000,
- ugiga = umega * 1000
- };
-
- enum : qint64 {
- kilo = 1000,
- mega = kilo * 1000,
- giga = mega * 1000
- };
-
- public:
- enum RoundingStrategy {
- RoundDown,
- RoundUp,
- RoundDefault = RoundDown
- };
-
- static constexpr qint64 Min = std::numeric_limits<qint64>::min();
- static constexpr qint64 Max = std::numeric_limits<qint64>::max();
-
- inline TimeReference(qint64 = 0, unsigned = 0);
- inline void updateTimer(qint64 &, unsigned &);
-
- inline bool addNanoseconds(qint64);
- inline bool addMilliseconds(qint64);
- bool addSecsAndNSecs(qint64, qint64);
-
- inline bool subtract(const qint64, const unsigned);
-
- inline bool toMilliseconds(qint64 *, RoundingStrategy = RoundDefault) const;
- inline bool toNanoseconds(qint64 *) const;
-
- inline void saturate(bool toMax);
- static bool sign(qint64, qint64);
-
- private:
- bool adjust(const qint64, const unsigned, qint64 = 0);
-
- private:
- qint64 secs;
- unsigned nsecs;
- };
-}
-
-inline TimeReference::TimeReference(qint64 t1, unsigned t2)
- : secs(t1), nsecs(t2)
-{
-}
+using namespace std::chrono;
-inline void TimeReference::updateTimer(qint64 &t1, unsigned &t2)
-{
- t1 = secs;
- t2 = nsecs;
-}
-
-inline void TimeReference::saturate(bool toMax)
+namespace {
+struct TimeReference : std::numeric_limits<qint64>
{
- secs = toMax ? Max : Min;
+ static constexpr qint64 Min = min();
+ static constexpr qint64 Max = max();
+};
}
-/*!
- * \internal
- *
- * Determines the sign of a (seconds, nanoseconds) pair
- * for differentiating overflow from underflow. It doesn't
- * deal with equality as it shouldn't ever be called in that case.
- *
- * Returns true if the pair represents a positive time offset
- * false otherwise.
- */
-bool TimeReference::sign(qint64 secs, qint64 nsecs)
+template <typename Duration1, typename... Durations>
+static qint64 add_saturate(qint64 t1, Duration1 dur, Durations... extra)
{
- if (secs > 0) {
- if (nsecs > 0)
- return true;
- } else {
- if (nsecs < 0)
- return false;
+ qint64 v = dur.count();
+ qint64 saturated = std::numeric_limits<qint64>::max();
+ if (v < 0)
+ saturated = std::numeric_limits<qint64>::min();
+
+ // convert to nanoseconds with saturation
+ using Ratio = std::ratio_divide<typename Duration1::period, nanoseconds::period>;
+ static_assert(Ratio::den == 1, "sub-multiples of nanosecond are not supported");
+ if (qMulOverflow<Ratio::num>(v, &v))
+ return saturated;
+
+ qint64 r;
+ if (qAddOverflow(t1, v, &r))
+ return saturated;
+ if constexpr (sizeof...(Durations)) {
+ // chain more additions
+ return add_saturate(r, extra...);
}
-
- // They are different in sign
- secs += nsecs / giga;
- if (secs > 0)
- return true;
- else if (secs < 0)
- return false;
-
- // We should never get over|underflow out of
- // the case: secs * giga == -nsecs
- // So the sign of nsecs is the deciding factor
- Q_ASSERT(nsecs % giga != 0);
- return nsecs > 0;
-}
-
-inline bool TimeReference::addNanoseconds(qint64 arg)
-{
- return adjust(arg, 0);
-}
-
-inline bool TimeReference::addMilliseconds(qint64 arg)
-{
- static constexpr qint64 maxMilliseconds = Max / mega;
- if (qAbs(arg) > maxMilliseconds)
- return false;
-
- return addNanoseconds(arg * mega);
-}
-
-/*!
- * \internal
- *
- * Adds \a t1 addSecs seconds and \a addNSecs nanoseconds to the
- * time reference. The arguments are normalized to seconds (qint64)
- * and nanoseconds (unsigned) before the actual calculation is
- * delegated to adjust(). If the nanoseconds are negative the
- * owed second used for the normalization is passed on to adjust()
- * as third argument.
- *
- * Returns true if operation was successful, false on over|underflow
- */
-inline bool TimeReference::addSecsAndNSecs(qint64 addSecs, qint64 addNSecs)
-{
- static constexpr qint64 maxSeconds = Max / giga;
- static constexpr qint64 minSeconds = Min / giga;
- if (addSecs > maxSeconds || addSecs < minSeconds || add_overflow<qint64>(addSecs * giga, addNSecs, &addNSecs))
- return false;
-
- return addNanoseconds(addNSecs);
-}
-
-/*!
- * \internal
- *
- * Adds \a t1 seconds and \a t2 nanoseconds to the internal members.
- * Takes into account the additional \a carrySeconds we may owe or need to carry over.
- *
- * Returns true if operation was successful, false on over|underflow
- */
-inline bool TimeReference::adjust(const qint64 t1, const unsigned t2, qint64 carrySeconds)
-{
- Q_UNUSED(t2);
- Q_UNUSED(carrySeconds);
-
- return !add_overflow<qint64>(secs, t1, &secs);
-}
-
-/*!
- * \internal
- *
- * Subtracts \a t1 seconds and \a t2 nanoseconds from the time reference.
- * When normalizing the nanoseconds to a positive number the owed seconds is
- * passed as third argument to adjust() as the seconds may over|underflow
- * if we do the calculation directly. There is little sense to check the
- * seconds for over|underflow here in case we are going to need to carry
- * over a second _after_ we add the nanoseconds.
- *
- * Returns true if operation was successful, false on over|underflow
- */
-inline bool TimeReference::subtract(const qint64 t1, const unsigned t2)
-{
- Q_UNUSED(t2);
-
- return addNanoseconds(-t1);
-}
-
-/*!
- * \internal
- *
- * Converts the time reference to milliseconds.
- *
- * Checks are done without making use of mul_overflow because it may
- * not be implemented on some 32bit platforms.
- *
- * Returns true if operation was successful, false on over|underflow
- */
-inline bool TimeReference::toMilliseconds(qint64 *result, RoundingStrategy rounding) const
-{
- // Force QDeadlineTimer to treat the border cases as
- // over|underflow and saturate the results returned to the user.
- // We don't want to get valid milliseconds out of saturated timers.
- if (secs == Max || secs == Min)
- return false;
-
- *result = secs / mega;
- if (rounding == RoundUp && secs > *result * mega)
- (*result)++;
-
- return true;
-}
-
-/*!
- * \internal
- *
- * Converts the time reference to nanoseconds.
- *
- * Checks are done without making use of mul_overflow because it may
- * not be implemented on some 32bit platforms.
- *
- * Returns true if operation was successful, false on over|underflow
- */
-inline bool TimeReference::toNanoseconds(qint64 *result) const
-{
- *result = secs;
- return true;
+ return r;
}
/*!
@@ -435,10 +259,8 @@ void QDeadlineTimer::setRemainingTime(qint64 msecs, Qt::TimerType timerType) noe
*this = current(timerType);
- TimeReference ref(t1, t2);
- if (!ref.addMilliseconds(msecs))
- ref.saturate(msecs > 0);
- ref.updateTimer(t1, t2);
+ milliseconds ms(msecs);
+ t1 = add_saturate(t1, ms);
}
/*!
@@ -460,10 +282,7 @@ void QDeadlineTimer::setPreciseRemainingTime(qint64 secs, qint64 nsecs, Qt::Time
}
*this = current(timerType);
- TimeReference ref(t1, t2);
- if (!ref.addSecsAndNSecs(secs, nsecs))
- ref.saturate(TimeReference::sign(secs, nsecs));
- ref.updateTimer(t1, t2);
+ t1 = add_saturate(t1, seconds{secs}, nanoseconds{nsecs});
}
/*!
@@ -561,19 +380,8 @@ qint64 QDeadlineTimer::remainingTime() const noexcept
if (isForever())
return -1;
- QDeadlineTimer now = current(timerType());
- TimeReference ref(t1, t2);
-
- qint64 msecs;
- if (!ref.subtract(now.t1, now.t2))
- return 0; // We can only underflow here
-
- // If we fail the conversion, t1 < now.t1 means we underflowed,
- // thus the deadline had long expired
- if (!ref.toMilliseconds(&msecs, TimeReference::RoundUp))
- return t1 < now.t1 ? 0 : -1;
-
- return msecs < 0 ? 0 : msecs;
+ nanoseconds nsecs(remainingTimeNSecs());
+ return ceil<milliseconds>(nsecs).count();
}
/*!
@@ -595,23 +403,16 @@ qint64 QDeadlineTimer::remainingTimeNSecs() const noexcept
/*!
\internal
Same as remainingTimeNSecs, but may return negative remaining times. Does
- not deal with Forever. In case of underflow the result is saturated to
- the minimum possible value, on overflow - the maximum possible value.
+ not deal with Forever. In case of underflow, which is only possible if the
+ timer has expired, an arbitrary negative value is returned.
*/
qint64 QDeadlineTimer::rawRemainingTimeNSecs() const noexcept
{
QDeadlineTimer now = current(timerType());
- TimeReference ref(t1, t2);
-
- qint64 nsecs;
- if (!ref.subtract(now.t1, now.t2))
- return TimeReference::Min; // We can only underflow here
-
- // If we fail the conversion, t1 < now.t1 means we underflowed,
- // thus the deadline had long expired
- if (!ref.toNanoseconds(&nsecs))
- return t1 < now.t1 ? TimeReference::Min : TimeReference::Max;
- return nsecs;
+ qint64 r;
+ if (qSubOverflow(t1, now.t1, &r))
+ return -1; // any negative number is fine
+ return r;
}
/*!
@@ -638,12 +439,11 @@ qint64 QDeadlineTimer::deadline() const noexcept
{
if (isForever())
return TimeReference::Max;
+ if (t1 == TimeReference::Min)
+ return t1;
- qint64 result;
- if (!TimeReference(t1, t2).toMilliseconds(&result))
- return t1 < 0 ? TimeReference::Min : TimeReference::Max;
-
- return result;
+ nanoseconds ns(t1);
+ return duration_cast<milliseconds>(ns).count();
}
/*!
@@ -672,11 +472,7 @@ qint64 QDeadlineTimer::deadlineNSecs() const noexcept
if (isForever())
return TimeReference::Max;
- qint64 result;
- if (!TimeReference(t1, t2).toNanoseconds(&result))
- return t1 < 0 ? TimeReference::Min : TimeReference::Max;
-
- return result;
+ return t1;
}
/*!
@@ -700,11 +496,7 @@ void QDeadlineTimer::setDeadline(qint64 msecs, Qt::TimerType timerType) noexcept
}
type = timerType;
-
- TimeReference ref;
- if (!ref.addMilliseconds(msecs))
- ref.saturate(msecs > 0);
- ref.updateTimer(t1, t2);
+ t1 = add_saturate(0, milliseconds{msecs});
}
/*!
@@ -722,13 +514,7 @@ void QDeadlineTimer::setDeadline(qint64 msecs, Qt::TimerType timerType) noexcept
void QDeadlineTimer::setPreciseDeadline(qint64 secs, qint64 nsecs, Qt::TimerType timerType) noexcept
{
type = timerType;
-
- // We don't pass the seconds to the constructor, because we don't know
- // at this point if t1 holds the seconds or nanoseconds; it's platform specific.
- TimeReference ref;
- if (!ref.addSecsAndNSecs(secs, nsecs))
- ref.saturate(TimeReference::sign(secs, nsecs));
- ref.updateTimer(t1, t2);
+ t1 = add_saturate(0, seconds{secs}, nanoseconds{nsecs});
}
/*!
@@ -744,11 +530,7 @@ QDeadlineTimer QDeadlineTimer::addNSecs(QDeadlineTimer dt, qint64 nsecs) noexcep
if (dt.isForever())
return dt;
- TimeReference ref(dt.t1, dt.t2);
- if (!ref.addNanoseconds(nsecs))
- ref.saturate(nsecs > 0);
- ref.updateTimer(dt.t1, dt.t2);
-
+ dt.t1 = add_saturate(dt.t1, nanoseconds{nsecs});
return dt;
}
@@ -866,11 +648,7 @@ QDeadlineTimer operator+(QDeadlineTimer dt, qint64 msecs)
if (dt.isForever())
return dt;
- TimeReference ref(dt.t1, dt.t2);
- if (!ref.addMilliseconds(msecs))
- ref.saturate(msecs > 0);
- ref.updateTimer(dt.t1, dt.t2);
-
+ dt.t1 = add_saturate(dt.t1, milliseconds{msecs});
return dt;
}
@@ -941,6 +719,4 @@ QDeadlineTimer operator+(QDeadlineTimer dt, qint64 msecs)
\internal
*/
-// the rest of the functions are in qelapsedtimer_xxx.cpp
-
QT_END_NAMESPACE
diff --git a/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp b/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp
index ab8adfc75b..bdf2e7a573 100644
--- a/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp
+++ b/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp
@@ -524,7 +524,7 @@ void tst_QDeadlineTimer::overflow()
QCOMPARE(deadline.remainingTimeNSecs(), 0);
QVERIFY(deadline.remainingTime() == 0);
// If the timer is saturated we don't want to get a valid number of milliseconds
- QVERIFY(deadline.deadline() == std::numeric_limits<qint64>::min());
+ QCOMPARE(deadline.deadline(), std::numeric_limits<qint64>::min());
// Check that the conversion to milliseconds and nanoseconds underflows gracefully
deadline.setPreciseDeadline(std::numeric_limits<qint64>::min() / 10, 0, timerType);