OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
ossia/editor/scenario/time_value.hpp
Go to the documentation of this file.
1#pragma once
2#include <ossia/detail/config.hpp>
3
4#include <ossia/detail/flicks.hpp>
5#if defined(__APPLE__)
6#include <mach/time_value.h>
7#endif
8
9#include <ossia/math/safe_math.hpp>
10
11#include <cmath>
12
13#include <cassert>
14#include <cinttypes>
15#include <limits>
16
20namespace ossia
21{
22using physical_time = int64_t;
29struct OSSIA_EXPORT time_value
30{
31 // infinity is everything beyond 2^60 as this is already a gigantic quantity
32 // (~50 years in flicks) we set ~2^62 as the default "infinity" value to
33 // allow for some leeway and make sure we won't hit integer overflow in any
34 // reasonable cases
35 static const constexpr int64_t infinite_min = std::numeric_limits<int64_t>::max() / 8;
36 static const constexpr int64_t infinity = std::numeric_limits<int64_t>::max() / 2;
37
38 constexpr time_value& operator=(bool d) noexcept = delete;
39 constexpr time_value& operator=(double d) noexcept = delete;
40 constexpr time_value& operator=(float d) noexcept = delete;
41 constexpr time_value& operator=(uint64_t d) noexcept = delete;
42
43 constexpr time_value& operator=(int64_t d) noexcept
44 {
45 impl = d;
46 return *this;
47 }
48
50 constexpr time_value& operator+=(double d) noexcept = delete;
51 constexpr time_value& operator+=(float d) noexcept = delete;
52
53 constexpr time_value& operator+=(int64_t d) noexcept
54 {
55 *this = *this + time_value{d};
56 return *this;
57 }
58
59 constexpr time_value& operator+=(ossia::time_value t) noexcept
60 {
61 if(infinite() || t.infinite())
62 impl = infinity;
63 else
64 impl += t.impl;
65
66 return *this;
67 }
68
70 constexpr time_value& operator-=(double d) noexcept = delete;
71 constexpr time_value& operator-=(int64_t d) noexcept
72 {
73 if(infinite())
74 impl = infinity;
75 else
76 impl -= d;
77
78 return *this;
79 }
80
81 constexpr time_value& operator-=(ossia::time_value t) noexcept
82 {
83 if(infinite() || t.infinite())
84 impl = infinity;
85 else
86 impl -= t.impl;
87
88 return *this;
89 }
90
91 [[nodiscard]] constexpr time_value operator-() const noexcept
92 {
93 return infinite() ? time_value{impl} : time_value{-impl};
94 }
95
97 // not constexpr because of isnan
98 /* constexpr */ time_value operator+(double d) const noexcept
99 {
100 assert(!ossia::safe_isnan(d));
101 assert(d < static_cast<double>(infinite_min));
102 return *this + time_value{int64_t(d)};
103 }
104 constexpr time_value operator+(int64_t d) const noexcept
105 {
106 return *this + time_value{d};
107 }
108 constexpr time_value operator+(uint64_t d) const noexcept
109 {
110 assert(d < infinite_min);
111 return *this + time_value{int64_t(d)};
112 }
113 constexpr time_value operator-(int64_t d) const noexcept
114 {
115 return *this + time_value{-d};
116 }
117 constexpr time_value operator-(uint64_t d) const noexcept
118 {
119 assert(d < infinite_min);
120 return *this + time_value{-int64_t(d)};
121 }
122
123 static constexpr bool
124 add_is_infinite(const ossia::time_value& lhs, const ossia::time_value& rhs) noexcept
125 {
126 if(lhs.infinite() || rhs.infinite())
127 {
128 return true;
129 }
130 else if(lhs.impl >= 0 && rhs.impl >= 0)
131 {
132 uint64_t l = lhs.impl;
133 uint64_t r = rhs.impl;
134 return l + r >= infinite_min;
135 }
136 else if(lhs.impl >= 0 && rhs.impl < 0)
137 {
138 return false;
139 }
140 else if(lhs.impl < 0 && rhs.impl >= 0)
141 {
142 return false;
143 }
144 else if(lhs.impl < 0 && rhs.impl < 0)
145 {
146 // TODO have a better underflow check
147 uint64_t l = -lhs.impl;
148 uint64_t r = -rhs.impl;
149 return l + r >= infinite_min;
150 }
151
152 return false;
153 }
154
155 static constexpr bool
156 sub_is_infinite(const ossia::time_value& lhs, const ossia::time_value& rhs) noexcept
157 {
158 if(lhs.infinite() || rhs.infinite())
159 {
160 return true;
161 }
162 else if(lhs.impl >= 0 && rhs.impl >= 0)
163 {
164 return false;
165 }
166 else if(lhs.impl >= 0 && rhs.impl < 0)
167 {
168 uint64_t l = lhs.impl;
169 uint64_t r = -rhs.impl;
170 return l + r >= infinite_min;
171 }
172 else if(lhs.impl < 0 && rhs.impl >= 0)
173 {
174 uint64_t l = -lhs.impl;
175 uint64_t r = rhs.impl;
176 return l + r >= infinite_min;
177 }
178 else if(lhs.impl < 0 && rhs.impl < 0)
179 {
180 return false;
181 }
182
183 return false;
184 }
185
186 constexpr time_value operator+(ossia::time_value t) const noexcept
187 {
188 if(add_is_infinite(*this, t))
189 return time_value{infinity};
190
191 return time_value{impl + t.impl};
192 }
193
195 // not constexpr because of isnan
196 /* constexpr */ time_value operator-(double d) const noexcept
197 {
198 assert(!ossia::safe_isnan(d));
199 assert(d < static_cast<double>(infinite_min));
200 return *this - time_value{int64_t(d)};
201 }
202
203 constexpr time_value operator-(ossia::time_value t) const noexcept
204 {
205 if(sub_is_infinite(*this, t))
206 return time_value{infinity};
207
208 return time_value{impl - t.impl};
209 }
210
213 constexpr time_value operator*(float d) const noexcept
214 {
215 return infinite() ? time_value{impl} : time_value{int64_t(impl * d)};
216 }
217
218 constexpr time_value operator*(double d) const noexcept
219 {
220 return infinite() ? time_value{impl} : time_value{int64_t(impl * d)};
221 }
222
223 constexpr time_value operator*(int32_t d) const noexcept
224 {
225 return infinite() ? time_value{impl} : time_value{impl * d};
226 }
227
228 constexpr time_value operator*(int64_t d) const noexcept
229 {
230 return infinite() ? time_value{impl} : time_value{impl * d};
231 }
232
233 constexpr time_value operator*(uint32_t d) const noexcept
234 {
235 return infinite() ? time_value{impl} : time_value{impl * d};
236 }
237
238 constexpr time_value operator*(uint64_t d) const noexcept
239 {
240 return infinite() ? time_value{impl} : time_value{int64_t(impl * d)};
241 }
242
243 friend constexpr double operator/(time_value lhs, time_value rhs) noexcept
244 {
245 return double(lhs.impl) / double(rhs.impl);
246 }
247
250 [[nodiscard]] constexpr bool infinite() const noexcept { return impl >= infinite_min; }
251 constexpr time_value operator%(time_value d) const noexcept
252 {
253 return time_value{impl % d.impl};
254 }
255 constexpr bool operator==(ossia::time_value rhs) const noexcept
256 {
257 return (infinite() && rhs.infinite()) || (impl == rhs.impl);
258 }
259 constexpr bool operator!=(ossia::time_value rhs) const noexcept
260 {
261 return (infinite() != rhs.infinite()) || (impl != rhs.impl);
262 }
263 constexpr bool operator<(ossia::time_value rhs) const noexcept
264 {
265 return !(infinite() && rhs.infinite()) && (impl < rhs.impl);
266 }
267 constexpr bool operator>(ossia::time_value rhs) const noexcept
268 {
269 return !(infinite() && rhs.infinite()) && (impl > rhs.impl);
270 }
271 // Two infinities compare equal, so they are also <= and >= each other;
272 // strict < and > stay false for them.
273 constexpr bool operator<=(ossia::time_value rhs) const noexcept
274 {
275 return (infinite() && rhs.infinite()) || (impl <= rhs.impl);
276 }
277 constexpr bool operator>=(ossia::time_value rhs) const noexcept
278 {
279 return (infinite() && rhs.infinite()) || (impl >= rhs.impl);
280 }
281
282 int64_t impl;
283};
284
285constexpr inline time_value operator""_tv(long double v) noexcept
286{
287 return time_value{int64_t(v)};
288}
289
290constexpr inline time_value operator""_tv(unsigned long long v) noexcept
291{
292 return time_value{(int64_t)v};
293}
294
295const constexpr time_value Infinite{time_value::infinity};
296const constexpr time_value Zero{0};
297const constexpr time_value One{1};
298
299constexpr inline time_value abs(time_value t) noexcept
300{
301 return time_value{t.impl >= 0 ? t.impl : -t.impl};
302}
303
304constexpr inline time_value norm(time_value t1, time_value t2) noexcept
305{
306 if(t1.infinite() || t2.infinite())
307 return Infinite;
308 return time_value{t1.impl > t2.impl ? t1.impl - t2.impl : t2.impl - t1.impl};
309}
310
311inline constexpr int64_t to_sample(ossia::time_value t, double rate) noexcept
312{
313 const double samples_per_flicks = rate / ossia::flicks_per_second<double>;
314 return (rate > 0 && !t.infinite()) ? std::round(t.impl * samples_per_flicks) : 0;
315}
316
317}
318
319// static_assert(std::is_pod<ossia::time_value>::value, "bug introduced
320// somewhere");
Definition git_info.h:7
The time_value class.
Definition ossia/editor/scenario/time_value.hpp:30
time_value operator-(double d) const noexcept
substraction operator
Definition ossia/editor/scenario/time_value.hpp:196
constexpr time_value operator*(float d) const noexcept
multiplication operator.
Definition ossia/editor/scenario/time_value.hpp:213
constexpr time_value & operator-=(double d) noexcept=delete
self substraction operator
time_value operator+(double d) const noexcept
addition operator
Definition ossia/editor/scenario/time_value.hpp:98
constexpr bool infinite() const noexcept
is the time value infinite ?
Definition ossia/editor/scenario/time_value.hpp:250
constexpr time_value & operator+=(double d) noexcept=delete
self addition operator