blob: 6f4dff88bc02327b182316bd3e1bdac2e67991ba [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 Jansson942b3602018-05-30 15:47:44 +020038
39 template <
40 typename T,
41 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
42 static Timestamp seconds(T seconds) {
43 RTC_DCHECK_GE(seconds, 0);
44 RTC_DCHECK_LT(seconds, timestamp_impl::kPlusInfinityVal / 1000000);
45 return Timestamp(rtc::dchecked_cast<int64_t>(seconds) * 1000000);
Sebastian Jansson30bd4032018-04-13 13:56:17 +020046 }
47
Sebastian Jansson942b3602018-05-30 15:47:44 +020048 template <
49 typename T,
50 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
51 static Timestamp ms(T milliseconds) {
52 RTC_DCHECK_GE(milliseconds, 0);
53 RTC_DCHECK_LT(milliseconds, timestamp_impl::kPlusInfinityVal / 1000);
54 return Timestamp(rtc::dchecked_cast<int64_t>(milliseconds) * 1000);
55 }
56
57 template <
58 typename T,
59 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
60 static Timestamp us(T microseconds) {
61 RTC_DCHECK_GE(microseconds, 0);
62 RTC_DCHECK_LT(microseconds, timestamp_impl::kPlusInfinityVal);
63 return Timestamp(rtc::dchecked_cast<int64_t>(microseconds));
64 }
65
66 template <typename T,
67 typename std::enable_if<std::is_floating_point<T>::value>::type* =
68 nullptr>
69 static Timestamp seconds(T seconds) {
70 return Timestamp::us(seconds * 1e6);
71 }
72
73 template <typename T,
74 typename std::enable_if<std::is_floating_point<T>::value>::type* =
75 nullptr>
76 static Timestamp ms(T milliseconds) {
77 return Timestamp::us(milliseconds * 1e3);
78 }
79 template <typename T,
80 typename std::enable_if<std::is_floating_point<T>::value>::type* =
81 nullptr>
82 static Timestamp us(T microseconds) {
83 if (microseconds == std::numeric_limits<double>::infinity()) {
84 return Infinity();
85 } else {
86 RTC_DCHECK(!std::isnan(microseconds));
87 RTC_DCHECK_GE(microseconds, 0);
88 RTC_DCHECK_LT(microseconds, timestamp_impl::kPlusInfinityVal);
89 return Timestamp(rtc::dchecked_cast<int64_t>(microseconds));
90 }
91 }
92
93 template <typename T = int64_t>
94 typename std::enable_if<std::is_integral<T>::value, T>::type seconds() const {
95 return rtc::dchecked_cast<T>((us() + 500000) / 1000000);
96 }
97 template <typename T = int64_t>
98 typename std::enable_if<std::is_integral<T>::value, T>::type ms() const {
99 return rtc::dchecked_cast<T>((us() + 500) / 1000);
100 }
101 template <typename T = int64_t>
102 typename std::enable_if<std::is_integral<T>::value, T>::type us() const {
103 RTC_DCHECK(IsFinite());
104 return rtc::dchecked_cast<T>(microseconds_);
105 }
106
107 template <typename T>
108 typename std::enable_if<std::is_floating_point<T>::value, T>::type seconds()
109 const {
110 return us<T>() * 1e-6;
111 }
112 template <typename T>
113 typename std::enable_if<std::is_floating_point<T>::value, T>::type ms()
114 const {
115 return us<T>() * 1e-3;
116 }
117 template <typename T>
118 typename std::enable_if<std::is_floating_point<T>::value, T>::type us()
119 const {
120 if (IsInfinite()) {
121 return std::numeric_limits<T>::infinity();
122 } else {
123 return microseconds_;
124 }
125 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200126
Sebastian Jansson8e064192018-08-07 12:34:33 +0200127 constexpr bool IsInfinite() const {
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200128 return microseconds_ == timestamp_impl::kPlusInfinityVal;
129 }
Sebastian Jansson8e064192018-08-07 12:34:33 +0200130 constexpr bool IsFinite() const { return !IsInfinite(); }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200131 TimeDelta operator-(const Timestamp& other) const {
132 return TimeDelta::us(us() - other.us());
133 }
134 Timestamp operator-(const TimeDelta& delta) const {
135 return Timestamp::us(us() - delta.us());
136 }
137 Timestamp operator+(const TimeDelta& delta) const {
138 return Timestamp::us(us() + delta.us());
139 }
140 Timestamp& operator-=(const TimeDelta& other) {
141 microseconds_ -= other.us();
142 return *this;
143 }
144 Timestamp& operator+=(const TimeDelta& other) {
145 microseconds_ += other.us();
146 return *this;
147 }
148 bool operator==(const Timestamp& other) const {
149 return microseconds_ == other.microseconds_;
150 }
151 bool operator!=(const Timestamp& other) const {
152 return microseconds_ != other.microseconds_;
153 }
Sebastian Janssonec2eb222018-05-24 12:32:05 +0200154 bool operator<=(const Timestamp& other) const {
155 return microseconds_ <= other.microseconds_;
156 }
157 bool operator>=(const Timestamp& other) const {
158 return microseconds_ >= other.microseconds_;
159 }
160 bool operator>(const Timestamp& other) const {
161 return microseconds_ > other.microseconds_;
162 }
163 bool operator<(const Timestamp& other) const {
164 return microseconds_ < other.microseconds_;
165 }
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200166
167 private:
Sebastian Jansson8e064192018-08-07 12:34:33 +0200168 explicit constexpr Timestamp(int64_t us) : microseconds_(us) {}
Sebastian Jansson30bd4032018-04-13 13:56:17 +0200169 int64_t microseconds_;
170};
171
172std::string ToString(const Timestamp& value);
173
174} // namespace webrtc
175
Sebastian Jansson6fae6ec2018-05-08 10:43:18 +0200176#endif // API_UNITS_TIMESTAMP_H_