1/*
2 * Copyright (C) 2016 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 {
41public:
42 static const ClockType clockType = ClockType::Monotonic;
43
44 // This is the epoch. So, x.secondsSinceEpoch() should be the same as x - MonotonicTime().
45 constexpr MonotonicTime() { }
46
47 // Call this if you know for sure that the double represents monotonic time according to the
48 // same time source as MonotonicTime. It must be in seconds.
49 static constexpr MonotonicTime fromRawSeconds(double value)
50 {
51 return MonotonicTime(value);
52 }
53
54 WTF_EXPORT_PRIVATE static MonotonicTime now();
55
56 static constexpr MonotonicTime infinity() { return fromRawSeconds(std::numeric_limits<double>::infinity()); }
57 static constexpr MonotonicTime nan() { return fromRawSeconds(std::numeric_limits<double>::quiet_NaN()); }
58
59 constexpr Seconds secondsSinceEpoch() const { return Seconds(m_value); }
60
61 MonotonicTime approximateMonotonicTime() const { return *this; }
62 WTF_EXPORT_PRIVATE WallTime approximateWallTime() const;
63
64 explicit constexpr operator bool() const { return !!m_value; }
65
66 constexpr MonotonicTime operator+(Seconds other) const
67 {
68 return fromRawSeconds(m_value + other.value());
69 }
70
71 constexpr MonotonicTime operator-(Seconds other) const
72 {
73 return fromRawSeconds(m_value - other.value());
74 }
75
76 Seconds operator%(Seconds other) const
77 {
78 return Seconds { fmod(m_value, other.value()) };
79 }
80
81 // Time is a scalar and scalars can be negated as this could arise from algebraic
82 // transformations. So, we allow it.
83 constexpr MonotonicTime operator-() const
84 {
85 return fromRawSeconds(-m_value);
86 }
87
88 MonotonicTime operator+=(Seconds other)
89 {
90 return *this = *this + other;
91 }
92
93 MonotonicTime operator-=(Seconds other)
94 {
95 return *this = *this - other;
96 }
97
98 constexpr Seconds operator-(MonotonicTime other) const
99 {
100 return Seconds(m_value - other.m_value);
101 }
102
103 constexpr bool operator==(MonotonicTime other) const
104 {
105 return m_value == other.m_value;
106 }
107
108 constexpr bool operator!=(MonotonicTime other) const
109 {
110 return m_value != other.m_value;
111 }
112
113 constexpr bool operator<(MonotonicTime other) const
114 {
115 return m_value < other.m_value;
116 }
117
118 constexpr bool operator>(MonotonicTime other) const
119 {
120 return m_value > other.m_value;
121 }
122
123 constexpr bool operator<=(MonotonicTime other) const
124 {
125 return m_value <= other.m_value;
126 }
127
128 constexpr bool operator>=(MonotonicTime other) const
129 {
130 return m_value >= other.m_value;
131 }
132
133 WTF_EXPORT_PRIVATE void dump(PrintStream&) const;
134
135 MonotonicTime isolatedCopy() const
136 {
137 return *this;
138 }
139
140 template<class Encoder>
141 void encode(Encoder& encoder) const
142 {
143 encoder << m_value;
144 }
145
146 template<class Decoder>
147 static Optional<MonotonicTime> decode(Decoder& decoder)
148 {
149 Optional<double> time;
150 decoder >> time;
151 if (!time)
152 return WTF::nullopt;
153 return MonotonicTime::fromRawSeconds(*time);
154 }
155
156 template<class Decoder>
157 static bool decode(Decoder& decoder, MonotonicTime& time)
158 {
159 double value;
160 if (!decoder.decode(value))
161 return false;
162
163 time = MonotonicTime::fromRawSeconds(value);
164 return true;
165 }
166
167 struct MarkableTraits;
168
169private:
170 constexpr MonotonicTime(double rawValue)
171 : m_value(rawValue)
172 {
173 }
174
175 double m_value { 0 };
176};
177
178struct MonotonicTime::MarkableTraits {
179 static bool isEmptyValue(MonotonicTime time)
180 {
181 return std::isnan(time.m_value);
182 }
183
184 static constexpr MonotonicTime emptyValue()
185 {
186 return MonotonicTime::nan();
187 }
188};
189
190} // namespace WTF
191
192namespace std {
193
194inline bool isnan(WTF::MonotonicTime time)
195{
196 return std::isnan(time.secondsSinceEpoch().value());
197}
198
199inline bool isinf(WTF::MonotonicTime time)
200{
201 return std::isinf(time.secondsSinceEpoch().value());
202}
203
204inline bool isfinite(WTF::MonotonicTime time)
205{
206 return std::isfinite(time.secondsSinceEpoch().value());
207}
208
209} // namespace std
210
211using WTF::MonotonicTime;
212