blob: d7e6a8db34340a2893d201b341b9faef7672d3a5 [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 {
Sebastian Jansson88c1a9e2018-08-30 13:58:38 +0200165 RTC_DCHECK(!delta.IsPlusInfinity());
166 if (IsInfinite() || delta.IsMinusInfinity())
167 return Infinity();
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200168 return Timestamp::us(us() - delta.us());
169 }
170 Timestamp operator+(const TimeDelta& delta) const {
Sebastian Jansson88c1a9e2018-08-30 13:58:38 +0200171 RTC_DCHECK(!delta.IsMinusInfinity());
172 if (IsInfinite() || delta.IsPlusInfinity())
173 return Infinity();
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200174 return Timestamp::us(us() + delta.us());
175 }
176 Timestamp& operator-=(const TimeDelta& other) {
Sebastian Jansson88c1a9e2018-08-30 13:58:38 +0200177 *this = *this - other;
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200178 return *this;
179 }
180 Timestamp& operator+=(const TimeDelta& other) {
Sebastian Jansson88c1a9e2018-08-30 13:58:38 +0200181 *this = *this + other;
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200182 return *this;
183 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200184 constexpr bool operator==(const Timestamp& other) const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200185 return microseconds_ == other.microseconds_;
186 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200187 constexpr bool operator!=(const Timestamp& other) const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +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 Janssonc1c8b8e2018-08-07 15:29:04 +0200196 constexpr bool operator>(const Timestamp& other) const {
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200197 return microseconds_ > other.microseconds_;
198 }
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200199 constexpr bool operator<(const Timestamp& other) const {
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200200 return microseconds_ < other.microseconds_;
201 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200202
203 private:
Sebastian Jansson8e064192018-08-07 12:34:33 +0200204 explicit constexpr Timestamp(int64_t us) : microseconds_(us) {}
Sebastian Janssonc1c8b8e2018-08-07 15:29:04 +0200205 constexpr int64_t UnsafeSeconds() const {
206 return (microseconds_ + 500000) / 1000000;
207 }
208 constexpr int64_t UnsafeMillis() const {
209 return (microseconds_ + 500) / 1000;
210 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200211 int64_t microseconds_;
212};
213
214std::string ToString(const Timestamp& value);
215
Sebastian Jansson2afd2812018-08-23 14:44:05 +0200216#ifdef UNIT_TEST
217inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
218 std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
219 Timestamp value) {
220 return stream << ToString(value);
221}
222#endif // UNIT_TEST
223
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200224} // namespace webrtc
225
Sebastian Jansson6fae6ec2018-05-08 10:43:18 +0200226#endif // API_UNITS_TIMESTAMP_H_