1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 Intel Corporation.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qdeadlinetimer.h"
41 #include "qdeadlinetimer_p.h"
42 #include "private/qnumeric_p.h"
43
44 QT_BEGIN_NAMESPACE
45
46 namespace {
47 class TimeReference
48 {
49 enum : unsigned {
50 umega = 1000 * 1000,
51 ugiga = umega * 1000
52 };
53
54 enum : qint64 {
55 kilo = 1000,
56 mega = kilo * 1000,
57 giga = mega * 1000
58 };
59
60 public:
61 enum RoundingStrategy {
62 RoundDown,
63 RoundUp,
64 RoundDefault = RoundDown
65 };
66
67 static constexpr qint64 Min = std::numeric_limits<qint64>::min();
68 static constexpr qint64 Max = std::numeric_limits<qint64>::max();
69
70 inline TimeReference(qint64 = 0, unsigned = 0);
71 inline void updateTimer(qint64 &, unsigned &);
72
73 inline bool addNanoseconds(qint64);
74 inline bool addMilliseconds(qint64);
75 bool addSecsAndNSecs(qint64, qint64);
76
77 inline bool subtract(const qint64, const unsigned);
78
79 inline bool toMilliseconds(qint64 *, RoundingStrategy = RoundDefault) const;
80 inline bool toNanoseconds(qint64 *) const;
81
82 inline void saturate(bool toMax);
83 static bool sign(qint64, qint64);
84
85 private:
86 bool adjust(const qint64, const unsigned, qint64 = 0);
87
88 private:
89 qint64 secs;
90 unsigned nsecs;
91 };
92 }
93
TimeReference(qint64 t1,unsigned t2)94 inline TimeReference::TimeReference(qint64 t1, unsigned t2)
95 : secs(t1), nsecs(t2)
96 {
97 }
98
updateTimer(qint64 & t1,unsigned & t2)99 inline void TimeReference::updateTimer(qint64 &t1, unsigned &t2)
100 {
101 t1 = secs;
102 t2 = nsecs;
103 }
104
saturate(bool toMax)105 inline void TimeReference::saturate(bool toMax)
106 {
107 secs = toMax ? Max : Min;
108 }
109
110 /*!
111 * \internal
112 *
113 * Determines the sign of a (seconds, nanoseconds) pair
114 * for differentiating overflow from underflow. It doesn't
115 * deal with equality as it shouldn't ever be called in that case.
116 *
117 * Returns true if the pair represents a positive time offset
118 * false otherwise.
119 */
sign(qint64 secs,qint64 nsecs)120 bool TimeReference::sign(qint64 secs, qint64 nsecs)
121 {
122 if (secs > 0) {
123 if (nsecs > 0)
124 return true;
125 } else {
126 if (nsecs < 0)
127 return false;
128 }
129
130 // They are different in sign
131 secs += nsecs / giga;
132 if (secs > 0)
133 return true;
134 else if (secs < 0)
135 return false;
136
137 // We should never get over|underflow out of
138 // the case: secs * giga == -nsecs
139 // So the sign of nsecs is the deciding factor
140 Q_ASSERT(nsecs % giga != 0);
141 return nsecs > 0;
142 }
143
144 #if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
addNanoseconds(qint64 arg)145 inline bool TimeReference::addNanoseconds(qint64 arg)
146 {
147 return addSecsAndNSecs(arg / giga, arg % giga);
148 }
149
addMilliseconds(qint64 arg)150 inline bool TimeReference::addMilliseconds(qint64 arg)
151 {
152 return addSecsAndNSecs(arg / kilo, (arg % kilo) * mega);
153 }
154
155 /*!
156 * \internal
157 *
158 * Adds \a t1 addSecs seconds and \a addNSecs nanoseconds to the
159 * time reference. The arguments are normalized to seconds (qint64)
160 * and nanoseconds (unsigned) before the actual calculation is
161 * delegated to adjust(). If the nanoseconds are negative the
162 * owed second used for the normalization is passed on to adjust()
163 * as third argument.
164 *
165 * Returns true if operation was successful, false on over|underflow
166 */
addSecsAndNSecs(qint64 addSecs,qint64 addNSecs)167 bool TimeReference::addSecsAndNSecs(qint64 addSecs, qint64 addNSecs)
168 {
169 // Normalize the arguments
170 if (qAbs(addNSecs) >= giga) {
171 if (add_overflow<qint64>(addSecs, addNSecs / giga, &addSecs))
172 return false;
173
174 addNSecs %= giga;
175 }
176
177 if (addNSecs < 0)
178 return adjust(addSecs, ugiga - unsigned(-addNSecs), -1);
179
180 return adjust(addSecs, unsigned(addNSecs));
181 }
182
183 /*!
184 * \internal
185 *
186 * Adds \a t1 seconds and \a t2 nanoseconds to the internal members.
187 * Takes into account the additional \a carrySeconds we may owe or need to carry over.
188 *
189 * Returns true if operation was successful, false on over|underflow
190 */
adjust(const qint64 t1,const unsigned t2,qint64 carrySeconds)191 bool TimeReference::adjust(const qint64 t1, const unsigned t2, qint64 carrySeconds)
192 {
193 Q_STATIC_ASSERT(QDeadlineTimerNanosecondsInT2);
194 nsecs += t2;
195 if (nsecs >= ugiga) {
196 nsecs -= ugiga;
197 carrySeconds++;
198 }
199
200 // We don't worry about the order of addition, because the result returned by
201 // callers of this function is unchanged regardless of us over|underflowing.
202 // If we do, we do so by no more than a second, thus saturating the timer to
203 // Forever has the same effect as if we did the arithmetic exactly and salvaged
204 // the overflow.
205 return !add_overflow<qint64>(secs, t1, &secs) && !add_overflow<qint64>(secs, carrySeconds, &secs);
206 }
207
208 /*!
209 * \internal
210 *
211 * Subtracts \a t1 seconds and \a t2 nanoseconds from the time reference.
212 * When normalizing the nanoseconds to a positive number the owed seconds is
213 * passed as third argument to adjust() as the seconds may over|underflow
214 * if we do the calculation directly. There is little sense to check the
215 * seconds for over|underflow here in case we are going to need to carry
216 * over a second _after_ we add the nanoseconds.
217 *
218 * Returns true if operation was successful, false on over|underflow
219 */
subtract(const qint64 t1,const unsigned t2)220 inline bool TimeReference::subtract(const qint64 t1, const unsigned t2)
221 {
222 Q_ASSERT(t2 < ugiga);
223 return adjust(-t1, ugiga - t2, -1);
224 }
225
226 /*!
227 * \internal
228 *
229 * Converts the time reference to milliseconds.
230 *
231 * Checks are done without making use of mul_overflow because it may
232 * not be implemented on some 32bit platforms.
233 *
234 * Returns true if operation was successful, false on over|underflow
235 */
toMilliseconds(qint64 * result,RoundingStrategy rounding) const236 inline bool TimeReference::toMilliseconds(qint64 *result, RoundingStrategy rounding) const
237 {
238 static constexpr qint64 maxSeconds = Max / kilo;
239 static constexpr qint64 minSeconds = Min / kilo;
240 if (secs > maxSeconds || secs < minSeconds)
241 return false;
242
243 unsigned ns = rounding == RoundDown ? nsecs : nsecs + umega - 1;
244
245 return !add_overflow<qint64>(secs * kilo, ns / umega, result);
246 }
247
248 /*!
249 * \internal
250 *
251 * Converts the time reference to nanoseconds.
252 *
253 * Checks are done without making use of mul_overflow because it may
254 * not be implemented on some 32bit platforms.
255 *
256 * Returns true if operation was successful, false on over|underflow
257 */
toNanoseconds(qint64 * result) const258 inline bool TimeReference::toNanoseconds(qint64 *result) const
259 {
260 static constexpr qint64 maxSeconds = Max / giga;
261 static constexpr qint64 minSeconds = Min / giga;
262 if (secs > maxSeconds || secs < minSeconds)
263 return false;
264
265 return !add_overflow<qint64>(secs * giga, nsecs, result);
266 }
267 #else
addNanoseconds(qint64 arg)268 inline bool TimeReference::addNanoseconds(qint64 arg)
269 {
270 return adjust(arg, 0);
271 }
272
addMilliseconds(qint64 arg)273 inline bool TimeReference::addMilliseconds(qint64 arg)
274 {
275 static constexpr qint64 maxMilliseconds = Max / mega;
276 if (qAbs(arg) > maxMilliseconds)
277 return false;
278
279 return addNanoseconds(arg * mega);
280 }
281
addSecsAndNSecs(qint64 addSecs,qint64 addNSecs)282 inline bool TimeReference::addSecsAndNSecs(qint64 addSecs, qint64 addNSecs)
283 {
284 static constexpr qint64 maxSeconds = Max / giga;
285 static constexpr qint64 minSeconds = Min / giga;
286 if (addSecs > maxSeconds || addSecs < minSeconds || add_overflow<qint64>(addSecs * giga, addNSecs, &addNSecs))
287 return false;
288
289 return addNanoseconds(addNSecs);
290 }
291
adjust(const qint64 t1,const unsigned t2,qint64 carrySeconds)292 inline bool TimeReference::adjust(const qint64 t1, const unsigned t2, qint64 carrySeconds)
293 {
294 Q_STATIC_ASSERT(!QDeadlineTimerNanosecondsInT2);
295 Q_UNUSED(t2);
296 Q_UNUSED(carrySeconds);
297
298 return !add_overflow<qint64>(secs, t1, &secs);
299 }
300
subtract(const qint64 t1,const unsigned t2)301 inline bool TimeReference::subtract(const qint64 t1, const unsigned t2)
302 {
303 Q_UNUSED(t2);
304
305 return addNanoseconds(-t1);
306 }
307
toMilliseconds(qint64 * result,RoundingStrategy rounding) const308 inline bool TimeReference::toMilliseconds(qint64 *result, RoundingStrategy rounding) const
309 {
310 // Force QDeadlineTimer to treat the border cases as
311 // over|underflow and saturate the results returned to the user.
312 // We don't want to get valid milliseconds out of saturated timers.
313 if (secs == Max || secs == Min)
314 return false;
315
316 *result = secs / mega;
317 if (rounding == RoundUp && secs > *result * mega)
318 (*result)++;
319
320 return true;
321 }
322
toNanoseconds(qint64 * result) const323 inline bool TimeReference::toNanoseconds(qint64 *result) const
324 {
325 *result = secs;
326 return true;
327 }
328 #endif
329
330 /*!
331 \class QDeadlineTimer
332 \inmodule QtCore
333 \brief The QDeadlineTimer class marks a deadline in the future.
334 \since 5.8
335
336 \reentrant
337 \ingroup tools
338
339 The QDeadlineTimer class is usually used to calculate future deadlines and
340 verify whether the deadline has expired. QDeadlineTimer can also be used
341 for deadlines without expiration ("forever"). It forms a counterpart to
342 QElapsedTimer, which calculates how much time has elapsed since
343 QElapsedTimer::start() was called.
344
345 QDeadlineTimer provides a more convenient API compared to
346 QElapsedTimer::hasExpired().
347
348 The typical use-case for the class is to create a QDeadlineTimer before the
349 operation in question is started, and then use remainingTime() or
350 hasExpired() to determine whether to continue trying the operation.
351 QDeadlineTimer objects can be passed to functions being called to execute
352 this operation so they know how long to still operate.
353
354 \snippet code/src_corelib_kernel_qdeadlinetimer.cpp 0
355
356 Many QDeadlineTimer functions deal with time out values, which all are
357 measured in milliseconds. There are two special values, the same as many
358 other Qt functions named \c{waitFor} or similar:
359
360 \list
361 \li 0: no time left, expired
362 \li -1: infinite time left, timer never expires
363 \endlist
364
365 \section1 Reference Clocks
366
367 QDeadlineTimer will use the same clock as QElapsedTimer (see
368 QElapsedTimer::clockType() and QElapsedTimer::isMonotonic()).
369
370 \section1 Timer types
371
372 Like QTimer, QDeadlineTimer can select among different levels of coarseness
373 on the timers. You can select precise timing by passing Qt::PreciseTimer to
374 the functions that set of change the timer, or you can select coarse timing
375 by passing Qt::CoarseTimer. Qt::VeryCoarseTimer is currently interpreted
376 the same way as Qt::CoarseTimer.
377
378 This feature is dependent on support from the operating system: if the OS
379 does not support a coarse timer functionality, then QDeadlineTimer will
380 behave like Qt::PreciseTimer was passed.
381
382 QDeadlineTimer defaults to Qt::CoarseTimer because on operating systems
383 that do support coarse timing, making timing calls to that clock source is
384 often much more efficient. The level of coarseness depends on the
385 operating system, but should be in the order of a couple of milliseconds.
386
387 \section1 \c{std::chrono} Compatibility
388
389 QDeadlineTimer is compatible with the \c{std::chrono} API from C++11 and
390 can be constructed from or compared to both \c{std::chrono::duration} and
391 \c{std::chrono::time_point} objects. In addition, it is fully compatible
392 with the time literals from C++14, which allow one to write code as:
393
394 \snippet code/src_corelib_kernel_qdeadlinetimer.cpp 1
395
396 As can be seen in the example above, QDeadlineTimer offers a templated
397 version of remainingTime() and deadline() that can be used to return
398 \c{std::chrono} objects.
399
400 Note that comparing to \c{time_point} is not as efficient as comparing to
401 \c{duration}, since QDeadlineTimer may need to convert from its own
402 internal clock source to the clock source used by the \c{time_point} object.
403 Also note that, due to this conversion, the deadlines will not be precise,
404 so the following code is not expected to compare equally:
405
406 \snippet code/src_corelib_kernel_qdeadlinetimer.cpp 2
407
408 \sa QTime, QTimer, QDeadlineTimer, Qt::TimerType
409 */
410
411 /*!
412 \enum QDeadlineTimer::ForeverConstant
413
414 \value Forever Used when creating a QDeadlineTimer to indicate the
415 deadline should not expire
416 */
417
418 /*!
419 \fn QDeadlineTimer::QDeadlineTimer(Qt::TimerType timerType)
420
421 Constructs an expired QDeadlineTimer object. For this object,
422 remainingTime() will return 0.
423
424 The timer type \a timerType may be ignored, since the timer is already
425 expired. Similarly, for optimization purposes, this function will not
426 attempt to obtain the current time and will use a value known to be in the
427 past. Therefore, deadline() may return an unexpected value and this object
428 cannot be used in calculation of how long it is overdue. If that
429 functionality is required, use QDeadlineTimer::current().
430
431 \sa hasExpired(), remainingTime(), Qt::TimerType, current()
432 */
433
434 /*!
435 \fn QDeadlineTimer::QDeadlineTimer(ForeverConstant, Qt::TimerType timerType)
436
437 QDeadlineTimer objects created with ForeverConstant never expire.
438 For such objects, remainingTime() will return -1, deadline() will return the
439 maximum value, and isForever() will return true.
440
441 The timer type \a timerType may be ignored, since the timer will never
442 expire.
443
444 \sa ForeverConstant, hasExpired(), isForever(), remainingTime(), timerType()
445 */
446
447 /*!
448 Constructs a QDeadlineTimer object with an expiry time of \a msecs msecs
449 from the moment of the creation of this object, if msecs is positive. If \a
450 msecs is zero, this QDeadlineTimer will be marked as expired, causing
451 remainingTime() to return zero and deadline() to return an indeterminate
452 time point in the past. If \a msecs is -1, the timer will be set to never
453 expire, causing remainingTime() to return -1 and deadline() to return the
454 maximum value.
455
456 The QDeadlineTimer object will be constructed with the specified timer \a type.
457
458 For optimization purposes, if \a msecs is zero, this function may skip
459 obtaining the current time and may instead use a value known to be in the
460 past. If that happens, deadline() may return an unexpected value and this
461 object cannot be used in calculation of how long it is overdue. If that
462 functionality is required, use QDeadlineTimer::current() and add time to
463 it.
464
465 \sa hasExpired(), isForever(), remainingTime(), setRemainingTime()
466 */
QDeadlineTimer(qint64 msecs,Qt::TimerType type)467 QDeadlineTimer::QDeadlineTimer(qint64 msecs, Qt::TimerType type) noexcept
468 : t2(0)
469 {
470 setRemainingTime(msecs, type);
471 }
472
473 /*!
474 \fn template <class Clock, class Duration> QDeadlineTimer::QDeadlineTimer(std::chrono::time_point<Clock, Duration> deadline, Qt::TimerType type)
475
476 Constructs a QDeadlineTimer object with a deadline at \a deadline time
477 point, converting from the clock source \c{Clock} to Qt's internal clock
478 source (see QElapsedTimer::clockType()).
479
480 If \a deadline is in the past, this QDeadlineTimer object is set to
481 expired, whereas if \a deadline is equal to \c{Duration::max()}, then this
482 object is set to never expire.
483
484 The QDeadlineTimer object will be constructed with the specified timer \a type.
485
486 \sa hasExpired(), isForever(), remainingTime(), setDeadline()
487 */
488
489 /*!
490 \fn template <class Rep, class Period> QDeadlineTimer::QDeadlineTimer(std::chrono::duration<Rep, Period> remaining, Qt::TimerType type)
491
492 Constructs a QDeadlineTimer object with a remaining time of \a remaining.
493 If \a remaining is zero or negative, this QDeadlineTimer object will be
494 mark as expired, whereas if \a remaining is equal to \c{duration::max()},
495 the object will be set to never expire.
496
497 The QDeadlineTimer object will be constructed with the specified timer \a type.
498
499 This constructor can be used with C++14's user-defined literals for time, such as in:
500
501 \snippet code/src_corelib_kernel_qdeadlinetimer.cpp 3
502
503 For optimization purposes, if \a remaining is zero or negative, this
504 function may skip obtaining the current time and may instead use a value
505 known to be in the past. If that happens, deadline() may return an
506 unexpected value and this object cannot be used in calculation of how long
507 it is overdue. If that functionality is required, use
508 QDeadlineTimer::current() and add time to it.
509
510 \sa hasExpired(), isForever(), remainingTime(), setRemainingTime()
511 */
512
513 /*!
514 \fn template <class Clock, class Duration> void QDeadlineTimer::setDeadline(std::chrono::time_point<Clock, Duration> deadline, Qt::TimerType type)
515
516 Sets this QDeadlineTimer to the deadline marked by \a deadline time
517 point, converting from the clock source \c{Clock} to Qt's internal clock
518 source (see QElapsedTimer::clockType()).
519
520 If \a deadline is in the past, this QDeadlineTimer object is set to
521 expired, whereas if \a deadline is equal to \c{Duration::max()}, then this
522 object is set to never expire.
523
524 The timer type for this QDeadlineTimer object will be set to the specified \a type.
525
526 \sa hasExpired(), isForever(), remainingTime(),
527 */
528
529 /*!
530 Sets the remaining time for this QDeadlineTimer object to \a msecs
531 milliseconds from now, if \a msecs has a positive value. If \a msecs is
532 zero, this QDeadlineTimer object will be marked as expired, whereas a value
533 of -1 will set it to never expire.
534
535 The timer type for this QDeadlineTimer object will be set to the specified \a timerType.
536
537 \sa setPreciseRemainingTime(), hasExpired(), isForever(), remainingTime()
538 */
setRemainingTime(qint64 msecs,Qt::TimerType timerType)539 void QDeadlineTimer::setRemainingTime(qint64 msecs, Qt::TimerType timerType) noexcept
540 {
541 if (msecs == -1) {
542 *this = QDeadlineTimer(Forever, timerType);
543 return;
544 }
545
546 *this = current(timerType);
547
548 TimeReference ref(t1, t2);
549 if (!ref.addMilliseconds(msecs))
550 ref.saturate(msecs > 0);
551 ref.updateTimer(t1, t2);
552 }
553
554 /*!
555 Sets the remaining time for this QDeadlineTimer object to \a secs seconds
556 plus \a nsecs nanoseconds from now, if \a secs has a positive value. If \a
557 secs is -1, this QDeadlineTimer will be set it to never expire. If both
558 parameters are zero, this QDeadlineTimer will be marked as expired.
559
560 The timer type for this QDeadlineTimer object will be set to the specified
561 \a timerType.
562
563 \sa setRemainingTime(), hasExpired(), isForever(), remainingTime()
564 */
setPreciseRemainingTime(qint64 secs,qint64 nsecs,Qt::TimerType timerType)565 void QDeadlineTimer::setPreciseRemainingTime(qint64 secs, qint64 nsecs, Qt::TimerType timerType) noexcept
566 {
567 if (secs == -1) {
568 *this = QDeadlineTimer(Forever, timerType);
569 return;
570 }
571
572 *this = current(timerType);
573 TimeReference ref(t1, t2);
574 if (!ref.addSecsAndNSecs(secs, nsecs))
575 ref.saturate(TimeReference::sign(secs, nsecs));
576 ref.updateTimer(t1, t2);
577 }
578
579 /*!
580 \overload
581 \fn template <class Rep, class Period> void QDeadlineTimer::setRemainingTime(std::chrono::duration<Rep, Period> remaining, Qt::TimerType type)
582
583 Sets the remaining time for this QDeadlineTimer object to \a remaining. If
584 \a remaining is zero or negative, this QDeadlineTimer object will be mark
585 as expired, whereas if \a remaining is equal to \c{duration::max()}, the
586 object will be set to never expire.
587
588 The timer type for this QDeadlineTimer object will be set to the specified \a type.
589
590 This function can be used with C++14's user-defined literals for time, such as in:
591
592 \snippet code/src_corelib_kernel_qdeadlinetimer.cpp 4
593
594 \note Qt detects the necessary C++14 compiler support by way of the feature
595 test recommendations from
596 \l{https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations}
597 {C++ Committee's Standing Document 6}.
598
599 \sa setDeadline(), remainingTime(), hasExpired(), isForever()
600 */
601
602 /*!
603 \fn bool QDeadlineTimer::isForever() const
604
605 Returns true if this QDeadlineTimer object never expires, false otherwise.
606 For timers that never expire, remainingTime() always returns -1 and
607 deadline() returns the maximum value.
608
609 \sa ForeverConstant, hasExpired(), remainingTime()
610 */
611
612 /*!
613 Returns true if this QDeadlineTimer object has expired, false if there
614 remains time left. For objects that have expired, remainingTime() will
615 return zero and deadline() will return a time point in the past.
616
617 QDeadlineTimer objects created with the \l {ForeverConstant} never expire
618 and this function always returns false for them.
619
620 \sa isForever(), remainingTime()
621 */
hasExpired() const622 bool QDeadlineTimer::hasExpired() const noexcept
623 {
624 if (isForever())
625 return false;
626 return *this <= current(timerType());
627 }
628
629 /*!
630 \fn Qt::TimerType QDeadlineTimer::timerType() const
631
632 Returns the timer type is active for this object.
633
634 \sa setTimerType()
635 */
636
637 /*!
638 Changes the timer type for this object to \a timerType.
639
640 The behavior for each possible value of \a timerType is operating-system
641 dependent. Qt::PreciseTimer will use the most precise timer that Qt can
642 find, with resolution of 1 millisecond or better, whereas QDeadlineTimer
643 will try to use a more coarse timer for Qt::CoarseTimer and
644 Qt::VeryCoarseTimer.
645
646 \sa Qt::TimerType
647 */
setTimerType(Qt::TimerType timerType)648 void QDeadlineTimer::setTimerType(Qt::TimerType timerType)
649 {
650 type = timerType;
651 }
652
653 /*!
654 Returns the remaining time in this QDeadlineTimer object in milliseconds.
655 If the timer has already expired, this function will return zero and it is
656 not possible to obtain the amount of time overdue with this function (to do
657 that, see deadline()). If the timer was set to never expire, this function
658 returns -1.
659
660 This function is suitable for use in Qt APIs that take a millisecond
661 timeout, such as the many \l QIODevice \c waitFor functions or the timed
662 lock functions in \l QMutex, \l QWaitCondition, \l QSemaphore, or
663 \l QReadWriteLock. For example:
664
665 \snippet code/src_corelib_kernel_qdeadlinetimer.cpp 5
666
667 \sa remainingTimeNSecs(), isForever(), hasExpired()
668 */
remainingTime() const669 qint64 QDeadlineTimer::remainingTime() const noexcept
670 {
671 if (isForever())
672 return -1;
673
674 QDeadlineTimer now = current(timerType());
675 TimeReference ref(t1, t2);
676
677 qint64 msecs;
678 if (!ref.subtract(now.t1, now.t2))
679 return 0; // We can only underflow here
680
681 // If we fail the conversion, t1 < now.t1 means we underflowed,
682 // thus the deadline had long expired
683 if (!ref.toMilliseconds(&msecs, TimeReference::RoundUp))
684 return t1 < now.t1 ? 0 : -1;
685
686 return msecs < 0 ? 0 : msecs;
687 }
688
689 /*!
690 Returns the remaining time in this QDeadlineTimer object in nanoseconds. If
691 the timer has already expired, this function will return zero and it is not
692 possible to obtain the amount of time overdue with this function. If the
693 timer was set to never expire, this function returns -1.
694
695 \sa remainingTime(), isForever(), hasExpired()
696 */
remainingTimeNSecs() const697 qint64 QDeadlineTimer::remainingTimeNSecs() const noexcept
698 {
699 if (isForever())
700 return -1;
701 qint64 raw = rawRemainingTimeNSecs();
702 return raw < 0 ? 0 : raw;
703 }
704
705 /*!
706 \internal
707 Same as remainingTimeNSecs, but may return negative remaining times. Does
708 not deal with Forever. In case of underflow the result is saturated to
709 the minimum possible value, on overflow - the maximum possible value.
710 */
rawRemainingTimeNSecs() const711 qint64 QDeadlineTimer::rawRemainingTimeNSecs() const noexcept
712 {
713 QDeadlineTimer now = current(timerType());
714 TimeReference ref(t1, t2);
715
716 qint64 nsecs;
717 if (!ref.subtract(now.t1, now.t2))
718 return TimeReference::Min; // We can only underflow here
719
720 // If we fail the conversion, t1 < now.t1 means we underflowed,
721 // thus the deadline had long expired
722 if (!ref.toNanoseconds(&nsecs))
723 return t1 < now.t1 ? TimeReference::Min : TimeReference::Max;
724 return nsecs;
725 }
726
727 /*!
728 Returns the absolute time point for the deadline stored in QDeadlineTimer
729 object, calculated in milliseconds relative to the reference clock, the
730 same as QElapsedTimer::msecsSinceReference(). The value will be in the past
731 if this QDeadlineTimer has expired.
732
733 If this QDeadlineTimer never expires, this function returns
734 \c{std::numeric_limits<qint64>::max()}.
735
736 This function can be used to calculate the amount of time a timer is
737 overdue, by subtracting QDeadlineTimer::current() or
738 QElapsedTimer::msecsSinceReference(), as in the following example:
739
740 \snippet code/src_corelib_kernel_qdeadlinetimer.cpp 6
741
742 \note Timers that were created as expired have an indetermine time point in
743 the past as their deadline, so the above calculation may not work.
744
745 \sa remainingTime(), deadlineNSecs(), setDeadline()
746 */
deadline() const747 qint64 QDeadlineTimer::deadline() const noexcept
748 {
749 if (isForever())
750 return TimeReference::Max;
751
752 qint64 result;
753 if (!TimeReference(t1, t2).toMilliseconds(&result))
754 return t1 < 0 ? TimeReference::Min : TimeReference::Max;
755
756 return result;
757 }
758
759 /*!
760 Returns the absolute time point for the deadline stored in QDeadlineTimer
761 object, calculated in nanoseconds relative to the reference clock, the
762 same as QElapsedTimer::msecsSinceReference(). The value will be in the past
763 if this QDeadlineTimer has expired.
764
765 If this QDeadlineTimer never expires or the number of nanoseconds until the
766 deadline can't be accommodated in the return type, this function returns
767 \c{std::numeric_limits<qint64>::max()}.
768
769 This function can be used to calculate the amount of time a timer is
770 overdue, by subtracting QDeadlineTimer::current(), as in the following
771 example:
772
773 \snippet code/src_corelib_kernel_qdeadlinetimer.cpp 7
774
775 \note Timers that were created as expired have an indetermine time point in
776 the past as their deadline, so the above calculation may not work.
777
778 \sa remainingTime(), deadlineNSecs()
779 */
deadlineNSecs() const780 qint64 QDeadlineTimer::deadlineNSecs() const noexcept
781 {
782 if (isForever())
783 return TimeReference::Max;
784
785 qint64 result;
786 if (!TimeReference(t1, t2).toNanoseconds(&result))
787 return t1 < 0 ? TimeReference::Min : TimeReference::Max;
788
789 return result;
790 }
791
792 /*!
793 Sets the deadline for this QDeadlineTimer object to be the \a msecs
794 absolute time point, counted in milliseconds since the reference clock (the
795 same as QElapsedTimer::msecsSinceReference()), and the timer type to \a
796 timerType. If the value is in the past, this QDeadlineTimer will be marked
797 as expired.
798
799 If \a msecs is \c{std::numeric_limits<qint64>::max()} or the deadline is
800 beyond a representable point in the future, this QDeadlineTimer will be set
801 to never expire.
802
803 \sa setPreciseDeadline(), deadline(), deadlineNSecs(), setRemainingTime()
804 */
setDeadline(qint64 msecs,Qt::TimerType timerType)805 void QDeadlineTimer::setDeadline(qint64 msecs, Qt::TimerType timerType) noexcept
806 {
807 if (msecs == TimeReference::Max) {
808 *this = QDeadlineTimer(Forever, timerType);
809 return;
810 }
811
812 type = timerType;
813
814 TimeReference ref;
815 if (!ref.addMilliseconds(msecs))
816 ref.saturate(msecs > 0);
817 ref.updateTimer(t1, t2);
818 }
819
820 /*!
821 Sets the deadline for this QDeadlineTimer object to be \a secs seconds and
822 \a nsecs nanoseconds since the reference clock epoch (the same as
823 QElapsedTimer::msecsSinceReference()), and the timer type to \a timerType.
824 If the value is in the past, this QDeadlineTimer will be marked as expired.
825
826 If \a secs or \a nsecs is \c{std::numeric_limits<qint64>::max()}, this
827 QDeadlineTimer will be set to never expire. If \a nsecs is more than 1
828 billion nanoseconds (1 second), then \a secs will be adjusted accordingly.
829
830 \sa setDeadline(), deadline(), deadlineNSecs(), setRemainingTime()
831 */
setPreciseDeadline(qint64 secs,qint64 nsecs,Qt::TimerType timerType)832 void QDeadlineTimer::setPreciseDeadline(qint64 secs, qint64 nsecs, Qt::TimerType timerType) noexcept
833 {
834 type = timerType;
835
836 // We don't pass the seconds to the constructor, because we don't know
837 // at this point if t1 holds the seconds or nanoseconds; it's platform specific.
838 TimeReference ref;
839 if (!ref.addSecsAndNSecs(secs, nsecs))
840 ref.saturate(TimeReference::sign(secs, nsecs));
841 ref.updateTimer(t1, t2);
842 }
843
844 /*!
845 Returns a QDeadlineTimer object whose deadline is extended from \a dt's
846 deadline by \a nsecs nanoseconds. If \a dt was set to never expire, this
847 function returns a QDeadlineTimer that will not expire either.
848
849 \note if \a dt was created as expired, its deadline is indeterminate and
850 adding an amount of time may or may not cause it to become unexpired.
851 */
addNSecs(QDeadlineTimer dt,qint64 nsecs)852 QDeadlineTimer QDeadlineTimer::addNSecs(QDeadlineTimer dt, qint64 nsecs) noexcept
853 {
854 if (dt.isForever())
855 return dt;
856
857 TimeReference ref(dt.t1, dt.t2);
858 if (!ref.addNanoseconds(nsecs))
859 ref.saturate(nsecs > 0);
860 ref.updateTimer(dt.t1, dt.t2);
861
862 return dt;
863 }
864
865 /*!
866 \fn QDeadlineTimer QDeadlineTimer::current(Qt::TimerType timerType)
867
868 Returns a QDeadlineTimer that is expired but is guaranteed to contain the
869 current time. Objects created by this function can participate in the
870 calculation of how long a timer is overdue, using the deadline() function.
871
872 The QDeadlineTimer object will be constructed with the specified \a timerType.
873 */
874
875 /*!
876 \fn bool operator==(QDeadlineTimer d1, QDeadlineTimer d2)
877 \relates QDeadlineTimer
878
879 Returns true if the deadline on \a d1 and the deadline in \a d2 are the
880 same, false otherwise. The timer type used to create the two deadlines is
881 ignored. This function is equivalent to:
882
883 \snippet code/src_corelib_kernel_qdeadlinetimer.cpp 8
884
885 \note comparing QDeadlineTimer objects with different timer types is
886 not supported and may result in unpredictable behavior.
887 */
888
889 /*!
890 \fn bool operator!=(QDeadlineTimer d1, QDeadlineTimer d2)
891 \relates QDeadlineTimer
892
893 Returns true if the deadline on \a d1 and the deadline in \a d2 are
894 diferent, false otherwise. The timer type used to create the two deadlines
895 is ignored. This function is equivalent to:
896
897 \snippet code/src_corelib_kernel_qdeadlinetimer.cpp 9
898
899 \note comparing QDeadlineTimer objects with different timer types is
900 not supported and may result in unpredictable behavior.
901 */
902
903 /*!
904 \fn bool operator<(QDeadlineTimer d1, QDeadlineTimer d2)
905 \relates QDeadlineTimer
906
907 Returns true if the deadline on \a d1 is earlier than the deadline in \a
908 d2, false otherwise. The timer type used to create the two deadlines is
909 ignored. This function is equivalent to:
910
911 \snippet code/src_corelib_kernel_qdeadlinetimer.cpp 10
912
913 \note comparing QDeadlineTimer objects with different timer types is
914 not supported and may result in unpredictable behavior.
915 */
916
917 /*!
918 \fn bool operator<=(QDeadlineTimer d1, QDeadlineTimer d2)
919 \relates QDeadlineTimer
920
921 Returns true if the deadline on \a d1 is earlier than or the same as the
922 deadline in \a d2, false otherwise. The timer type used to create the two
923 deadlines is ignored. This function is equivalent to:
924
925 \snippet code/src_corelib_kernel_qdeadlinetimer.cpp 11
926
927 \note comparing QDeadlineTimer objects with different timer types is
928 not supported and may result in unpredictable behavior.
929 */
930
931 /*!
932 \fn bool operator>(QDeadlineTimer d1, QDeadlineTimer d2)
933 \relates QDeadlineTimer
934
935 Returns true if the deadline on \a d1 is later than the deadline in \a
936 d2, false otherwise. The timer type used to create the two deadlines is
937 ignored. This function is equivalent to:
938
939 \snippet code/src_corelib_kernel_qdeadlinetimer.cpp 12
940
941 \note comparing QDeadlineTimer objects with different timer types is
942 not supported and may result in unpredictable behavior.
943 */
944
945 /*!
946 \fn bool operator>=(QDeadlineTimer d1, QDeadlineTimer d2)
947 \relates QDeadlineTimer
948
949 Returns true if the deadline on \a d1 is later than or the same as the
950 deadline in \a d2, false otherwise. The timer type used to create the two
951 deadlines is ignored. This function is equivalent to:
952
953 \snippet code/src_corelib_kernel_qdeadlinetimer.cpp 13
954
955 \note comparing QDeadlineTimer objects with different timer types is
956 not supported and may result in unpredictable behavior.
957 */
958
959 /*!
960 \fn QDeadlineTimer operator+(QDeadlineTimer dt, qint64 msecs)
961 \relates QDeadlineTimer
962
963 Returns a QDeadlineTimer object whose deadline is \a msecs later than the
964 deadline stored in \a dt. If \a dt is set to never expire, this function
965 returns a QDeadlineTimer that does not expire either.
966
967 To add times of precision greater than 1 millisecond, use addNSecs().
968 */
969
operator +(QDeadlineTimer dt,qint64 msecs)970 QDeadlineTimer operator+(QDeadlineTimer dt, qint64 msecs)
971 {
972 if (dt.isForever())
973 return dt;
974
975 TimeReference ref(dt.t1, dt.t2);
976 if (!ref.addMilliseconds(msecs))
977 ref.saturate(msecs > 0);
978 ref.updateTimer(dt.t1, dt.t2);
979
980 return dt;
981 }
982
983 /*!
984 \fn QDeadlineTimer operator+(qint64 msecs, QDeadlineTimer dt)
985 \relates QDeadlineTimer
986
987 Returns a QDeadlineTimer object whose deadline is \a msecs later than the
988 deadline stored in \a dt. If \a dt is set to never expire, this function
989 returns a QDeadlineTimer that does not expire either.
990
991 To add times of precision greater than 1 millisecond, use addNSecs().
992 */
993
994 /*!
995 \fn QDeadlineTimer operator-(QDeadlineTimer dt, qint64 msecs)
996 \relates QDeadlineTimer
997
998 Returns a QDeadlineTimer object whose deadline is \a msecs before the
999 deadline stored in \a dt. If \a dt is set to never expire, this function
1000 returns a QDeadlineTimer that does not expire either.
1001
1002 To subtract times of precision greater than 1 millisecond, use addNSecs().
1003 */
1004
1005 /*!
1006 \fn QDeadlineTimer &QDeadlineTimer::operator+=(qint64 msecs)
1007
1008 Extends this QDeadlineTimer object by \a msecs milliseconds and returns
1009 itself. If this object is set to never expire, this function does nothing.
1010
1011 To add times of precision greater than 1 millisecond, use addNSecs().
1012 */
1013
1014 /*!
1015 \fn QDeadlineTimer &QDeadlineTimer::operator-=(qint64 msecs)
1016
1017 Shortens this QDeadlineTimer object by \a msecs milliseconds and returns
1018 itself. If this object is set to never expire, this function does nothing.
1019
1020 To subtract times of precision greater than 1 millisecond, use addNSecs().
1021 */
1022
1023 /*!
1024 \fn void QDeadlineTimer::swap(QDeadlineTimer &other)
1025
1026 Swaps this deadline timer with the \a other deadline timer.
1027 */
1028
1029 /*!
1030 \fn template <class Clock, class Duration> QDeadlineTimer & QDeadlineTimer::operator=(std::chrono::time_point<Clock, Duration> deadline_)
1031
1032 Assigns \a deadline_ to this deadline timer.
1033 */
1034
1035 /*!
1036 \fn template <class Rep, class Period> QDeadlineTimer & QDeadlineTimer::operator=(std::chrono::duration<Rep, Period> remaining)
1037
1038 Sets this deadline timer to the \a remaining time.
1039 */
1040
1041 /*!
1042 \fn std::chrono::nanoseconds QDeadlineTimer::remainingTimeAsDuration() const
1043
1044 Returns the time remaining before the deadline.
1045 */
1046
1047 /*!
1048 \fn QPair<qint64, unsigned> QDeadlineTimer::_q_data() const
1049 \internal
1050 */
1051
1052 // the rest of the functions are in qelapsedtimer_xxx.cpp
1053
1054 QT_END_NAMESPACE
1055