blob: 80f1839250418e83d8efc6c398d0bf50f5c5aa3d [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_TIMESTAMP_H_
12#define API_UNITS_TIMESTAMP_H_
Sebastian Jansson30bd4032018-04-13 13:56:17 +020013
Sebastian Jansson2afd2812018-08-23 14:44:05 +020014#ifdef UNIT_TEST
15#include <ostream> // no-presubmit-check TODO(webrtc:8982)
16#endif // UNIT_TEST
17
Yves Gerey988cc082018-10-23 12:03:01 +020018#include <math.h>
Sebastian Jansson30bd4032018-04-13 13:56:17 +020019#include <stdint.h>
20#include <limits>
21#include <string>
Yves Gerey988cc082018-10-23 12:03:01 +020022#include <type_traits>
Sebastian Jansson30bd4032018-04-13 13:56:17 +020023
Sebastian Jansson6fae6ec2018-05-08 10:43:18 +020024#include "api/units/time_delta.h"
Sebastian Jansson30bd4032018-04-13 13:56:17 +020025#include "rtc_base/checks.h"
Sebastian Jansson942b3602018-05-30 15:47:44 +020026#include "rtc_base/numerics/safe_conversions.h"
Sebastian Jansson30bd4032018-04-13 13:56:17 +020027
28namespace webrtc {
29namespace timestamp_impl {
30constexpr int64_t kPlusInfinityVal = std::numeric_limits<int64_t>::max();
31constexpr int64_t kMinusInfinityVal = std::numeric_limits<int64_t>::min();
Sebastian Jansson30bd4032018-04-13 13:56:17 +020032} // namespace timestamp_impl
33
34// Timestamp represents the time that has passed since some unspecified epoch.
35// The epoch is assumed to be before any represented timestamps, this means that
36// negative values are not valid. The most notable feature is that the
37// difference of two Timestamps results in a TimeDelta.
38class Timestamp {
39 public:
Sebastian Jansson3b69b192018-05-07 13:51:51 +020040 Timestamp() = delete;
Sebastian Jansson9de4ef42018-09-04 17:32:36 +020041 static constexpr Timestamp PlusInfinity() {
Sebastian Jansson30bd4032018-04-13 13:56:17 +020042 return Timestamp(timestamp_impl::kPlusInfinityVal);
43 }
Sebastian Jansson9de4ef42018-09-04 17:32:36 +020044 static constexpr Timestamp MinusInfinity() {
45 return Timestamp(timestamp_impl::kMinusInfinityVal);
46 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +020047 template <int64_t seconds>
48 static constexpr Timestamp Seconds() {
49 static_assert(seconds >= 0, "");
50 static_assert(seconds < timestamp_impl::kPlusInfinityVal / 1000000, "");
51 return Timestamp(seconds * 1000000);
52 }
53 template <int64_t ms>
54 static constexpr Timestamp Millis() {
55 static_assert(ms >= 0, "");
56 static_assert(ms < timestamp_impl::kPlusInfinityVal / 1000, "");
57 return Timestamp(ms * 1000);
58 }
59 template <int64_t us>
60 static constexpr Timestamp Micros() {
61 static_assert(us >= 0, "");
62 static_assert(us < timestamp_impl::kPlusInfinityVal, "");
63 return Timestamp(us);
64 }
Sebastian Jansson942b3602018-05-30 15:47:44 +020065
66 template <
67 typename T,
68 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
69 static Timestamp seconds(T seconds) {
70 RTC_DCHECK_GE(seconds, 0);
71 RTC_DCHECK_LT(seconds, timestamp_impl::kPlusInfinityVal / 1000000);
72 return Timestamp(rtc::dchecked_cast<int64_t>(seconds) * 1000000);
Sebastian Jansson30bd4032018-04-13 13:56:17 +020073 }
74
Sebastian Jansson942b3602018-05-30 15:47:44 +020075 template <
76 typename T,
77 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
78 static Timestamp ms(T milliseconds) {
79 RTC_DCHECK_GE(milliseconds, 0);
80 RTC_DCHECK_LT(milliseconds, timestamp_impl::kPlusInfinityVal / 1000);
81 return Timestamp(rtc::dchecked_cast<int64_t>(milliseconds) * 1000);
82 }
83
84 template <
85 typename T,
86 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
87 static Timestamp us(T microseconds) {
88 RTC_DCHECK_GE(microseconds, 0);
89 RTC_DCHECK_LT(microseconds, timestamp_impl::kPlusInfinityVal);
90 return Timestamp(rtc::dchecked_cast<int64_t>(microseconds));
91 }
92
93 template <typename T,
94 typename std::enable_if<std::is_floating_point<T>::value>::type* =
95 nullptr>
96 static Timestamp seconds(T seconds) {
97 return Timestamp::us(seconds * 1e6);
98 }
99
100 template <typename T,
101 typename std::enable_if<std::is_floating_point<T>::value>::type* =
102 nullptr>
103 static Timestamp ms(T milliseconds) {
104 return Timestamp::us(milliseconds * 1e3);
105 }
106 template <typename T,
107 typename std::enable_if<std::is_floating_point<T>::value>::type* =
108 nullptr>
109 static Timestamp us(T microseconds) {
110 if (microseconds == std::numeric_limits<double>::infinity()) {
Sebastian Jansson9de4ef42018-09-04 17:32:36 +0200111 return PlusInfinity();
112 } else if (microseconds == -std::numeric_limits<double>::infinity()) {
113 return MinusInfinity();
Sebastian Jansson942b3602018-05-30 15:47:44 +0200114 } else {
115 RTC_DCHECK(!std::isnan(microseconds));
116 RTC_DCHECK_GE(microseconds, 0);
117 RTC_DCHECK_LT(microseconds, timestamp_impl::kPlusInfinityVal);
118 return Timestamp(rtc::dchecked_cast<int64_t>(microseconds));
119 }
120 }
121
122 template <typename T = int64_t>
123 typename std::enable_if<std::is_integral<T>::value, T>::type seconds() const {
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200124 RTC_DCHECK(IsFinite());
125 return rtc::dchecked_cast<T>(UnsafeSeconds());
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 ms() const {
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200129 RTC_DCHECK(IsFinite());
130 return rtc::dchecked_cast<T>(UnsafeMillis());
Sebastian Jansson942b3602018-05-30 15:47:44 +0200131 }
132 template <typename T = int64_t>
133 typename std::enable_if<std::is_integral<T>::value, T>::type us() const {
134 RTC_DCHECK(IsFinite());
135 return rtc::dchecked_cast<T>(microseconds_);
136 }
137
138 template <typename T>
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200139 constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
140 seconds() const {
Sebastian Jansson942b3602018-05-30 15:47:44 +0200141 return us<T>() * 1e-6;
142 }
143 template <typename T>
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200144 constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
145 ms() const {
Sebastian Jansson942b3602018-05-30 15:47:44 +0200146 return us<T>() * 1e-3;
147 }
148 template <typename T>
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200149 constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
150 us() const {
Sebastian Jansson9de4ef42018-09-04 17:32:36 +0200151 return IsPlusInfinity()
152 ? std::numeric_limits<T>::infinity()
153 : IsMinusInfinity() ? -std::numeric_limits<T>::infinity()
154 : microseconds_;
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200155 }
156
157 constexpr int64_t seconds_or(int64_t fallback_value) const {
158 return IsFinite() ? UnsafeSeconds() : fallback_value;
159 }
160 constexpr int64_t ms_or(int64_t fallback_value) const {
161 return IsFinite() ? UnsafeMillis() : fallback_value;
162 }
163 constexpr int64_t us_or(int64_t fallback_value) const {
164 return IsFinite() ? microseconds_ : fallback_value;
Sebastian Jansson942b3602018-05-30 15:47:44 +0200165 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200166
Sebastian Jansson8e064192018-08-07 12:34:33 +0200167 constexpr bool IsFinite() const { return !IsInfinite(); }
Sebastian Jansson9de4ef42018-09-04 17:32:36 +0200168 constexpr bool IsInfinite() const {
169 return microseconds_ == timedelta_impl::kPlusInfinityVal ||
170 microseconds_ == timedelta_impl::kMinusInfinityVal;
171 }
172 constexpr bool IsPlusInfinity() const {
173 return microseconds_ == timedelta_impl::kPlusInfinityVal;
174 }
175 constexpr bool IsMinusInfinity() const {
176 return microseconds_ == timedelta_impl::kMinusInfinityVal;
177 }
178 Timestamp operator+(const TimeDelta& other) const {
179 if (IsPlusInfinity() || other.IsPlusInfinity()) {
180 RTC_DCHECK(!IsMinusInfinity());
181 RTC_DCHECK(!other.IsMinusInfinity());
182 return PlusInfinity();
183 } else if (IsMinusInfinity() || other.IsMinusInfinity()) {
184 RTC_DCHECK(!IsPlusInfinity());
185 RTC_DCHECK(!other.IsPlusInfinity());
186 return MinusInfinity();
187 }
188 return Timestamp::us(us() + other.us());
189 }
190 Timestamp operator-(const TimeDelta& other) const {
191 if (IsPlusInfinity() || other.IsMinusInfinity()) {
192 RTC_DCHECK(!IsMinusInfinity());
193 RTC_DCHECK(!other.IsPlusInfinity());
194 return PlusInfinity();
195 } else if (IsMinusInfinity() || other.IsPlusInfinity()) {
196 RTC_DCHECK(!IsPlusInfinity());
197 RTC_DCHECK(!other.IsMinusInfinity());
198 return MinusInfinity();
199 }
200 return Timestamp::us(us() - other.us());
201 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200202 TimeDelta operator-(const Timestamp& other) const {
Sebastian Jansson9de4ef42018-09-04 17:32:36 +0200203 if (IsPlusInfinity() || other.IsMinusInfinity()) {
204 RTC_DCHECK(!IsMinusInfinity());
205 RTC_DCHECK(!other.IsPlusInfinity());
206 return TimeDelta::PlusInfinity();
207 } else if (IsMinusInfinity() || other.IsPlusInfinity()) {
208 RTC_DCHECK(!IsPlusInfinity());
209 RTC_DCHECK(!other.IsMinusInfinity());
210 return TimeDelta::MinusInfinity();
211 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200212 return TimeDelta::us(us() - other.us());
213 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200214 Timestamp& operator-=(const TimeDelta& other) {
Sebastian Jansson88c1a9e2018-08-30 13:58:38 +0200215 *this = *this - other;
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200216 return *this;
217 }
218 Timestamp& operator+=(const TimeDelta& other) {
Sebastian Jansson88c1a9e2018-08-30 13:58:38 +0200219 *this = *this + other;
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200220 return *this;
221 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200222 constexpr bool operator==(const Timestamp& other) const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200223 return microseconds_ == other.microseconds_;
224 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200225 constexpr bool operator!=(const Timestamp& other) const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200226 return microseconds_ != other.microseconds_;
227 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200228 constexpr bool operator<=(const Timestamp& other) const {
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200229 return microseconds_ <= other.microseconds_;
230 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200231 constexpr bool operator>=(const Timestamp& other) const {
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200232 return microseconds_ >= other.microseconds_;
233 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200234 constexpr bool operator>(const Timestamp& other) const {
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200235 return microseconds_ > other.microseconds_;
236 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200237 constexpr bool operator<(const Timestamp& other) const {
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200238 return microseconds_ < other.microseconds_;
239 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200240
241 private:
Sebastian Jansson8e064192018-08-07 12:34:33 +0200242 explicit constexpr Timestamp(int64_t us) : microseconds_(us) {}
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200243 constexpr int64_t UnsafeSeconds() const {
244 return (microseconds_ + 500000) / 1000000;
245 }
246 constexpr int64_t UnsafeMillis() const {
247 return (microseconds_ + 500) / 1000;
248 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200249 int64_t microseconds_;
250};
251
252std::string ToString(const Timestamp& value);
253
Sebastian Jansson2afd2812018-08-23 14:44:05 +0200254#ifdef UNIT_TEST
255inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
256 std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
257 Timestamp value) {
258 return stream << ToString(value);
259}
260#endif // UNIT_TEST
261
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200262} // namespace webrtc
263
Sebastian Jansson6fae6ec2018-05-08 10:43:18 +0200264#endif // API_UNITS_TIMESTAMP_H_