blob: 6e5e3925acadbd629066d032bdef1d82550939b6 [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 Jansson8e064192018-08-07 12:34:33 +020039 static constexpr Timestamp Infinity() {
Sebastian Jansson30bd4032018-04-13 13:56:17 +020040 return Timestamp(timestamp_impl::kPlusInfinityVal);
41 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +020042 template <int64_t seconds>
43 static constexpr Timestamp Seconds() {
44 static_assert(seconds >= 0, "");
45 static_assert(seconds < timestamp_impl::kPlusInfinityVal / 1000000, "");
46 return Timestamp(seconds * 1000000);
47 }
48 template <int64_t ms>
49 static constexpr Timestamp Millis() {
50 static_assert(ms >= 0, "");
51 static_assert(ms < timestamp_impl::kPlusInfinityVal / 1000, "");
52 return Timestamp(ms * 1000);
53 }
54 template <int64_t us>
55 static constexpr Timestamp Micros() {
56 static_assert(us >= 0, "");
57 static_assert(us < timestamp_impl::kPlusInfinityVal, "");
58 return Timestamp(us);
59 }
Sebastian Jansson942b3602018-05-30 15:47:44 +020060
61 template <
62 typename T,
63 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
64 static Timestamp seconds(T seconds) {
65 RTC_DCHECK_GE(seconds, 0);
66 RTC_DCHECK_LT(seconds, timestamp_impl::kPlusInfinityVal / 1000000);
67 return Timestamp(rtc::dchecked_cast<int64_t>(seconds) * 1000000);
Sebastian Jansson30bd4032018-04-13 13:56:17 +020068 }
69
Sebastian Jansson942b3602018-05-30 15:47:44 +020070 template <
71 typename T,
72 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
73 static Timestamp ms(T milliseconds) {
74 RTC_DCHECK_GE(milliseconds, 0);
75 RTC_DCHECK_LT(milliseconds, timestamp_impl::kPlusInfinityVal / 1000);
76 return Timestamp(rtc::dchecked_cast<int64_t>(milliseconds) * 1000);
77 }
78
79 template <
80 typename T,
81 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
82 static Timestamp us(T microseconds) {
83 RTC_DCHECK_GE(microseconds, 0);
84 RTC_DCHECK_LT(microseconds, timestamp_impl::kPlusInfinityVal);
85 return Timestamp(rtc::dchecked_cast<int64_t>(microseconds));
86 }
87
88 template <typename T,
89 typename std::enable_if<std::is_floating_point<T>::value>::type* =
90 nullptr>
91 static Timestamp seconds(T seconds) {
92 return Timestamp::us(seconds * 1e6);
93 }
94
95 template <typename T,
96 typename std::enable_if<std::is_floating_point<T>::value>::type* =
97 nullptr>
98 static Timestamp ms(T milliseconds) {
99 return Timestamp::us(milliseconds * 1e3);
100 }
101 template <typename T,
102 typename std::enable_if<std::is_floating_point<T>::value>::type* =
103 nullptr>
104 static Timestamp us(T microseconds) {
105 if (microseconds == std::numeric_limits<double>::infinity()) {
106 return Infinity();
107 } else {
108 RTC_DCHECK(!std::isnan(microseconds));
109 RTC_DCHECK_GE(microseconds, 0);
110 RTC_DCHECK_LT(microseconds, timestamp_impl::kPlusInfinityVal);
111 return Timestamp(rtc::dchecked_cast<int64_t>(microseconds));
112 }
113 }
114
115 template <typename T = int64_t>
116 typename std::enable_if<std::is_integral<T>::value, T>::type seconds() const {
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200117 RTC_DCHECK(IsFinite());
118 return rtc::dchecked_cast<T>(UnsafeSeconds());
Sebastian Jansson942b3602018-05-30 15:47:44 +0200119 }
120 template <typename T = int64_t>
121 typename std::enable_if<std::is_integral<T>::value, T>::type ms() const {
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200122 RTC_DCHECK(IsFinite());
123 return rtc::dchecked_cast<T>(UnsafeMillis());
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 us() const {
127 RTC_DCHECK(IsFinite());
128 return rtc::dchecked_cast<T>(microseconds_);
129 }
130
131 template <typename T>
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200132 constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
133 seconds() const {
Sebastian Jansson942b3602018-05-30 15:47:44 +0200134 return us<T>() * 1e-6;
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 ms() const {
Sebastian Jansson942b3602018-05-30 15:47:44 +0200139 return us<T>() * 1e-3;
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 us() const {
144 return IsInfinite() ? std::numeric_limits<T>::infinity() : microseconds_;
145 }
146
147 constexpr int64_t seconds_or(int64_t fallback_value) const {
148 return IsFinite() ? UnsafeSeconds() : fallback_value;
149 }
150 constexpr int64_t ms_or(int64_t fallback_value) const {
151 return IsFinite() ? UnsafeMillis() : fallback_value;
152 }
153 constexpr int64_t us_or(int64_t fallback_value) const {
154 return IsFinite() ? microseconds_ : fallback_value;
Sebastian Jansson942b3602018-05-30 15:47:44 +0200155 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200156
Sebastian Jansson8e064192018-08-07 12:34:33 +0200157 constexpr bool IsInfinite() const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200158 return microseconds_ == timestamp_impl::kPlusInfinityVal;
159 }
Sebastian Jansson8e064192018-08-07 12:34:33 +0200160 constexpr bool IsFinite() const { return !IsInfinite(); }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200161 TimeDelta operator-(const Timestamp& other) const {
162 return TimeDelta::us(us() - other.us());
163 }
164 Timestamp operator-(const TimeDelta& delta) const {
165 return Timestamp::us(us() - delta.us());
166 }
167 Timestamp operator+(const TimeDelta& delta) const {
168 return Timestamp::us(us() + delta.us());
169 }
170 Timestamp& operator-=(const TimeDelta& other) {
171 microseconds_ -= other.us();
172 return *this;
173 }
174 Timestamp& operator+=(const TimeDelta& other) {
175 microseconds_ += other.us();
176 return *this;
177 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200178 constexpr bool operator==(const Timestamp& other) const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200179 return microseconds_ == other.microseconds_;
180 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200181 constexpr bool operator!=(const Timestamp& other) const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200182 return microseconds_ != other.microseconds_;
183 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200184 constexpr bool operator<=(const Timestamp& other) const {
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200185 return microseconds_ <= other.microseconds_;
186 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200187 constexpr bool operator>=(const Timestamp& other) const {
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200188 return microseconds_ >= other.microseconds_;
189 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200190 constexpr bool operator>(const Timestamp& other) const {
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200191 return microseconds_ > other.microseconds_;
192 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200193 constexpr bool operator<(const Timestamp& other) const {
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200194 return microseconds_ < other.microseconds_;
195 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200196
197 private:
Sebastian Jansson8e064192018-08-07 12:34:33 +0200198 explicit constexpr Timestamp(int64_t us) : microseconds_(us) {}
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200199 constexpr int64_t UnsafeSeconds() const {
200 return (microseconds_ + 500000) / 1000000;
201 }
202 constexpr int64_t UnsafeMillis() const {
203 return (microseconds_ + 500) / 1000;
204 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200205 int64_t microseconds_;
206};
207
208std::string ToString(const Timestamp& value);
209
Sebastian Jansson2afd2812018-08-23 14:44:05 +0200210#ifdef UNIT_TEST
211inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
212 std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
213 Timestamp value) {
214 return stream << ToString(value);
215}
216#endif // UNIT_TEST
217
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200218} // namespace webrtc
219
Sebastian Jansson6fae6ec2018-05-08 10:43:18 +0200220#endif // API_UNITS_TIMESTAMP_H_