blob: 0298f5da979342bdbc29980876622b2ea040acf1 [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
Sebastian Jansson30bd4032018-04-13 13:56:17 +020018#include <stdint.h>
19#include <limits>
20#include <string>
21
Sebastian Jansson6fae6ec2018-05-08 10:43:18 +020022#include "api/units/time_delta.h"
Sebastian Jansson30bd4032018-04-13 13:56:17 +020023#include "rtc_base/checks.h"
Sebastian Jansson942b3602018-05-30 15:47:44 +020024#include "rtc_base/numerics/safe_conversions.h"
Sebastian Jansson30bd4032018-04-13 13:56:17 +020025
26namespace webrtc {
27namespace timestamp_impl {
28constexpr int64_t kPlusInfinityVal = std::numeric_limits<int64_t>::max();
29constexpr int64_t kMinusInfinityVal = std::numeric_limits<int64_t>::min();
Sebastian Jansson30bd4032018-04-13 13:56:17 +020030} // namespace timestamp_impl
31
32// Timestamp represents the time that has passed since some unspecified epoch.
33// The epoch is assumed to be before any represented timestamps, this means that
34// negative values are not valid. The most notable feature is that the
35// difference of two Timestamps results in a TimeDelta.
36class Timestamp {
37 public:
Sebastian Jansson3b69b192018-05-07 13:51:51 +020038 Timestamp() = delete;
Sebastian Jansson9de4ef42018-09-04 17:32:36 +020039 static constexpr Timestamp PlusInfinity() {
Sebastian Jansson30bd4032018-04-13 13:56:17 +020040 return Timestamp(timestamp_impl::kPlusInfinityVal);
41 }
Sebastian Jansson9de4ef42018-09-04 17:32:36 +020042 static constexpr Timestamp MinusInfinity() {
43 return Timestamp(timestamp_impl::kMinusInfinityVal);
44 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +020045 template <int64_t seconds>
46 static constexpr Timestamp Seconds() {
47 static_assert(seconds >= 0, "");
48 static_assert(seconds < timestamp_impl::kPlusInfinityVal / 1000000, "");
49 return Timestamp(seconds * 1000000);
50 }
51 template <int64_t ms>
52 static constexpr Timestamp Millis() {
53 static_assert(ms >= 0, "");
54 static_assert(ms < timestamp_impl::kPlusInfinityVal / 1000, "");
55 return Timestamp(ms * 1000);
56 }
57 template <int64_t us>
58 static constexpr Timestamp Micros() {
59 static_assert(us >= 0, "");
60 static_assert(us < timestamp_impl::kPlusInfinityVal, "");
61 return Timestamp(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 Timestamp seconds(T seconds) {
68 RTC_DCHECK_GE(seconds, 0);
69 RTC_DCHECK_LT(seconds, timestamp_impl::kPlusInfinityVal / 1000000);
70 return Timestamp(rtc::dchecked_cast<int64_t>(seconds) * 1000000);
Sebastian Jansson30bd4032018-04-13 13:56:17 +020071 }
72
Sebastian Jansson942b3602018-05-30 15:47:44 +020073 template <
74 typename T,
75 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
76 static Timestamp ms(T milliseconds) {
77 RTC_DCHECK_GE(milliseconds, 0);
78 RTC_DCHECK_LT(milliseconds, timestamp_impl::kPlusInfinityVal / 1000);
79 return Timestamp(rtc::dchecked_cast<int64_t>(milliseconds) * 1000);
80 }
81
82 template <
83 typename T,
84 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
85 static Timestamp us(T microseconds) {
86 RTC_DCHECK_GE(microseconds, 0);
87 RTC_DCHECK_LT(microseconds, timestamp_impl::kPlusInfinityVal);
88 return Timestamp(rtc::dchecked_cast<int64_t>(microseconds));
89 }
90
91 template <typename T,
92 typename std::enable_if<std::is_floating_point<T>::value>::type* =
93 nullptr>
94 static Timestamp seconds(T seconds) {
95 return Timestamp::us(seconds * 1e6);
96 }
97
98 template <typename T,
99 typename std::enable_if<std::is_floating_point<T>::value>::type* =
100 nullptr>
101 static Timestamp ms(T milliseconds) {
102 return Timestamp::us(milliseconds * 1e3);
103 }
104 template <typename T,
105 typename std::enable_if<std::is_floating_point<T>::value>::type* =
106 nullptr>
107 static Timestamp us(T microseconds) {
108 if (microseconds == std::numeric_limits<double>::infinity()) {
Sebastian Jansson9de4ef42018-09-04 17:32:36 +0200109 return PlusInfinity();
110 } else if (microseconds == -std::numeric_limits<double>::infinity()) {
111 return MinusInfinity();
Sebastian Jansson942b3602018-05-30 15:47:44 +0200112 } else {
113 RTC_DCHECK(!std::isnan(microseconds));
114 RTC_DCHECK_GE(microseconds, 0);
115 RTC_DCHECK_LT(microseconds, timestamp_impl::kPlusInfinityVal);
116 return Timestamp(rtc::dchecked_cast<int64_t>(microseconds));
117 }
118 }
119
120 template <typename T = int64_t>
121 typename std::enable_if<std::is_integral<T>::value, T>::type seconds() const {
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200122 RTC_DCHECK(IsFinite());
123 return rtc::dchecked_cast<T>(UnsafeSeconds());
Sebastian Jansson942b3602018-05-30 15:47:44 +0200124 }
125 template <typename T = int64_t>
126 typename std::enable_if<std::is_integral<T>::value, T>::type ms() const {
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200127 RTC_DCHECK(IsFinite());
128 return rtc::dchecked_cast<T>(UnsafeMillis());
Sebastian Jansson942b3602018-05-30 15:47:44 +0200129 }
130 template <typename T = int64_t>
131 typename std::enable_if<std::is_integral<T>::value, T>::type us() const {
132 RTC_DCHECK(IsFinite());
133 return rtc::dchecked_cast<T>(microseconds_);
134 }
135
136 template <typename T>
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200137 constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
138 seconds() const {
Sebastian Jansson942b3602018-05-30 15:47:44 +0200139 return us<T>() * 1e-6;
140 }
141 template <typename T>
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200142 constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
143 ms() const {
Sebastian Jansson942b3602018-05-30 15:47:44 +0200144 return us<T>() * 1e-3;
145 }
146 template <typename T>
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200147 constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
148 us() const {
Sebastian Jansson9de4ef42018-09-04 17:32:36 +0200149 return IsPlusInfinity()
150 ? std::numeric_limits<T>::infinity()
151 : IsMinusInfinity() ? -std::numeric_limits<T>::infinity()
152 : microseconds_;
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200153 }
154
155 constexpr int64_t seconds_or(int64_t fallback_value) const {
156 return IsFinite() ? UnsafeSeconds() : fallback_value;
157 }
158 constexpr int64_t ms_or(int64_t fallback_value) const {
159 return IsFinite() ? UnsafeMillis() : fallback_value;
160 }
161 constexpr int64_t us_or(int64_t fallback_value) const {
162 return IsFinite() ? microseconds_ : fallback_value;
Sebastian Jansson942b3602018-05-30 15:47:44 +0200163 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200164
Sebastian Jansson8e064192018-08-07 12:34:33 +0200165 constexpr bool IsFinite() const { return !IsInfinite(); }
Sebastian Jansson9de4ef42018-09-04 17:32:36 +0200166 constexpr bool IsInfinite() const {
167 return microseconds_ == timedelta_impl::kPlusInfinityVal ||
168 microseconds_ == timedelta_impl::kMinusInfinityVal;
169 }
170 constexpr bool IsPlusInfinity() const {
171 return microseconds_ == timedelta_impl::kPlusInfinityVal;
172 }
173 constexpr bool IsMinusInfinity() const {
174 return microseconds_ == timedelta_impl::kMinusInfinityVal;
175 }
176 Timestamp operator+(const TimeDelta& other) const {
177 if (IsPlusInfinity() || other.IsPlusInfinity()) {
178 RTC_DCHECK(!IsMinusInfinity());
179 RTC_DCHECK(!other.IsMinusInfinity());
180 return PlusInfinity();
181 } else if (IsMinusInfinity() || other.IsMinusInfinity()) {
182 RTC_DCHECK(!IsPlusInfinity());
183 RTC_DCHECK(!other.IsPlusInfinity());
184 return MinusInfinity();
185 }
186 return Timestamp::us(us() + other.us());
187 }
188 Timestamp operator-(const TimeDelta& other) const {
189 if (IsPlusInfinity() || other.IsMinusInfinity()) {
190 RTC_DCHECK(!IsMinusInfinity());
191 RTC_DCHECK(!other.IsPlusInfinity());
192 return PlusInfinity();
193 } else if (IsMinusInfinity() || other.IsPlusInfinity()) {
194 RTC_DCHECK(!IsPlusInfinity());
195 RTC_DCHECK(!other.IsMinusInfinity());
196 return MinusInfinity();
197 }
198 return Timestamp::us(us() - other.us());
199 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200200 TimeDelta operator-(const Timestamp& other) const {
Sebastian Jansson9de4ef42018-09-04 17:32:36 +0200201 if (IsPlusInfinity() || other.IsMinusInfinity()) {
202 RTC_DCHECK(!IsMinusInfinity());
203 RTC_DCHECK(!other.IsPlusInfinity());
204 return TimeDelta::PlusInfinity();
205 } else if (IsMinusInfinity() || other.IsPlusInfinity()) {
206 RTC_DCHECK(!IsPlusInfinity());
207 RTC_DCHECK(!other.IsMinusInfinity());
208 return TimeDelta::MinusInfinity();
209 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200210 return TimeDelta::us(us() - other.us());
211 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200212 Timestamp& operator-=(const TimeDelta& other) {
Sebastian Jansson88c1a9e2018-08-30 13:58:38 +0200213 *this = *this - other;
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200214 return *this;
215 }
216 Timestamp& operator+=(const TimeDelta& other) {
Sebastian Jansson88c1a9e2018-08-30 13:58:38 +0200217 *this = *this + other;
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200218 return *this;
219 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200220 constexpr bool operator==(const Timestamp& other) const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200221 return microseconds_ == other.microseconds_;
222 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200223 constexpr bool operator!=(const Timestamp& other) const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200224 return microseconds_ != other.microseconds_;
225 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200226 constexpr bool operator<=(const Timestamp& other) const {
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200227 return microseconds_ <= other.microseconds_;
228 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200229 constexpr bool operator>=(const Timestamp& other) const {
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200230 return microseconds_ >= other.microseconds_;
231 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200232 constexpr bool operator>(const Timestamp& other) const {
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200233 return microseconds_ > other.microseconds_;
234 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200235 constexpr bool operator<(const Timestamp& other) const {
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200236 return microseconds_ < other.microseconds_;
237 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200238
239 private:
Sebastian Jansson8e064192018-08-07 12:34:33 +0200240 explicit constexpr Timestamp(int64_t us) : microseconds_(us) {}
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200241 constexpr int64_t UnsafeSeconds() const {
242 return (microseconds_ + 500000) / 1000000;
243 }
244 constexpr int64_t UnsafeMillis() const {
245 return (microseconds_ + 500) / 1000;
246 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200247 int64_t microseconds_;
248};
249
250std::string ToString(const Timestamp& value);
251
Sebastian Jansson2afd2812018-08-23 14:44:05 +0200252#ifdef UNIT_TEST
253inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
254 std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
255 Timestamp value) {
256 return stream << ToString(value);
257}
258#endif // UNIT_TEST
259
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200260} // namespace webrtc
261
Sebastian Jansson6fae6ec2018-05-08 10:43:18 +0200262#endif // API_UNITS_TIMESTAMP_H_