1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef META_BASE_TIMESPAN_H
17 #define META_BASE_TIMESPAN_H
18 
19 #include <stdint.h>
20 
21 #include <meta/base/meta_types.h>
22 #include <meta/base/namespace.h>
23 
META_BEGIN_NAMESPACE()24 META_BEGIN_NAMESPACE()
25 
26 /**
27  * @brief Microsecond precision time span type.
28  * The int64_t min and max values are used to mark infinities.
29  */
30 class TimeSpan final {
31 public:
32     constexpr TimeSpan() : value_(0) {}
33 
34     ~TimeSpan() = default;
35 
36     constexpr TimeSpan(const TimeSpan& rhs) noexcept = default;
37     constexpr TimeSpan(TimeSpan&& rhs) noexcept = default;
38 
39     constexpr TimeSpan& operator=(const TimeSpan& rhs) noexcept = default;
40     constexpr TimeSpan& operator=(TimeSpan&& rhs) noexcept = default;
41 
42     constexpr int64_t ToSeconds() const noexcept
43     {
44         return value_ / 1000000;
45     }
46 
47     constexpr float ToSecondsFloat() const noexcept
48     {
49         return static_cast<float>(value_) / 1000000.0f;
50     }
51 
52     constexpr int64_t ToMilliseconds() const noexcept
53     {
54         return Round(static_cast<float>(value_) / 1000.f);
55     }
56 
57     constexpr int64_t ToMicroseconds() const noexcept
58     {
59         return value_;
60     }
61 
62     constexpr void SetSeconds(float seconds) noexcept
63     {
64         value_ = ToMicroseconds(seconds);
65     }
66 
67     constexpr void SetMilliseconds(int64_t milliseconds) noexcept
68     {
69         value_ = milliseconds * 1000;
70     }
71 
72     constexpr void SetMicroseconds(int64_t microseconds) noexcept
73     {
74         value_ = microseconds;
75     }
76 
77     constexpr bool IsFinite() const
78     {
79         return value_ != INT64_MIN && value_ != INT64_MAX;
80     }
81 
82     static constexpr TimeSpan Seconds(float seconds) noexcept
83     {
84         return TimeSpan(ToMicroseconds(seconds));
85     }
86 
87     static constexpr TimeSpan Milliseconds(int64_t milliseconds) noexcept
88     {
89         return TimeSpan(milliseconds * 1000);
90     }
91 
92     static constexpr TimeSpan Microseconds(int64_t microseconds) noexcept
93     {
94         return TimeSpan(microseconds);
95     }
96 
97     static constexpr TimeSpan Max() noexcept
98     {
99         return TimeSpan(INT64_MAX);
100     }
101 
102     static constexpr TimeSpan Zero() noexcept
103     {
104         return TimeSpan(0);
105     }
106 
107     static constexpr TimeSpan Infinite() noexcept
108     {
109         return TimeSpan(INT64_MAX);
110     }
111 
112     constexpr bool operator==(const TimeSpan& rhs) const noexcept
113     {
114         return value_ == rhs.value_;
115     }
116 
117     constexpr bool operator!=(const TimeSpan& rhs) const noexcept
118     {
119         return value_ != rhs.value_;
120     }
121 
122     constexpr bool operator<(const TimeSpan& rhs) const noexcept
123     {
124         return value_ < rhs.value_;
125     }
126 
127     constexpr bool operator>(const TimeSpan& rhs) const noexcept
128     {
129         return value_ > rhs.value_;
130     }
131 
132     constexpr bool operator>=(const TimeSpan& rhs) const noexcept
133     {
134         return value_ >= rhs.value_;
135     }
136 
137     constexpr bool operator<=(const TimeSpan& rhs) const noexcept
138     {
139         return value_ <= rhs.value_;
140     }
141 
142     constexpr TimeSpan operator-() const noexcept
143     {
144         TimeSpan result;
145 
146         if (*this == Infinite()) {
147             result = TimeSpan(INT64_MIN);
148         } else if (value_ == INT64_MIN) {
149             result = TimeSpan::Infinite();
150         } else {
151             result = TimeSpan(-value_);
152         }
153 
154         return result;
155     }
156 
157     constexpr TimeSpan operator+(const TimeSpan& rhs) const noexcept
158     {
159         TimeSpan result;
160 
161         if (value_ == INT64_MAX || rhs.value_ == INT64_MAX) {
162             result = Infinite();
163         } else if (value_ == INT64_MIN || rhs.value_ == INT64_MIN) {
164             result = -Infinite();
165         } else {
166             result = TimeSpan(value_ + rhs.value_);
167         }
168 
169         return result;
170     }
171 
172     constexpr TimeSpan operator*(const TimeSpan& rhs) const noexcept
173     {
174         TimeSpan result;
175 
176         if (value_ == INT64_MAX || rhs.value_ == INT64_MAX) {
177             result = Infinite();
178         } else if (value_ == INT64_MIN || rhs.value_ == INT64_MIN) {
179             result = -Infinite();
180         } else {
181             result = TimeSpan(value_ * rhs.value_);
182         }
183 
184         return result;
185     }
186 
187     constexpr TimeSpan operator/(const TimeSpan& rhs) const noexcept
188     {
189         TimeSpan result;
190 
191         if (value_ == INT64_MAX || rhs.value_ == INT64_MAX || rhs.value_ == 0) {
192             result = Infinite();
193         } else if (value_ == INT64_MIN || rhs.value_ == INT64_MIN) {
194             result = -Infinite();
195         } else {
196             result = TimeSpan(value_ / rhs.value_);
197         }
198 
199         return result;
200     }
201 
202     constexpr TimeSpan operator-(const TimeSpan& rhs) const noexcept
203     {
204         return *this + -rhs;
205     }
206 
207     constexpr TimeSpan& operator+=(const TimeSpan& rhs) noexcept
208     {
209         *this = *this + rhs;
210         return *this;
211     }
212 
213     constexpr TimeSpan& operator-=(const TimeSpan& rhs) noexcept
214     {
215         *this = *this - rhs;
216         return *this;
217     }
218 
219     constexpr TimeSpan& operator*=(const TimeSpan& rhs) noexcept
220     {
221         *this = *this * rhs;
222         return *this;
223     }
224 
225     constexpr TimeSpan& operator/=(const TimeSpan& rhs) noexcept
226     {
227         *this = *this / rhs;
228         return *this;
229     }
230 
231     constexpr TimeSpan operator*(int n) const noexcept
232     {
233         TimeSpan result;
234 
235         if (IsFinite()) {
236             result = TimeSpan(n * value_);
237         } else if (n == 0) {
238             result = Zero();
239         } else if (n > 0) {
240             result = *this;
241         } else {
242             result = -*this;
243         }
244 
245         return result;
246     }
247 
248     constexpr TimeSpan operator*(float n) const noexcept
249     {
250         TimeSpan result;
251 
252         if (IsFinite()) {
253             result = TimeSpan(Round(n * static_cast<float>(value_)));
254         } else if (n == 0) {
255             result = Zero();
256         } else if (n > 0) {
257             result = *this;
258         } else {
259             result = -*this;
260         }
261 
262         return result;
263     }
264 
265     constexpr TimeSpan operator/(float n) const noexcept
266     {
267         TimeSpan result;
268 
269         if (n == 0) {
270             result = Infinite();
271         } else if (IsFinite()) {
272             result = TimeSpan(Round(static_cast<float>(value_) / n));
273         } else if (n > 0) {
274             result = *this;
275         } else {
276             result = -*this;
277         }
278 
279         return result;
280     }
281 
282     friend constexpr TimeSpan operator*(int n, const TimeSpan& rhs)
283     {
284         return rhs * n;
285     }
286     friend constexpr TimeSpan operator*(float n, const TimeSpan& rhs)
287     {
288         return rhs * n;
289     }
290     friend constexpr TimeSpan operator/(float n, const TimeSpan& rhs)
291     {
292         return rhs / n;
293     }
294 
295 private:
296     explicit constexpr TimeSpan(int64_t microseconds) : value_(microseconds) {}
297 
298     static constexpr int64_t Round(float in) noexcept
299     {
300         in = in < 0 ? in - 0.5f : in + 0.5f;
301         return static_cast<int64_t>(in);
302     }
303 
304     static constexpr int64_t ToMicroseconds(float seconds) noexcept
305     {
306         return Round(seconds * 1000000.0f);
307     }
308 
309 private:
310     // Value stored in microseconds
311     int64_t value_ = 0;
312 };
313 
314 namespace TimeSpanLiterals {
315 constexpr TimeSpan operator"" _s(unsigned long long seconds)
316 {
317     return TimeSpan::Seconds(static_cast<float>(seconds));
318 }
319 
320 constexpr TimeSpan operator"" _ms(unsigned long long milliseconds)
321 {
322     return TimeSpan::Milliseconds(static_cast<int64_t>(milliseconds));
323 }
324 
325 constexpr TimeSpan operator"" _us(unsigned long long microseconds)
326 {
327     return TimeSpan::Microseconds(static_cast<int64_t>(microseconds));
328 }
329 } // namespace TimeSpanLiterals
330 
331 META_END_NAMESPACE()
332 
333 META_TYPE(META_NS::TimeSpan)
334 
335 #endif
336