blob: 1155eb526bed989c3d0ee9ee62ac9ccb1ba9f169 [file] [log] [blame]
Sebastian Jansson30bd4032018-04-13 13:56:17 +02001/*
2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Sebastian Jansson6fae6ec2018-05-08 10:43:18 +020011#ifndef API_UNITS_TIME_DELTA_H_
12#define API_UNITS_TIME_DELTA_H_
Sebastian Jansson30bd4032018-04-13 13:56:17 +020013
14#include <stdint.h>
15#include <cmath>
16#include <limits>
17#include <string>
18
19#include "rtc_base/checks.h"
Sebastian Jansson942b3602018-05-30 15:47:44 +020020#include "rtc_base/numerics/safe_conversions.h"
Sebastian Jansson30bd4032018-04-13 13:56:17 +020021
22namespace webrtc {
23namespace timedelta_impl {
24constexpr int64_t kPlusInfinityVal = std::numeric_limits<int64_t>::max();
25constexpr int64_t kMinusInfinityVal = std::numeric_limits<int64_t>::min();
Sebastian Jansson30bd4032018-04-13 13:56:17 +020026} // namespace timedelta_impl
27
28// TimeDelta represents the difference between two timestamps. Commonly this can
29// be a duration. However since two Timestamps are not guaranteed to have the
30// same epoch (they might come from different computers, making exact
31// synchronisation infeasible), the duration covered by a TimeDelta can be
32// undefined. To simplify usage, it can be constructed and converted to
33// different units, specifically seconds (s), milliseconds (ms) and
34// microseconds (us).
35class TimeDelta {
36 public:
Sebastian Jansson3b69b192018-05-07 13:51:51 +020037 TimeDelta() = delete;
Sebastian Jansson8e064192018-08-07 12:34:33 +020038 static constexpr TimeDelta Zero() { return TimeDelta(0); }
39 static constexpr TimeDelta PlusInfinity() {
Sebastian Jansson30bd4032018-04-13 13:56:17 +020040 return TimeDelta(timedelta_impl::kPlusInfinityVal);
41 }
Sebastian Jansson8e064192018-08-07 12:34:33 +020042 static constexpr TimeDelta MinusInfinity() {
Sebastian Jansson30bd4032018-04-13 13:56:17 +020043 return TimeDelta(timedelta_impl::kMinusInfinityVal);
44 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +020045 template <int64_t seconds>
46 static constexpr TimeDelta Seconds() {
47 static_assert(seconds > timedelta_impl::kMinusInfinityVal / 1000000, "");
48 static_assert(seconds < timedelta_impl::kPlusInfinityVal / 1000000, "");
49 return TimeDelta(seconds * 1000000);
50 }
51 template <int64_t ms>
52 static constexpr TimeDelta Millis() {
53 static_assert(ms > timedelta_impl::kMinusInfinityVal / 1000, "");
54 static_assert(ms < timedelta_impl::kPlusInfinityVal / 1000, "");
55 return TimeDelta(ms * 1000);
56 }
57 template <int64_t us>
58 static constexpr TimeDelta Micros() {
59 static_assert(us > timedelta_impl::kMinusInfinityVal, "");
60 static_assert(us < timedelta_impl::kPlusInfinityVal, "");
61 return TimeDelta(us);
62 }
Sebastian Jansson942b3602018-05-30 15:47:44 +020063
64 template <
65 typename T,
66 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
67 static TimeDelta seconds(T seconds) {
68 RTC_DCHECK_GT(seconds, timedelta_impl::kMinusInfinityVal / 1000000);
69 RTC_DCHECK_LT(seconds, timedelta_impl::kPlusInfinityVal / 1000000);
70 return TimeDelta(rtc::dchecked_cast<int64_t>(seconds) * 1000000);
Sebastian Jansson30bd4032018-04-13 13:56:17 +020071 }
Sebastian Jansson942b3602018-05-30 15:47:44 +020072 template <
73 typename T,
74 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
75 static TimeDelta ms(T milliseconds) {
76 RTC_DCHECK_GT(milliseconds, timedelta_impl::kMinusInfinityVal / 1000);
77 RTC_DCHECK_LT(milliseconds, timedelta_impl::kPlusInfinityVal / 1000);
78 return TimeDelta(rtc::dchecked_cast<int64_t>(milliseconds) * 1000);
Sebastian Jansson30bd4032018-04-13 13:56:17 +020079 }
Sebastian Jansson942b3602018-05-30 15:47:44 +020080 template <
81 typename T,
82 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
83 static TimeDelta us(T microseconds) {
84 RTC_DCHECK_GT(microseconds, timedelta_impl::kMinusInfinityVal);
85 RTC_DCHECK_LT(microseconds, timedelta_impl::kPlusInfinityVal);
86 return TimeDelta(rtc::dchecked_cast<int64_t>(microseconds));
Sebastian Jansson5f83cf02018-05-08 14:52:22 +020087 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +020088
Sebastian Jansson942b3602018-05-30 15:47:44 +020089 template <typename T,
90 typename std::enable_if<std::is_floating_point<T>::value>::type* =
91 nullptr>
92 static TimeDelta seconds(T seconds) {
93 return TimeDelta::us(seconds * 1e6);
94 }
95 template <typename T,
96 typename std::enable_if<std::is_floating_point<T>::value>::type* =
97 nullptr>
98 static TimeDelta ms(T milliseconds) {
99 return TimeDelta::us(milliseconds * 1e3);
100 }
101 template <typename T,
102 typename std::enable_if<std::is_floating_point<T>::value>::type* =
103 nullptr>
104 static TimeDelta us(T microseconds) {
105 if (microseconds == std::numeric_limits<T>::infinity()) {
106 return PlusInfinity();
107 } else if (microseconds == -std::numeric_limits<T>::infinity()) {
108 return MinusInfinity();
109 } else {
110 RTC_DCHECK(!std::isnan(microseconds));
111 RTC_DCHECK_GT(microseconds, timedelta_impl::kMinusInfinityVal);
112 RTC_DCHECK_LT(microseconds, timedelta_impl::kPlusInfinityVal);
113 return TimeDelta(rtc::dchecked_cast<int64_t>(microseconds));
114 }
115 }
116
117 template <typename T = int64_t>
118 typename std::enable_if<std::is_integral<T>::value, T>::type seconds() const {
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200119 RTC_DCHECK(IsFinite());
120 return rtc::dchecked_cast<T>(UnsafeSeconds());
Sebastian Jansson942b3602018-05-30 15:47:44 +0200121 }
122 template <typename T = int64_t>
123 typename std::enable_if<std::is_integral<T>::value, T>::type ms() const {
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200124 RTC_DCHECK(IsFinite());
125 return rtc::dchecked_cast<T>(UnsafeMillis());
Sebastian Jansson942b3602018-05-30 15:47:44 +0200126 }
127 template <typename T = int64_t>
128 typename std::enable_if<std::is_integral<T>::value, T>::type us() const {
129 RTC_DCHECK(IsFinite());
130 return rtc::dchecked_cast<T>(microseconds_);
131 }
132 template <typename T = int64_t>
133 typename std::enable_if<std::is_integral<T>::value, T>::type ns() const {
134 RTC_DCHECK_GE(us(), std::numeric_limits<T>::min() / 1000);
135 RTC_DCHECK_LE(us(), std::numeric_limits<T>::max() / 1000);
136 return rtc::dchecked_cast<T>(us() * 1000);
137 }
138
139 template <typename T>
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200140 constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
141 seconds() const {
Sebastian Jansson942b3602018-05-30 15:47:44 +0200142 return us<T>() * 1e-6;
143 }
144 template <typename T>
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200145 constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
146 ms() const {
Sebastian Jansson942b3602018-05-30 15:47:44 +0200147 return us<T>() * 1e-3;
148 }
149 template <typename T>
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200150 constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
151 us() const {
152 return IsPlusInfinity()
153 ? std::numeric_limits<T>::infinity()
154 : IsMinusInfinity() ? -std::numeric_limits<T>::infinity()
155 : microseconds_;
Sebastian Jansson942b3602018-05-30 15:47:44 +0200156 }
157 template <typename T>
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200158 constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
159 ns() const {
Sebastian Jansson942b3602018-05-30 15:47:44 +0200160 return us<T>() * 1e3;
161 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200162
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200163 constexpr int64_t seconds_or(int64_t fallback_value) const {
164 return IsFinite() ? UnsafeSeconds() : fallback_value;
165 }
166 constexpr int64_t ms_or(int64_t fallback_value) const {
167 return IsFinite() ? UnsafeMillis() : fallback_value;
168 }
169 constexpr int64_t us_or(int64_t fallback_value) const {
170 return IsFinite() ? microseconds_ : fallback_value;
171 }
172
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200173 TimeDelta Abs() const { return TimeDelta::us(std::abs(us())); }
Sebastian Jansson8e064192018-08-07 12:34:33 +0200174 constexpr bool IsZero() const { return microseconds_ == 0; }
175 constexpr bool IsFinite() const { return !IsInfinite(); }
176 constexpr bool IsInfinite() const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200177 return microseconds_ == timedelta_impl::kPlusInfinityVal ||
178 microseconds_ == timedelta_impl::kMinusInfinityVal;
179 }
Sebastian Jansson8e064192018-08-07 12:34:33 +0200180 constexpr bool IsPlusInfinity() const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200181 return microseconds_ == timedelta_impl::kPlusInfinityVal;
182 }
Sebastian Jansson8e064192018-08-07 12:34:33 +0200183 constexpr bool IsMinusInfinity() const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200184 return microseconds_ == timedelta_impl::kMinusInfinityVal;
185 }
186 TimeDelta operator+(const TimeDelta& other) const {
187 return TimeDelta::us(us() + other.us());
188 }
189 TimeDelta operator-(const TimeDelta& other) const {
190 return TimeDelta::us(us() - other.us());
191 }
192 TimeDelta& operator-=(const TimeDelta& other) {
193 microseconds_ -= other.us();
194 return *this;
195 }
196 TimeDelta& operator+=(const TimeDelta& other) {
197 microseconds_ += other.us();
198 return *this;
199 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200200 constexpr double operator/(const TimeDelta& other) const {
Sebastian Jansson942b3602018-05-30 15:47:44 +0200201 return us<double>() / other.us<double>();
202 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200203 constexpr bool operator==(const TimeDelta& other) const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200204 return microseconds_ == other.microseconds_;
205 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200206 constexpr bool operator!=(const TimeDelta& other) const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200207 return microseconds_ != other.microseconds_;
208 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200209 constexpr bool operator<=(const TimeDelta& other) const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200210 return microseconds_ <= other.microseconds_;
211 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200212 constexpr bool operator>=(const TimeDelta& other) const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200213 return microseconds_ >= other.microseconds_;
214 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200215 constexpr bool operator>(const TimeDelta& other) const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200216 return microseconds_ > other.microseconds_;
217 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200218 constexpr bool operator<(const TimeDelta& other) const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200219 return microseconds_ < other.microseconds_;
220 }
221
222 private:
Sebastian Jansson8e064192018-08-07 12:34:33 +0200223 explicit constexpr TimeDelta(int64_t us) : microseconds_(us) {}
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200224 constexpr int64_t UnsafeSeconds() const {
225 return (microseconds_ + (microseconds_ >= 0 ? 500000 : -500000)) / 1000000;
226 }
227 constexpr int64_t UnsafeMillis() const {
228 return (microseconds_ + (microseconds_ >= 0 ? 500 : -500)) / 1000;
229 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200230 int64_t microseconds_;
231};
Sebastian Jansson66fa5352018-04-30 16:54:57 +0200232
233inline TimeDelta operator*(const TimeDelta& delta, const double& scalar) {
234 return TimeDelta::us(std::round(delta.us() * scalar));
235}
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200236inline TimeDelta operator*(const double& scalar, const TimeDelta& delta) {
237 return delta * scalar;
238}
Sebastian Jansson66fa5352018-04-30 16:54:57 +0200239inline TimeDelta operator*(const TimeDelta& delta, const int64_t& scalar) {
240 return TimeDelta::us(delta.us() * scalar);
241}
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200242inline TimeDelta operator*(const int64_t& scalar, const TimeDelta& delta) {
243 return delta * scalar;
244}
Sebastian Jansson66fa5352018-04-30 16:54:57 +0200245inline TimeDelta operator*(const TimeDelta& delta, const int32_t& scalar) {
246 return TimeDelta::us(delta.us() * scalar);
247}
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200248inline TimeDelta operator*(const int32_t& scalar, const TimeDelta& delta) {
249 return delta * scalar;
250}
251
Sebastian Jansson66fa5352018-04-30 16:54:57 +0200252inline TimeDelta operator/(const TimeDelta& delta, const int64_t& scalar) {
253 return TimeDelta::us(delta.us() / scalar);
254}
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200255std::string ToString(const TimeDelta& value);
256} // namespace webrtc
257
Sebastian Jansson6fae6ec2018-05-08 10:43:18 +0200258#endif // API_UNITS_TIME_DELTA_H_