1/*
2 * Copyright (C) 2016-2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include <wtf/ClockType.h>
29#include <wtf/Seconds.h>
30
31namespace WTF {
32
33class WallTime;
34class PrintStream;
35
36// The current time according to a monotonic clock. Monotonic clocks don't go backwards and
37// possibly don't count downtime. This uses floating point internally so that you can reason about
38// infinity and other things that arise in math. It's acceptable to use this to wrap NaN times,
39// negative times, and infinite times, so long as they are all relative to the same clock.
40class MonotonicTime final {
41 WTF_MAKE_FAST_ALLOCATED;
42public:
43 static constexpr ClockType clockType = ClockType::Monotonic;
44
45 // This is the epoch. So, x.secondsSinceEpoch() should be the same as x - MonotonicTime().
46 constexpr MonotonicTime() { }
47
48 // Call this if you know for sure that the double represents monotonic time according to the
49 // same time source as MonotonicTime. It must be in seconds.
50 static constexpr MonotonicTime fromRawSeconds(double value)
51 {
52 return MonotonicTime(value);
53 }
54
55 WTF_EXPORT_PRIVATE static MonotonicTime now();
56
57 static constexpr MonotonicTime infinity() { return fromRawSeconds(std::numeric_limits<double>::infinity()); }
58 static constexpr MonotonicTime nan() { return fromRawSeconds(std::numeric_limits<double>::quiet_NaN()); }
59
60 constexpr Seconds secondsSinceEpoch() const { return Seconds(m_value); }
61
62 MonotonicTime approximateMonotonicTime() const { return *this; }
63 WTF_EXPORT_PRIVATE WallTime approximateWallTime() const;
64
65 explicit constexpr operator bool() const { return !!m_value; }
66
67 constexpr MonotonicTime operator+(Seconds other) const
68 {
69 return fromRawSeconds(m_value + other.value());
70 }
71
72 constexpr MonotonicTime operator-(Seconds other) const
73 {
74 return fromRawSeconds(m_value - other.value());
75 }
76
77 Seconds operator%(Seconds other) const
78 {
79 return Seconds { fmod(m_value, other.value()) };
80 }
81
82 // Time is a scalar and scalars can be negated as this could arise from algebraic
83 // transformations. So, we allow it.
84 constexpr MonotonicTime operator-() const
85 {
86 return fromRawSeconds(-m_value);
87 }
88
89 MonotonicTime operator+=(Seconds other)
90 {
91 return *this = *this + other;
92 }
93
94 MonotonicTime operator-=(Seconds other)
95 {
96 return *this = *this - other;
97 }
98
99 constexpr Seconds operator-(MonotonicTime other) const
100 {
101 return Seconds(m_value - other.m_value);
102 }
103
104 constexpr bool operator==(MonotonicTime other) const
105 {
106 return m_value == other.m_value;
107 }
108
109 constexpr bool operator!=(MonotonicTime other) const
110 {
111 return m_value != other.m_value;
112 }
113
114 constexpr bool operator<(MonotonicTime other) const
115 {
116 return m_value < other.m_value;
117 }
118
119 constexpr bool operator>(MonotonicTime other) const
120 {
121 return m_value > other.m_value;
122 }
123
124 constexpr bool operator<=(MonotonicTime other) const
125 {
126 return m_value <= other.m_value;
127 }
128
129 constexpr bool operator>=(MonotonicTime other) const
130 {
131 return m_value >= other.m_value;
132 }
133
134 WTF_EXPORT_PRIVATE void dump(PrintStream&) const;
135
136 MonotonicTime isolatedCopy() const
137 {
138 return *this;
139 }
140
141 template<class Encoder>
142 void encode(Encoder& encoder) const
143 {
144 encoder << m_value;
145 }
146
147 template<class Decoder>
148 static Optional<MonotonicTime> decode(Decoder& decoder)
149 {
150 Optional<double> time;
151 decoder >> time;
152 if (!time)
153 return WTF::nullopt;
154 return MonotonicTime::fromRawSeconds(*time);
155 }
156
157 template<class Decoder>
158 static bool decode(Decoder& decoder, MonotonicTime& time)
159 {
160 double value;
161 if (!decoder.decode(value))
162 return false;
163
164 time = MonotonicTime::fromRawSeconds(value);
165 return true;
166 }
167
168 struct MarkableTraits;
169
170private:
171 constexpr MonotonicTime(double rawValue)
172 : m_value(rawValue)
173 {
174 }
175
176 double m_value { 0 };
177};
178
179struct MonotonicTime::MarkableTraits {
180 static bool isEmptyValue(MonotonicTime time)
181 {
182 return std::isnan(time.m_value);
183 }
184
185 static constexpr MonotonicTime emptyValue()
186 {
187 return MonotonicTime::nan();
188 }
189};
190
191} // namespace WTF
192
193namespace std {
194
195inline bool isnan(WTF::MonotonicTime time)
196{
197 return std::isnan(time.secondsSinceEpoch().value());
198}
199
200inline bool isinf(WTF::MonotonicTime time)
201{
202 return std::isinf(time.secondsSinceEpoch().value());
203}
204
205inline bool isfinite(WTF::MonotonicTime time)
206{
207 return std::isfinite(time.secondsSinceEpoch().value());
208}
209
210} // namespace std
211
212using WTF::MonotonicTime;
213