OSSIA
Open Scenario System for Interactive Application
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 <cmath>
10 
11 #include <cassert>
12 #include <cinttypes>
13 #include <limits>
14 
18 namespace ossia
19 {
20 using physical_time = int64_t;
27 struct OSSIA_EXPORT time_value
28 {
29  // infinity is everything beyond 2^60 as this is already a gigantic quantity
30  // (~50 years in flicks) we set ~2^62 as the default "infinity" value to
31  // allow for some leeway and make sure we won't hit integer overflow in any
32  // reasonable cases
33  static const constexpr int64_t infinite_min = std::numeric_limits<int64_t>::max() / 8;
34  static const constexpr int64_t infinity = std::numeric_limits<int64_t>::max() / 2;
35 
36  constexpr time_value& operator=(bool d) noexcept = delete;
37  constexpr time_value& operator=(double d) noexcept = delete;
38  constexpr time_value& operator=(float d) noexcept = delete;
39  constexpr time_value& operator=(uint64_t d) noexcept = delete;
40 
41  constexpr time_value& operator=(int64_t d) noexcept
42  {
43  impl = d;
44  return *this;
45  }
46 
48  constexpr time_value& operator+=(double d) noexcept = delete;
49  constexpr time_value& operator+=(float d) noexcept = delete;
50 
51  constexpr time_value& operator+=(int64_t d) noexcept
52  {
53  if(infinite())
54  impl = 0;
55  else
56  impl += d;
57 
58  return *this;
59  }
60 
61  constexpr time_value& operator+=(ossia::time_value t) noexcept
62  {
63  if(infinite() || t.infinite())
64  impl = infinity;
65  else
66  impl += t.impl;
67 
68  return *this;
69  }
70 
72  constexpr time_value& operator-=(double d) noexcept = delete;
73  constexpr time_value& operator-=(int64_t d) noexcept
74  {
75  if(infinite())
76  impl = infinity;
77  else
78  impl -= d;
79 
80  return *this;
81  }
82 
83  constexpr time_value& operator-=(ossia::time_value t) noexcept
84  {
85  if(infinite() || t.infinite())
86  impl = infinity;
87  else
88  impl -= t.impl;
89 
90  return *this;
91  }
92 
93  constexpr time_value& operator-() noexcept
94  {
95  if(!infinite())
96  impl = -impl;
97 
98  return *this;
99  }
100 
102  // not constexpr because of isnan
103  /* constexpr */ time_value operator+(double d) const noexcept
104  {
105  assert(!std::isnan(d));
106  assert(d < static_cast<double>(infinite_min));
107  return *this + time_value{int64_t(d)};
108  }
109  constexpr time_value operator+(int64_t d) const noexcept
110  {
111  return *this + time_value{d};
112  }
113  constexpr time_value operator+(uint64_t d) const noexcept
114  {
115  assert(d < infinite_min);
116  return *this + time_value{int64_t(d)};
117  }
118  constexpr time_value operator-(int64_t d) const noexcept
119  {
120  return *this + time_value{-d};
121  }
122  constexpr time_value operator-(uint64_t d) const noexcept
123  {
124  assert(d < infinite_min);
125  return *this + time_value{-int64_t(d)};
126  }
127 
128  static constexpr bool
129  add_is_infinite(const ossia::time_value& lhs, const ossia::time_value& rhs) noexcept
130  {
131  if(lhs.infinite() || rhs.infinite())
132  {
133  return true;
134  }
135  else if(lhs.impl >= 0 && rhs.impl >= 0)
136  {
137  uint64_t l = lhs.impl;
138  uint64_t r = rhs.impl;
139  return l + r >= infinite_min;
140  }
141  else if(lhs.impl >= 0 && rhs.impl < 0)
142  {
143  uint64_t l = lhs.impl;
144  return l + rhs.impl >= infinite_min;
145  }
146  else if(lhs.impl < 0 && rhs.impl >= 0)
147  {
148  uint64_t r = rhs.impl;
149  return lhs.impl + r >= infinite_min;
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(!std::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 
289 constexpr inline time_value operator"" _tv(long double v) noexcept
290 {
291  return time_value{int64_t(v)};
292 }
293 
294 constexpr inline time_value operator"" _tv(unsigned long long v) noexcept
295 {
296  return time_value{(int64_t)v};
297 }
298 
299 const constexpr time_value Infinite{time_value::infinity};
300 const constexpr time_value Zero{0};
301 const constexpr time_value One{1};
302 
303 constexpr inline time_value abs(time_value t) noexcept
304 {
305  return time_value{t.impl >= 0 ? t.impl : -t.impl};
306 }
307 
308 constexpr 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 
315 inline 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
constexpr OSSIA_INLINE auto max(const T a, const U b) noexcept -> typename std::conditional<(sizeof(T) > sizeof(U)), T, U >::type
max function tailored for values
Definition: math.hpp:96
The time_value class.
Definition: ossia/editor/scenario/time_value.hpp:28
constexpr time_value & operator+=(double d) noexcept=delete
self addition operator
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
time_value operator+(double d) const noexcept
addition operator
Definition: ossia/editor/scenario/time_value.hpp:103
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 substraction operator