blob: 1a636bd09d39f712d69973cc84435c76de62e550 [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 Jansson942b3602018-05-30 15:47:44 +020045
46 template <
47 typename T,
48 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
49 static TimeDelta seconds(T seconds) {
50 RTC_DCHECK_GT(seconds, timedelta_impl::kMinusInfinityVal / 1000000);
51 RTC_DCHECK_LT(seconds, timedelta_impl::kPlusInfinityVal / 1000000);
52 return TimeDelta(rtc::dchecked_cast<int64_t>(seconds) * 1000000);
Sebastian Jansson30bd4032018-04-13 13:56:17 +020053 }
Sebastian Jansson942b3602018-05-30 15:47:44 +020054 template <
55 typename T,
56 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
57 static TimeDelta ms(T milliseconds) {
58 RTC_DCHECK_GT(milliseconds, timedelta_impl::kMinusInfinityVal / 1000);
59 RTC_DCHECK_LT(milliseconds, timedelta_impl::kPlusInfinityVal / 1000);
60 return TimeDelta(rtc::dchecked_cast<int64_t>(milliseconds) * 1000);
Sebastian Jansson30bd4032018-04-13 13:56:17 +020061 }
Sebastian Jansson942b3602018-05-30 15:47:44 +020062 template <
63 typename T,
64 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
65 static TimeDelta us(T microseconds) {
66 RTC_DCHECK_GT(microseconds, timedelta_impl::kMinusInfinityVal);
67 RTC_DCHECK_LT(microseconds, timedelta_impl::kPlusInfinityVal);
68 return TimeDelta(rtc::dchecked_cast<int64_t>(microseconds));
Sebastian Jansson5f83cf02018-05-08 14:52:22 +020069 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +020070
Sebastian Jansson942b3602018-05-30 15:47:44 +020071 template <typename T,
72 typename std::enable_if<std::is_floating_point<T>::value>::type* =
73 nullptr>
74 static TimeDelta seconds(T seconds) {
75 return TimeDelta::us(seconds * 1e6);
76 }
77 template <typename T,
78 typename std::enable_if<std::is_floating_point<T>::value>::type* =
79 nullptr>
80 static TimeDelta ms(T milliseconds) {
81 return TimeDelta::us(milliseconds * 1e3);
82 }
83 template <typename T,
84 typename std::enable_if<std::is_floating_point<T>::value>::type* =
85 nullptr>
86 static TimeDelta us(T microseconds) {
87 if (microseconds == std::numeric_limits<T>::infinity()) {
88 return PlusInfinity();
89 } else if (microseconds == -std::numeric_limits<T>::infinity()) {
90 return MinusInfinity();
91 } else {
92 RTC_DCHECK(!std::isnan(microseconds));
93 RTC_DCHECK_GT(microseconds, timedelta_impl::kMinusInfinityVal);
94 RTC_DCHECK_LT(microseconds, timedelta_impl::kPlusInfinityVal);
95 return TimeDelta(rtc::dchecked_cast<int64_t>(microseconds));
96 }
97 }
98
99 template <typename T = int64_t>
100 typename std::enable_if<std::is_integral<T>::value, T>::type seconds() const {
101 return rtc::dchecked_cast<T>((us() + (us() >= 0 ? 500000 : -500000)) /
102 1000000);
103 }
104 template <typename T = int64_t>
105 typename std::enable_if<std::is_integral<T>::value, T>::type ms() const {
106 return rtc::dchecked_cast<T>((us() + (us() >= 0 ? 500 : -500)) / 1000);
107 }
108 template <typename T = int64_t>
109 typename std::enable_if<std::is_integral<T>::value, T>::type us() const {
110 RTC_DCHECK(IsFinite());
111 return rtc::dchecked_cast<T>(microseconds_);
112 }
113 template <typename T = int64_t>
114 typename std::enable_if<std::is_integral<T>::value, T>::type ns() const {
115 RTC_DCHECK_GE(us(), std::numeric_limits<T>::min() / 1000);
116 RTC_DCHECK_LE(us(), std::numeric_limits<T>::max() / 1000);
117 return rtc::dchecked_cast<T>(us() * 1000);
118 }
119
120 template <typename T>
121 typename std::enable_if<std::is_floating_point<T>::value, T>::type seconds()
122 const {
123 return us<T>() * 1e-6;
124 }
125 template <typename T>
126 typename std::enable_if<std::is_floating_point<T>::value, T>::type ms()
127 const {
128 return us<T>() * 1e-3;
129 }
130 template <typename T>
131 typename std::enable_if<std::is_floating_point<T>::value, T>::type us()
132 const {
133 if (IsPlusInfinity()) {
134 return std::numeric_limits<T>::infinity();
135 } else if (IsMinusInfinity()) {
136 return -std::numeric_limits<T>::infinity();
137 } else {
138 return microseconds_;
139 }
140 }
141 template <typename T>
142 typename std::enable_if<std::is_floating_point<T>::value, T>::type ns()
143 const {
144 return us<T>() * 1e3;
145 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200146
147 TimeDelta Abs() const { return TimeDelta::us(std::abs(us())); }
Sebastian Jansson8e064192018-08-07 12:34:33 +0200148 constexpr bool IsZero() const { return microseconds_ == 0; }
149 constexpr bool IsFinite() const { return !IsInfinite(); }
150 constexpr bool IsInfinite() const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200151 return microseconds_ == timedelta_impl::kPlusInfinityVal ||
152 microseconds_ == timedelta_impl::kMinusInfinityVal;
153 }
Sebastian Jansson8e064192018-08-07 12:34:33 +0200154 constexpr bool IsPlusInfinity() const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200155 return microseconds_ == timedelta_impl::kPlusInfinityVal;
156 }
Sebastian Jansson8e064192018-08-07 12:34:33 +0200157 constexpr bool IsMinusInfinity() const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200158 return microseconds_ == timedelta_impl::kMinusInfinityVal;
159 }
160 TimeDelta operator+(const TimeDelta& other) const {
161 return TimeDelta::us(us() + other.us());
162 }
163 TimeDelta operator-(const TimeDelta& other) const {
164 return TimeDelta::us(us() - other.us());
165 }
166 TimeDelta& operator-=(const TimeDelta& other) {
167 microseconds_ -= other.us();
168 return *this;
169 }
170 TimeDelta& operator+=(const TimeDelta& other) {
171 microseconds_ += other.us();
172 return *this;
173 }
Sebastian Jansson942b3602018-05-30 15:47:44 +0200174 double operator/(const TimeDelta& other) const {
175 return us<double>() / other.us<double>();
176 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200177 bool operator==(const TimeDelta& other) const {
178 return microseconds_ == other.microseconds_;
179 }
180 bool operator!=(const TimeDelta& other) const {
181 return microseconds_ != other.microseconds_;
182 }
183 bool operator<=(const TimeDelta& other) const {
184 return microseconds_ <= other.microseconds_;
185 }
186 bool operator>=(const TimeDelta& other) const {
187 return microseconds_ >= other.microseconds_;
188 }
189 bool operator>(const TimeDelta& other) const {
190 return microseconds_ > other.microseconds_;
191 }
192 bool operator<(const TimeDelta& other) const {
193 return microseconds_ < other.microseconds_;
194 }
195
196 private:
Sebastian Jansson8e064192018-08-07 12:34:33 +0200197 explicit constexpr TimeDelta(int64_t us) : microseconds_(us) {}
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200198 int64_t microseconds_;
199};
Sebastian Jansson66fa5352018-04-30 16:54:57 +0200200
201inline TimeDelta operator*(const TimeDelta& delta, const double& scalar) {
202 return TimeDelta::us(std::round(delta.us() * scalar));
203}
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200204inline TimeDelta operator*(const double& scalar, const TimeDelta& delta) {
205 return delta * scalar;
206}
Sebastian Jansson66fa5352018-04-30 16:54:57 +0200207inline TimeDelta operator*(const TimeDelta& delta, const int64_t& scalar) {
208 return TimeDelta::us(delta.us() * scalar);
209}
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200210inline TimeDelta operator*(const int64_t& scalar, const TimeDelta& delta) {
211 return delta * scalar;
212}
Sebastian Jansson66fa5352018-04-30 16:54:57 +0200213inline TimeDelta operator*(const TimeDelta& delta, const int32_t& scalar) {
214 return TimeDelta::us(delta.us() * scalar);
215}
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200216inline TimeDelta operator*(const int32_t& scalar, const TimeDelta& delta) {
217 return delta * scalar;
218}
219
Sebastian Jansson66fa5352018-04-30 16:54:57 +0200220inline TimeDelta operator/(const TimeDelta& delta, const int64_t& scalar) {
221 return TimeDelta::us(delta.us() / scalar);
222}
223
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200224std::string ToString(const TimeDelta& value);
225} // namespace webrtc
226
Sebastian Jansson6fae6ec2018-05-08 10:43:18 +0200227#endif // API_UNITS_TIME_DELTA_H_