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 if(infinite())
56 impl = 0;
57 else
58 impl += d;
59
60 return *this;
61 }
62
63 constexpr time_value& operator+=(ossia::time_value t) noexcept
64 {
65 if(infinite() || t.infinite())
66 impl = infinity;
67 else
68 impl += t.impl;
69
70 return *this;
71 }
72
74 constexpr time_value& operator-=(double d) noexcept = delete;
75 constexpr time_value& operator-=(int64_t d) noexcept
76 {
77 if(infinite())
78 impl = infinity;
79 else
80 impl -= d;
81
82 return *this;
83 }
84
85 constexpr time_value& operator-=(ossia::time_value t) noexcept
86 {
87 if(infinite() || t.infinite())
88 impl = infinity;
89 else
90 impl -= t.impl;
91
92 return *this;
93 }
94
95 constexpr time_value& operator-() noexcept
96 {
97 if(!infinite())
98 impl = -impl;
99
100 return *this;
101 }
102
104 // not constexpr because of isnan
105 /* constexpr */ time_value operator+(double d) const noexcept
106 {
107 assert(!ossia::safe_isnan(d));
108 assert(d < static_cast<double>(infinite_min));
109 return *this + time_value{int64_t(d)};
110 }
111 constexpr time_value operator+(int64_t d) const noexcept
112 {
113 return *this + time_value{d};
114 }
115 constexpr time_value operator+(uint64_t d) const noexcept
116 {
117 assert(d < infinite_min);
118 return *this + time_value{int64_t(d)};
119 }
120 constexpr time_value operator-(int64_t d) const noexcept
121 {
122 return *this + time_value{-d};
123 }
124 constexpr time_value operator-(uint64_t d) const noexcept
125 {
126 assert(d < infinite_min);
127 return *this + time_value{-int64_t(d)};
128 }
129
130 static constexpr bool
131 add_is_infinite(const ossia::time_value& lhs, const ossia::time_value& rhs) noexcept
132 {
133 if(lhs.infinite() || rhs.infinite())
134 {
135 return true;
136 }
137 else if(lhs.impl >= 0 && rhs.impl >= 0)
138 {
139 uint64_t l = lhs.impl;
140 uint64_t r = rhs.impl;
141 return l + r >= infinite_min;
142 }
143 else if(lhs.impl >= 0 && rhs.impl < 0)
144 {
145 return false;
146 }
147 else if(lhs.impl < 0 && rhs.impl >= 0)
148 {
149 return false;
150 }
151 else if(lhs.impl < 0 && rhs.impl < 0)
152 {
153 // TODO have a better underflow check
154 uint64_t l = -lhs.impl;
155 uint64_t r = -rhs.impl;
156 return l + r >= infinite_min;
157 }
158
159 return false;
160 }
161
162 static constexpr bool
163 sub_is_infinite(const ossia::time_value& lhs, const ossia::time_value& rhs) noexcept
164 {
165 if(lhs.infinite() || rhs.infinite())
166 {
167 return true;
168 }
169 else if(lhs.impl >= 0 && rhs.impl >= 0)
170 {
171 return false;
172 }
173 else if(lhs.impl >= 0 && rhs.impl < 0)
174 {
175 uint64_t l = lhs.impl;
176 uint64_t r = -rhs.impl;
177 return l + r >= infinite_min;
178 }
179 else if(lhs.impl < 0 && rhs.impl >= 0)
180 {
181 uint64_t l = -lhs.impl;
182 uint64_t r = rhs.impl;
183 return l + r >= infinite_min;
184 }
185 else if(lhs.impl < 0 && rhs.impl < 0)
186 {
187 return false;
188 }
189
190 return false;
191 }
192
193 constexpr time_value operator+(ossia::time_value t) const noexcept
194 {
195 if(add_is_infinite(*this, t))
196 return time_value{infinity};
197
198 return time_value{impl + t.impl};
199 }
200
202 // not constexpr because of isnan
203 /* constexpr */ time_value operator-(double d) const noexcept
204 {
205 assert(!ossia::safe_isnan(d));
206 assert(d < static_cast<double>(infinite_min));
207 return *this - time_value{int64_t(d)};
208 }
209
210 constexpr time_value operator-(ossia::time_value t) const noexcept
211 {
212 if(sub_is_infinite(*this, t))
213 return time_value{infinity};
214
215 return time_value{impl - t.impl};
216 }
217
219 constexpr time_value operator*(float d) const noexcept
220 {
221 return time_value{int64_t(impl * d)};
222 }
223
224 constexpr time_value operator*(double d) const noexcept
225 {
226 return time_value{int64_t(impl * d)};
227 }
228
229 constexpr time_value operator*(int32_t d) const noexcept
230 {
231 return time_value{impl * d};
232 }
233
234 constexpr time_value operator*(int64_t d) const noexcept
235 {
236 return time_value{impl * d};
237 }
238
239 constexpr time_value operator*(uint32_t d) const noexcept
240 {
241 return time_value{impl * d};
242 }
243
244 constexpr time_value operator*(uint64_t d) const noexcept
245 {
246 return time_value{int64_t(impl * d)};
247 }
248
249 friend constexpr double operator/(time_value lhs, time_value rhs) noexcept
250 {
251 return double(lhs.impl) / double(rhs.impl);
252 }
253
256 [[nodiscard]] constexpr bool infinite() const noexcept { return impl >= infinite_min; }
257 constexpr time_value operator%(time_value d) const noexcept
258 {
259 return time_value{impl % d.impl};
260 }
261 constexpr bool operator==(ossia::time_value rhs) const noexcept
262 {
263 return (infinite() && rhs.infinite()) || (impl == rhs.impl);
264 }
265 constexpr bool operator!=(ossia::time_value rhs) const noexcept
266 {
267 return (infinite() != rhs.infinite()) || (impl != rhs.impl);
268 }
269 constexpr bool operator<(ossia::time_value rhs) const noexcept
270 {
271 return !(infinite() && rhs.infinite()) && (impl < rhs.impl);
272 }
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 constexpr bool operator>=(ossia::time_value rhs) const noexcept
282 {
283 return !(infinite() && rhs.infinite()) && (impl >= rhs.impl);
284 }
285
286 int64_t impl;
287};
288
289constexpr inline time_value operator""_tv(long double v) noexcept
290{
291 return time_value{int64_t(v)};
292}
293
294constexpr inline time_value operator""_tv(unsigned long long v) noexcept
295{
296 return time_value{(int64_t)v};
297}
298
299const constexpr time_value Infinite{time_value::infinity};
300const constexpr time_value Zero{0};
301const constexpr time_value One{1};
302
303constexpr inline time_value abs(time_value t) noexcept
304{
305 return time_value{t.impl >= 0 ? t.impl : -t.impl};
306}
307
308constexpr inline time_value norm(time_value t1, time_value t2) noexcept
309{
310 if(t1.infinite() || t2.infinite())
311 return Infinite;
312 return time_value{t1.impl > t2.impl ? t1.impl - t2.impl : t2.impl - t1.impl};
313}
314
315inline constexpr int64_t to_sample(ossia::time_value t, double rate) noexcept
316{
317 const double samples_per_flicks = rate / ossia::flicks_per_second<double>;
318 return (rate > 0 && !t.infinite()) ? std::round(t.impl * samples_per_flicks) : 0;
319}
320
321}
322
323// static_assert(std::is_pod<ossia::time_value>::value, "bug introduced
324// 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:203
constexpr time_value operator*(float d) const noexcept
multiplication operator
Definition ossia/editor/scenario/time_value.hpp:219
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:105
constexpr bool infinite() const noexcept
is the time value infinite ?
Definition ossia/editor/scenario/time_value.hpp:256
constexpr time_value & operator+=(double d) noexcept=delete
self addition operator