1// Copyright (C) 2016 Intel Corporation.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QDEADLINETIMER_H
5#define QDEADLINETIMER_H
6
7#include <QtCore/qelapsedtimer.h>
8#include <QtCore/qmetatype.h>
9#include <QtCore/qnamespace.h>
10#include <QtCore/qpair.h>
11
12#ifdef max
13// un-pollute the namespace. We need std::numeric_limits::max() and std::chrono::duration::max()
14# undef max
15#endif
16
17#include <limits>
18
19#include <chrono>
20
21QT_BEGIN_NAMESPACE
22
23class Q_CORE_EXPORT QDeadlineTimer
24{
25public:
26 enum class ForeverConstant { Forever };
27 static constexpr ForeverConstant Forever = ForeverConstant::Forever;
28
29 constexpr QDeadlineTimer() noexcept = default;
30 constexpr explicit QDeadlineTimer(Qt::TimerType type_) noexcept
31 : type(type_) {}
32 constexpr QDeadlineTimer(ForeverConstant, Qt::TimerType type_ = Qt::CoarseTimer) noexcept
33 : t1((std::numeric_limits<qint64>::max)()), type(type_) {}
34 explicit QDeadlineTimer(qint64 msecs, Qt::TimerType type = Qt::CoarseTimer) noexcept;
35
36 void swap(QDeadlineTimer &other) noexcept
37 { std::swap(a&: t1, b&: other.t1); std::swap(a&: type, b&: other.type); }
38
39 constexpr bool isForever() const noexcept
40 { return t1 == (std::numeric_limits<qint64>::max)(); }
41 bool hasExpired() const noexcept;
42
43 Qt::TimerType timerType() const noexcept
44 { return Qt::TimerType(type & 0xff); }
45 void setTimerType(Qt::TimerType type);
46
47 qint64 remainingTime() const noexcept;
48 qint64 remainingTimeNSecs() const noexcept;
49 void setRemainingTime(qint64 msecs, Qt::TimerType type = Qt::CoarseTimer) noexcept;
50 void setPreciseRemainingTime(qint64 secs, qint64 nsecs = 0,
51 Qt::TimerType type = Qt::CoarseTimer) noexcept;
52
53 qint64 deadline() const noexcept Q_DECL_PURE_FUNCTION;
54 qint64 deadlineNSecs() const noexcept Q_DECL_PURE_FUNCTION;
55 void setDeadline(qint64 msecs, Qt::TimerType timerType = Qt::CoarseTimer) noexcept;
56 void setPreciseDeadline(qint64 secs, qint64 nsecs = 0,
57 Qt::TimerType type = Qt::CoarseTimer) noexcept;
58
59 static QDeadlineTimer addNSecs(QDeadlineTimer dt, qint64 nsecs) noexcept Q_DECL_PURE_FUNCTION;
60 static QDeadlineTimer current(Qt::TimerType timerType = Qt::CoarseTimer) noexcept;
61
62 friend bool operator==(QDeadlineTimer d1, QDeadlineTimer d2) noexcept
63 { return d1.t1 == d2.t1; }
64 friend bool operator!=(QDeadlineTimer d1, QDeadlineTimer d2) noexcept
65 { return !(d1 == d2); }
66 friend bool operator<(QDeadlineTimer d1, QDeadlineTimer d2) noexcept
67 { return d1.t1 < d2.t1; }
68 friend bool operator<=(QDeadlineTimer d1, QDeadlineTimer d2) noexcept
69 { return d1 == d2 || d1 < d2; }
70 friend bool operator>(QDeadlineTimer d1, QDeadlineTimer d2) noexcept
71 { return d2 < d1; }
72 friend bool operator>=(QDeadlineTimer d1, QDeadlineTimer d2) noexcept
73 { return !(d1 < d2); }
74
75 friend Q_CORE_EXPORT QDeadlineTimer operator+(QDeadlineTimer dt, qint64 msecs);
76 friend QDeadlineTimer operator+(qint64 msecs, QDeadlineTimer dt)
77 { return dt + msecs; }
78 friend QDeadlineTimer operator-(QDeadlineTimer dt, qint64 msecs)
79 { return dt + (-msecs); }
80 friend qint64 operator-(QDeadlineTimer dt1, QDeadlineTimer dt2)
81 { return (dt1.deadlineNSecs() - dt2.deadlineNSecs()) / (1000 * 1000); }
82 QDeadlineTimer &operator+=(qint64 msecs)
83 { *this = *this + msecs; return *this; }
84 QDeadlineTimer &operator-=(qint64 msecs)
85 { *this = *this + (-msecs); return *this; }
86
87 template <class Clock, class Duration = typename Clock::duration>
88 QDeadlineTimer(std::chrono::time_point<Clock, Duration> deadline_,
89 Qt::TimerType type_ = Qt::CoarseTimer) : t2(0)
90 { setDeadline(deadline_, type_); }
91 template <class Clock, class Duration = typename Clock::duration>
92 QDeadlineTimer &operator=(std::chrono::time_point<Clock, Duration> deadline_)
93 { setDeadline(deadline_); return *this; }
94
95 template <class Clock, class Duration = typename Clock::duration>
96 void setDeadline(std::chrono::time_point<Clock, Duration> tp,
97 Qt::TimerType type_ = Qt::CoarseTimer);
98
99 template <class Clock, class Duration = typename Clock::duration>
100 std::chrono::time_point<Clock, Duration> deadline() const;
101
102 template <class Rep, class Period>
103 QDeadlineTimer(std::chrono::duration<Rep, Period> remaining, Qt::TimerType type_ = Qt::CoarseTimer)
104 : t2(0)
105 { setRemainingTime(remaining, type_); }
106
107 template <class Rep, class Period>
108 QDeadlineTimer &operator=(std::chrono::duration<Rep, Period> remaining)
109 { setRemainingTime(remaining); return *this; }
110
111 template <class Rep, class Period>
112 void setRemainingTime(std::chrono::duration<Rep, Period> remaining, Qt::TimerType type_ = Qt::CoarseTimer)
113 {
114 using namespace std::chrono;
115 if (remaining == remaining.max())
116 *this = QDeadlineTimer(Forever, type_);
117 else
118 setPreciseRemainingTime(secs: 0, nsecs: ceil<nanoseconds>(remaining).count(), type: type_);
119 }
120
121 std::chrono::nanoseconds remainingTimeAsDuration() const noexcept
122 {
123 if (isForever())
124 return std::chrono::nanoseconds::max();
125 qint64 nsecs = rawRemainingTimeNSecs();
126 if (nsecs <= 0)
127 return std::chrono::nanoseconds::zero();
128 return std::chrono::nanoseconds(nsecs);
129 }
130
131 template <class Rep, class Period>
132 friend QDeadlineTimer operator+(QDeadlineTimer dt, std::chrono::duration<Rep, Period> value)
133 { return QDeadlineTimer::addNSecs(dt, nsecs: std::chrono::duration_cast<std::chrono::nanoseconds>(value).count()); }
134 template <class Rep, class Period>
135 friend QDeadlineTimer operator+(std::chrono::duration<Rep, Period> value, QDeadlineTimer dt)
136 { return dt + value; }
137 template <class Rep, class Period>
138 friend QDeadlineTimer operator+=(QDeadlineTimer &dt, std::chrono::duration<Rep, Period> value)
139 { return dt = dt + value; }
140
141private:
142 qint64 t1 = 0;
143#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
144 unsigned t2 = 0;
145#endif
146 unsigned type = Qt::CoarseTimer;
147
148 qint64 rawRemainingTimeNSecs() const noexcept;
149};
150
151template<class Clock, class Duration>
152std::chrono::time_point<Clock, Duration> QDeadlineTimer::deadline() const
153{
154 using namespace std::chrono;
155 if constexpr (std::is_same_v<Clock, steady_clock>) {
156 auto val = duration_cast<Duration>(nanoseconds(deadlineNSecs()));
157 return time_point<Clock, Duration>(val);
158 } else {
159 auto val = nanoseconds(rawRemainingTimeNSecs()) + Clock::now();
160 return time_point_cast<Duration>(val);
161 }
162}
163
164template<class Clock, class Duration>
165void QDeadlineTimer::setDeadline(std::chrono::time_point<Clock, Duration> tp, Qt::TimerType type_)
166{
167 using namespace std::chrono;
168 if (tp == tp.max()) {
169 *this = Forever;
170 type = type_;
171 } else if constexpr (std::is_same_v<Clock, steady_clock>) {
172 setPreciseDeadline(secs: 0,
173 nsecs: duration_cast<nanoseconds>(tp.time_since_epoch()).count(),
174 type: type_);
175 } else {
176 setPreciseRemainingTime(secs: 0, nsecs: duration_cast<nanoseconds>(tp - Clock::now()).count(), type: type_);
177 }
178}
179
180Q_DECLARE_SHARED(QDeadlineTimer)
181
182QT_END_NAMESPACE
183
184QT_DECL_METATYPE_EXTERN(QDeadlineTimer, Q_CORE_EXPORT)
185
186#endif // QDEADLINETIMER_H
187

source code of qtbase/src/corelib/kernel/qdeadlinetimer.h