// Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QDEADLINETIMER_H #define QDEADLINETIMER_H #include #include #include #ifdef max // un-pollute the namespace. We need std::numeric_limits::max() and std::chrono::duration::max() # undef max #endif #include #include QT_BEGIN_NAMESPACE class Q_CORE_EXPORT QDeadlineTimer { public: enum class ForeverConstant { Forever }; static constexpr ForeverConstant Forever = ForeverConstant::Forever; constexpr QDeadlineTimer() noexcept = default; constexpr explicit QDeadlineTimer(Qt::TimerType type_) noexcept : type(type_) {} constexpr QDeadlineTimer(ForeverConstant, Qt::TimerType type_ = Qt::CoarseTimer) noexcept : t1((std::numeric_limits::max)()), type(type_) {} explicit QDeadlineTimer(qint64 msecs, Qt::TimerType type = Qt::CoarseTimer) noexcept; void swap(QDeadlineTimer &other) noexcept { std::swap(t1, other.t1); std::swap(type, other.type); } constexpr bool isForever() const noexcept { return t1 == (std::numeric_limits::max)(); } bool hasExpired() const noexcept; Qt::TimerType timerType() const noexcept { return Qt::TimerType(type & 0xff); } void setTimerType(Qt::TimerType type); qint64 remainingTime() const noexcept; qint64 remainingTimeNSecs() const noexcept; void setRemainingTime(qint64 msecs, Qt::TimerType type = Qt::CoarseTimer) noexcept; void setPreciseRemainingTime(qint64 secs, qint64 nsecs = 0, Qt::TimerType type = Qt::CoarseTimer) noexcept; qint64 deadline() const noexcept Q_DECL_PURE_FUNCTION; qint64 deadlineNSecs() const noexcept Q_DECL_PURE_FUNCTION; void setDeadline(qint64 msecs, Qt::TimerType timerType = Qt::CoarseTimer) noexcept; void setPreciseDeadline(qint64 secs, qint64 nsecs = 0, Qt::TimerType type = Qt::CoarseTimer) noexcept; static QDeadlineTimer addNSecs(QDeadlineTimer dt, qint64 nsecs) noexcept Q_DECL_PURE_FUNCTION; static QDeadlineTimer current(Qt::TimerType timerType = Qt::CoarseTimer) noexcept; friend Q_CORE_EXPORT QDeadlineTimer operator+(QDeadlineTimer dt, qint64 msecs); friend QDeadlineTimer operator+(qint64 msecs, QDeadlineTimer dt) { return dt + msecs; } friend QDeadlineTimer operator-(QDeadlineTimer dt, qint64 msecs) { return dt + (-msecs); } friend qint64 operator-(QDeadlineTimer dt1, QDeadlineTimer dt2) { return (dt1.deadlineNSecs() - dt2.deadlineNSecs()) / (1000 * 1000); } QDeadlineTimer &operator+=(qint64 msecs) { *this = *this + msecs; return *this; } QDeadlineTimer &operator-=(qint64 msecs) { *this = *this + (-msecs); return *this; } template QDeadlineTimer(std::chrono::time_point deadline_, Qt::TimerType type_ = Qt::CoarseTimer) : t2(0) { setDeadline(deadline_, type_); } template QDeadlineTimer &operator=(std::chrono::time_point deadline_) { setDeadline(deadline_); return *this; } template void setDeadline(std::chrono::time_point tp, Qt::TimerType type_ = Qt::CoarseTimer); template std::chrono::time_point deadline() const; template QDeadlineTimer(std::chrono::duration remaining, Qt::TimerType type_ = Qt::CoarseTimer) : t2(0) { setRemainingTime(remaining, type_); } template QDeadlineTimer &operator=(std::chrono::duration remaining) { setRemainingTime(remaining); return *this; } template void setRemainingTime(std::chrono::duration remaining, Qt::TimerType type_ = Qt::CoarseTimer) { using namespace std::chrono; if (remaining == remaining.max()) *this = QDeadlineTimer(Forever, type_); else setPreciseRemainingTime(0, ceil(remaining).count(), type_); } std::chrono::nanoseconds remainingTimeAsDuration() const noexcept { if (isForever()) return std::chrono::nanoseconds::max(); qint64 nsecs = rawRemainingTimeNSecs(); if (nsecs <= 0) return std::chrono::nanoseconds::zero(); return std::chrono::nanoseconds(nsecs); } template friend QDeadlineTimer operator+(QDeadlineTimer dt, std::chrono::duration value) { return QDeadlineTimer::addNSecs(dt, std::chrono::duration_cast(value).count()); } template friend QDeadlineTimer operator+(std::chrono::duration value, QDeadlineTimer dt) { return dt + value; } template friend QDeadlineTimer operator+=(QDeadlineTimer &dt, std::chrono::duration value) { return dt = dt + value; } private: friend bool comparesEqual(const QDeadlineTimer &lhs, const QDeadlineTimer &rhs) noexcept { return lhs.t1 == rhs.t1; } friend Qt::strong_ordering compareThreeWay(const QDeadlineTimer &lhs, const QDeadlineTimer &rhs) noexcept { return Qt::compareThreeWay(lhs.t1, rhs.t1); } Q_DECLARE_STRONGLY_ORDERED(QDeadlineTimer) qint64 t1 = 0; #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) unsigned t2 = 0; #endif unsigned type = Qt::CoarseTimer; qint64 rawRemainingTimeNSecs() const noexcept; }; template std::chrono::time_point QDeadlineTimer::deadline() const { using namespace std::chrono; if constexpr (std::is_same_v) { auto val = duration_cast(nanoseconds(deadlineNSecs())); return time_point(val); } else { auto val = nanoseconds(rawRemainingTimeNSecs()) + Clock::now(); return time_point_cast(val); } } template void QDeadlineTimer::setDeadline(std::chrono::time_point tp, Qt::TimerType type_) { using namespace std::chrono; if (tp == tp.max()) { *this = Forever; type = type_; } else if constexpr (std::is_same_v) { setPreciseDeadline(0, duration_cast(tp.time_since_epoch()).count(), type_); } else { setPreciseRemainingTime(0, duration_cast(tp - Clock::now()).count(), type_); } } Q_DECLARE_SHARED(QDeadlineTimer) QT_END_NAMESPACE QT_DECL_METATYPE_EXTERN(QDeadlineTimer, Q_CORE_EXPORT) #endif // QDEADLINETIMER_H