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/MathExtras.h>
29#include <wtf/Optional.h>
30
31namespace WTF {
32
33class MonotonicTime;
34class PrintStream;
35class TimeWithDynamicClockType;
36class WallTime;
37
38class Seconds {
39public:
40 constexpr Seconds() { }
41
42 explicit constexpr Seconds(double value)
43 : m_value(value)
44 {
45 }
46
47 constexpr double value() const { return m_value; }
48
49 constexpr double minutes() const { return m_value / 60; }
50 constexpr double seconds() const { return m_value; }
51 constexpr double milliseconds() const { return seconds() * 1000; }
52 constexpr double microseconds() const { return milliseconds() * 1000; }
53 constexpr double nanoseconds() const { return microseconds() * 1000; }
54
55 // Keep in mind that Seconds is held in double. If the value is not in range of 53bit integer, the result may not be precise.
56 template<typename T> T minutesAs() const { static_assert(std::is_integral<T>::value, ""); return clampToAccepting64<T>(minutes()); }
57 template<typename T> T secondsAs() const { static_assert(std::is_integral<T>::value, ""); return clampToAccepting64<T>(seconds()); }
58 template<typename T> T millisecondsAs() const { static_assert(std::is_integral<T>::value, ""); return clampToAccepting64<T>(milliseconds()); }
59 template<typename T> T microsecondsAs() const { static_assert(std::is_integral<T>::value, ""); return clampToAccepting64<T>(microseconds()); }
60 template<typename T> T nanosecondsAs() const { static_assert(std::is_integral<T>::value, ""); return clampToAccepting64<T>(nanoseconds()); }
61
62 static constexpr Seconds fromMinutes(double minutes)
63 {
64 return Seconds(minutes * 60);
65 }
66
67 static constexpr Seconds fromHours(double hours)
68 {
69 return Seconds(hours * 3600);
70 }
71
72 static constexpr Seconds fromMilliseconds(double milliseconds)
73 {
74 return Seconds(milliseconds / 1000);
75 }
76
77 static constexpr Seconds fromMicroseconds(double microseconds)
78 {
79 return fromMilliseconds(microseconds / 1000);
80 }
81
82 static constexpr Seconds fromNanoseconds(double nanoseconds)
83 {
84 return fromMicroseconds(nanoseconds / 1000);
85 }
86
87 static constexpr Seconds infinity()
88 {
89 return Seconds(std::numeric_limits<double>::infinity());
90 }
91
92 static constexpr Seconds nan()
93 {
94 return Seconds(std::numeric_limits<double>::quiet_NaN());
95 }
96
97 explicit constexpr operator bool() const { return !!m_value; }
98
99 constexpr Seconds operator+(Seconds other) const
100 {
101 return Seconds(value() + other.value());
102 }
103
104 constexpr Seconds operator-(Seconds other) const
105 {
106 return Seconds(value() - other.value());
107 }
108
109 constexpr Seconds operator-() const
110 {
111 return Seconds(-value());
112 }
113
114 // It makes sense to consider scaling a duration, like, "I want to wait 5 times as long as
115 // last time!".
116 constexpr Seconds operator*(double scalar) const
117 {
118 return Seconds(value() * scalar);
119 }
120
121 constexpr Seconds operator/(double scalar) const
122 {
123 return Seconds(value() / scalar);
124 }
125
126 // It's reasonable to think about ratios between Seconds.
127 constexpr double operator/(Seconds other) const
128 {
129 return value() / other.value();
130 }
131
132 Seconds operator%(double scalar) const
133 {
134 return Seconds(fmod(value(), scalar));
135 }
136
137 // This solves for r, where:
138 //
139 // floor(this / other) + r / other = this / other
140 //
141 // Therefore, if this is Seconds then r is Seconds.
142 Seconds operator%(Seconds other) const
143 {
144 return Seconds(fmod(value(), other.value()));
145 }
146
147 Seconds& operator+=(Seconds other)
148 {
149 return *this = *this + other;
150 }
151
152 Seconds& operator-=(Seconds other)
153 {
154 return *this = *this - other;
155 }
156
157 Seconds& operator*=(double scalar)
158 {
159 return *this = *this * scalar;
160 }
161
162 Seconds& operator/=(double scalar)
163 {
164 return *this = *this / scalar;
165 }
166
167 Seconds& operator%=(double scalar)
168 {
169 return *this = *this % scalar;
170 }
171
172 Seconds& operator%=(Seconds other)
173 {
174 return *this = *this % other;
175 }
176
177 WTF_EXPORT_PRIVATE WallTime operator+(WallTime) const;
178 WTF_EXPORT_PRIVATE MonotonicTime operator+(MonotonicTime) const;
179 WTF_EXPORT_PRIVATE TimeWithDynamicClockType operator+(const TimeWithDynamicClockType&) const;
180
181 WTF_EXPORT_PRIVATE WallTime operator-(WallTime) const;
182 WTF_EXPORT_PRIVATE MonotonicTime operator-(MonotonicTime) const;
183 WTF_EXPORT_PRIVATE TimeWithDynamicClockType operator-(const TimeWithDynamicClockType&) const;
184
185 constexpr bool operator==(Seconds other) const
186 {
187 return m_value == other.m_value;
188 }
189
190 constexpr bool operator!=(Seconds other) const
191 {
192 return m_value != other.m_value;
193 }
194
195 constexpr bool operator<(Seconds other) const
196 {
197 return m_value < other.m_value;
198 }
199
200 constexpr bool operator>(Seconds other) const
201 {
202 return m_value > other.m_value;
203 }
204
205 constexpr bool operator<=(Seconds other) const
206 {
207 return m_value <= other.m_value;
208 }
209
210 constexpr bool operator>=(Seconds other) const
211 {
212 return m_value >= other.m_value;
213 }
214
215 WTF_EXPORT_PRIVATE void dump(PrintStream&) const;
216
217 Seconds isolatedCopy() const
218 {
219 return *this;
220 }
221
222 template<class Encoder>
223 void encode(Encoder& encoder) const
224 {
225 encoder << m_value;
226 }
227
228 template<class Decoder>
229 static Optional<Seconds> decode(Decoder& decoder)
230 {
231 Optional<double> seconds;
232 decoder >> seconds;
233 if (!seconds)
234 return WTF::nullopt;
235 return Seconds(*seconds);
236 }
237
238 template<class Decoder>
239 static bool decode(Decoder& decoder, Seconds& seconds)
240 {
241 double value;
242 if (!decoder.decode(value))
243 return false;
244
245 seconds = Seconds(value);
246 return true;
247 }
248
249 struct MarkableTraits;
250
251private:
252 double m_value { 0 };
253};
254
255WTF_EXPORT_PRIVATE void sleep(Seconds);
256
257struct Seconds::MarkableTraits {
258 static bool isEmptyValue(Seconds seconds)
259 {
260 return std::isnan(seconds.value());
261 }
262
263 static constexpr Seconds emptyValue()
264 {
265 return Seconds::nan();
266 }
267};
268
269inline namespace seconds_literals {
270
271constexpr Seconds operator"" _min(long double minutes)
272{
273 return Seconds::fromMinutes(minutes);
274}
275
276constexpr Seconds operator"" _h(long double hours)
277{
278 return Seconds::fromHours(hours);
279}
280
281constexpr Seconds operator"" _s(long double seconds)
282{
283 return Seconds(seconds);
284}
285
286constexpr Seconds operator"" _ms(long double milliseconds)
287{
288 return Seconds::fromMilliseconds(milliseconds);
289}
290
291constexpr Seconds operator"" _us(long double microseconds)
292{
293 return Seconds::fromMicroseconds(microseconds);
294}
295
296constexpr Seconds operator"" _ns(long double nanoseconds)
297{
298 return Seconds::fromNanoseconds(nanoseconds);
299}
300
301constexpr Seconds operator"" _min(unsigned long long minutes)
302{
303 return Seconds::fromMinutes(minutes);
304}
305
306constexpr Seconds operator"" _h(unsigned long long hours)
307{
308 return Seconds::fromHours(hours);
309}
310
311constexpr Seconds operator"" _s(unsigned long long seconds)
312{
313 return Seconds(seconds);
314}
315
316constexpr Seconds operator"" _ms(unsigned long long milliseconds)
317{
318 return Seconds::fromMilliseconds(milliseconds);
319}
320
321constexpr Seconds operator"" _us(unsigned long long microseconds)
322{
323 return Seconds::fromMicroseconds(microseconds);
324}
325
326constexpr Seconds operator"" _ns(unsigned long long nanoseconds)
327{
328 return Seconds::fromNanoseconds(nanoseconds);
329}
330
331} // inline seconds_literals
332
333} // namespace WTF
334
335using WTF::sleep;
336
337namespace std {
338
339inline bool isnan(WTF::Seconds seconds)
340{
341 return std::isnan(seconds.value());
342}
343
344inline bool isinf(WTF::Seconds seconds)
345{
346 return std::isinf(seconds.value());
347}
348
349inline bool isfinite(WTF::Seconds seconds)
350{
351 return std::isfinite(seconds.value());
352}
353
354} // namespace std
355
356using namespace WTF::seconds_literals;
357using WTF::Seconds;
358