blob: 1b5e84ff6014f961ca19d321ce830d0333c0c49b [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
14#include <stdint.h>
15#include <limits>
16#include <string>
17
Sebastian Jansson6fae6ec2018-05-08 10:43:18 +020018#include "api/units/time_delta.h"
Sebastian Jansson30bd4032018-04-13 13:56:17 +020019#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 timestamp_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 timestamp_impl
27
28// Timestamp represents the time that has passed since some unspecified epoch.
29// The epoch is assumed to be before any represented timestamps, this means that
30// negative values are not valid. The most notable feature is that the
31// difference of two Timestamps results in a TimeDelta.
32class Timestamp {
33 public:
Sebastian Jansson3b69b192018-05-07 13:51:51 +020034 Timestamp() = delete;
Sebastian Jansson8e064192018-08-07 12:34:33 +020035 static constexpr Timestamp Infinity() {
Sebastian Jansson30bd4032018-04-13 13:56:17 +020036 return Timestamp(timestamp_impl::kPlusInfinityVal);
37 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +020038 template <int64_t seconds>
39 static constexpr Timestamp Seconds() {
40 static_assert(seconds >= 0, "");
41 static_assert(seconds < timestamp_impl::kPlusInfinityVal / 1000000, "");
42 return Timestamp(seconds * 1000000);
43 }
44 template <int64_t ms>
45 static constexpr Timestamp Millis() {
46 static_assert(ms >= 0, "");
47 static_assert(ms < timestamp_impl::kPlusInfinityVal / 1000, "");
48 return Timestamp(ms * 1000);
49 }
50 template <int64_t us>
51 static constexpr Timestamp Micros() {
52 static_assert(us >= 0, "");
53 static_assert(us < timestamp_impl::kPlusInfinityVal, "");
54 return Timestamp(us);
55 }
Sebastian Jansson942b3602018-05-30 15:47:44 +020056
57 template <
58 typename T,
59 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
60 static Timestamp seconds(T seconds) {
61 RTC_DCHECK_GE(seconds, 0);
62 RTC_DCHECK_LT(seconds, timestamp_impl::kPlusInfinityVal / 1000000);
63 return Timestamp(rtc::dchecked_cast<int64_t>(seconds) * 1000000);
Sebastian Jansson30bd4032018-04-13 13:56:17 +020064 }
65
Sebastian Jansson942b3602018-05-30 15:47:44 +020066 template <
67 typename T,
68 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
69 static Timestamp ms(T milliseconds) {
70 RTC_DCHECK_GE(milliseconds, 0);
71 RTC_DCHECK_LT(milliseconds, timestamp_impl::kPlusInfinityVal / 1000);
72 return Timestamp(rtc::dchecked_cast<int64_t>(milliseconds) * 1000);
73 }
74
75 template <
76 typename T,
77 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
78 static Timestamp us(T microseconds) {
79 RTC_DCHECK_GE(microseconds, 0);
80 RTC_DCHECK_LT(microseconds, timestamp_impl::kPlusInfinityVal);
81 return Timestamp(rtc::dchecked_cast<int64_t>(microseconds));
82 }
83
84 template <typename T,
85 typename std::enable_if<std::is_floating_point<T>::value>::type* =
86 nullptr>
87 static Timestamp seconds(T seconds) {
88 return Timestamp::us(seconds * 1e6);
89 }
90
91 template <typename T,
92 typename std::enable_if<std::is_floating_point<T>::value>::type* =
93 nullptr>
94 static Timestamp ms(T milliseconds) {
95 return Timestamp::us(milliseconds * 1e3);
96 }
97 template <typename T,
98 typename std::enable_if<std::is_floating_point<T>::value>::type* =
99 nullptr>
100 static Timestamp us(T microseconds) {
101 if (microseconds == std::numeric_limits<double>::infinity()) {
102 return Infinity();
103 } else {
104 RTC_DCHECK(!std::isnan(microseconds));
105 RTC_DCHECK_GE(microseconds, 0);
106 RTC_DCHECK_LT(microseconds, timestamp_impl::kPlusInfinityVal);
107 return Timestamp(rtc::dchecked_cast<int64_t>(microseconds));
108 }
109 }
110
111 template <typename T = int64_t>
112 typename std::enable_if<std::is_integral<T>::value, T>::type seconds() const {
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200113 RTC_DCHECK(IsFinite());
114 return rtc::dchecked_cast<T>(UnsafeSeconds());
Sebastian Jansson942b3602018-05-30 15:47:44 +0200115 }
116 template <typename T = int64_t>
117 typename std::enable_if<std::is_integral<T>::value, T>::type ms() const {
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200118 RTC_DCHECK(IsFinite());
119 return rtc::dchecked_cast<T>(UnsafeMillis());
Sebastian Jansson942b3602018-05-30 15:47:44 +0200120 }
121 template <typename T = int64_t>
122 typename std::enable_if<std::is_integral<T>::value, T>::type us() const {
123 RTC_DCHECK(IsFinite());
124 return rtc::dchecked_cast<T>(microseconds_);
125 }
126
127 template <typename T>
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200128 constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
129 seconds() const {
Sebastian Jansson942b3602018-05-30 15:47:44 +0200130 return us<T>() * 1e-6;
131 }
132 template <typename T>
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200133 constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
134 ms() const {
Sebastian Jansson942b3602018-05-30 15:47:44 +0200135 return us<T>() * 1e-3;
136 }
137 template <typename T>
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200138 constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
139 us() const {
140 return IsInfinite() ? std::numeric_limits<T>::infinity() : microseconds_;
141 }
142
143 constexpr int64_t seconds_or(int64_t fallback_value) const {
144 return IsFinite() ? UnsafeSeconds() : fallback_value;
145 }
146 constexpr int64_t ms_or(int64_t fallback_value) const {
147 return IsFinite() ? UnsafeMillis() : fallback_value;
148 }
149 constexpr int64_t us_or(int64_t fallback_value) const {
150 return IsFinite() ? microseconds_ : fallback_value;
Sebastian Jansson942b3602018-05-30 15:47:44 +0200151 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200152
Sebastian Jansson8e064192018-08-07 12:34:33 +0200153 constexpr bool IsInfinite() const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200154 return microseconds_ == timestamp_impl::kPlusInfinityVal;
155 }
Sebastian Jansson8e064192018-08-07 12:34:33 +0200156 constexpr bool IsFinite() const { return !IsInfinite(); }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200157 TimeDelta operator-(const Timestamp& other) const {
158 return TimeDelta::us(us() - other.us());
159 }
160 Timestamp operator-(const TimeDelta& delta) const {
161 return Timestamp::us(us() - delta.us());
162 }
163 Timestamp operator+(const TimeDelta& delta) const {
164 return Timestamp::us(us() + delta.us());
165 }
166 Timestamp& operator-=(const TimeDelta& other) {
167 microseconds_ -= other.us();
168 return *this;
169 }
170 Timestamp& operator+=(const TimeDelta& other) {
171 microseconds_ += other.us();
172 return *this;
173 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200174 constexpr bool operator==(const Timestamp& other) const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200175 return microseconds_ == other.microseconds_;
176 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200177 constexpr bool operator!=(const Timestamp& other) const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200178 return microseconds_ != other.microseconds_;
179 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200180 constexpr bool operator<=(const Timestamp& other) const {
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200181 return microseconds_ <= other.microseconds_;
182 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200183 constexpr bool operator>=(const Timestamp& other) const {
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200184 return microseconds_ >= other.microseconds_;
185 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200186 constexpr bool operator>(const Timestamp& other) const {
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200187 return microseconds_ > other.microseconds_;
188 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200189 constexpr bool operator<(const Timestamp& other) const {
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200190 return microseconds_ < other.microseconds_;
191 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200192
193 private:
Sebastian Jansson8e064192018-08-07 12:34:33 +0200194 explicit constexpr Timestamp(int64_t us) : microseconds_(us) {}
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200195 constexpr int64_t UnsafeSeconds() const {
196 return (microseconds_ + 500000) / 1000000;
197 }
198 constexpr int64_t UnsafeMillis() const {
199 return (microseconds_ + 500) / 1000;
200 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200201 int64_t microseconds_;
202};
203
204std::string ToString(const Timestamp& value);
205
206} // namespace webrtc
207
Sebastian Jansson6fae6ec2018-05-08 10:43:18 +0200208#endif // API_UNITS_TIMESTAMP_H_