OSSIA
Open Scenario System for Interactive Application
nullable_variant.hpp
1 #pragma once
2 #include <ossia/detail/config.hpp>
3 
4 #include <ossia/detail/variant.hpp>
5 
6 #include <boost/mp11.hpp>
7 
8 #include <stdexcept>
9 namespace ossia
10 {
11 struct nullable_variant_index
12 {
13  std::size_t value;
14  OSSIA_MAXIMUM_INLINE constexpr bool valid() const noexcept { return value != 0; }
15  OSSIA_MAXIMUM_INLINE constexpr std::size_t index() const noexcept { return value; }
16  OSSIA_MAXIMUM_INLINE constexpr std::size_t to_std_index() const noexcept
17  {
18  return value - 1;
19  }
20 };
21 OSSIA_MAXIMUM_INLINE constexpr bool
22 operator==(nullable_variant_index lhs, nullable_variant_index rhs) noexcept
23 {
24  return lhs.value == rhs.value;
25 }
26 OSSIA_MAXIMUM_INLINE constexpr bool
27 operator!=(nullable_variant_index lhs, nullable_variant_index rhs) noexcept
28 {
29  return lhs.value != rhs.value;
30 }
31 OSSIA_MAXIMUM_INLINE constexpr bool
32 operator<(nullable_variant_index lhs, nullable_variant_index rhs) noexcept
33 {
34  return lhs.value < rhs.value;
35 }
36 
37 template <typename... Args>
38 struct nullable_variant
39  : public ossia_variant_alias::variant<ossia_variant_alias::monostate, Args...>
40 {
41  using base =
42  typename ossia_variant_alias::variant<ossia_variant_alias::monostate, Args...>;
43  using base::base;
44 
45  static constexpr nullable_variant_index npos{0};
46 
47  template <typename T>
48  static constexpr nullable_variant_index index_of() noexcept
49  {
50  if constexpr(!boost::mp11::mp_contains<base, T>::value)
51  return npos;
52  else
53  return {boost::mp11::mp_find<base, T>::value};
54  }
55 
56  OSSIA_MAXIMUM_INLINE constexpr operator bool() const noexcept
57  {
58  return this->index() != 0;
59  }
60 
61  OSSIA_MAXIMUM_INLINE constexpr nullable_variant_index which() const noexcept
62  {
63  return nullable_variant_index{this->index()};
64  }
65 
66  template <typename T>
67  OSSIA_MAXIMUM_INLINE constexpr T* target() noexcept
68  {
69  return ossia_variant_alias::get_if<T>(this);
70  }
71  template <typename T>
72  OSSIA_MAXIMUM_INLINE constexpr const T* target() const noexcept
73  {
74  return ossia_variant_alias::get_if<T>(this);
75  }
76 
77  // FIXME is this safe
78  OSSIA_MAXIMUM_INLINE constexpr void* target() noexcept { return this; }
79 
80  OSSIA_MAXIMUM_INLINE constexpr const void* target() const noexcept { return this; }
81 };
82 
83 /*
84 template<typename F, typename... Args>
85 OSSIA_MAXIMUM_INLINE auto visit(F&& visitor, Args&&... variants)
86  -> decltype(auto)
87 {
88  return ossia_variant_alias::visit(visitor, static_cast<Args&&>(variants)...);
89 }
90 */
91 template <typename F, typename... Args>
92 OSSIA_MAXIMUM_INLINE auto apply(F&& visitor, ossia::nullable_variant<Args...>& variant)
93  -> decltype(auto)
94 {
95  return ossia_variant_alias::visit(visitor, variant);
96 }
97 template <typename F, typename... Args>
98 OSSIA_MAXIMUM_INLINE auto
99 apply(F&& visitor, const ossia::nullable_variant<Args...>& variant) -> decltype(auto)
100 {
101  return ossia_variant_alias::visit(visitor, variant);
102 }
103 template <typename F, typename... Args>
104 OSSIA_MAXIMUM_INLINE auto apply(F&& visitor, ossia::nullable_variant<Args...>&& variant)
105  -> decltype(auto)
106 {
107  return ossia_variant_alias::visit(visitor, std::move(variant));
108 }
109 
110 template <typename F, typename... Args>
111 OSSIA_MAXIMUM_INLINE auto
112 apply_nonnull(F&& visitor, ossia::nullable_variant<Args...>& variant) -> decltype(auto)
113 {
114  if(variant)
115  {
116  return ossia_variant_alias::visit(visitor, variant);
117  }
118  else
119  {
120  ossia_do_throw(std::runtime_error, "apply_nonnull called on invalid variant");
121  }
122 }
123 template <typename F, typename... Args>
124 OSSIA_MAXIMUM_INLINE auto
125 apply_nonnull(F&& visitor, const ossia::nullable_variant<Args...>& variant)
126  -> decltype(auto)
127 {
128  if(variant)
129  {
130  return ossia_variant_alias::visit(visitor, variant);
131  }
132  else
133  {
134  ossia_do_throw(std::runtime_error, "apply_nonnull called on invalid variant");
135  }
136 }
137 template <typename F, typename... Args>
138 OSSIA_MAXIMUM_INLINE auto
139 apply_nonnull(F&& visitor, ossia::nullable_variant<Args...>&& variant) -> decltype(auto)
140 {
141  if(variant)
142  {
143  return ossia_variant_alias::visit(visitor, std::move(variant));
144  }
145  else
146  {
147  ossia_do_throw(std::runtime_error, "apply_nonnull called on invalid variant");
148  }
149 }
150 template <typename F, typename... Args>
151 OSSIA_MAXIMUM_INLINE auto apply_nonnull(
152  F&& visitor, ossia::nullable_variant<Args...>& v1,
153  ossia::nullable_variant<Args...>& v2) -> decltype(auto)
154 {
155  if(v1 && v2)
156  {
157  return ossia_variant_alias::visit(visitor, v1, v2);
158  }
159  else
160  {
161  ossia_do_throw(std::runtime_error, "apply_nonnull called on invalid variant");
162  }
163 }
164 template <typename F, typename... Args>
165 OSSIA_MAXIMUM_INLINE auto apply_nonnull(
166  F&& visitor, const ossia::nullable_variant<Args...>& v1,
167  const ossia::nullable_variant<Args...>& v2) -> decltype(auto)
168 {
169  if(v1 && v2)
170  {
171  return ossia_variant_alias::visit(visitor, v1, v2);
172  }
173  else
174  {
175  ossia_do_throw(std::runtime_error, "apply_nonnull called on invalid variant");
176  }
177 }
178 template <typename F, typename... Args>
179 OSSIA_MAXIMUM_INLINE auto apply_nonnull(
180  F&& visitor, ossia::nullable_variant<Args...>&& v1,
181  const ossia::nullable_variant<Args...>&& v2) -> decltype(auto)
182 {
183  if(v1 && v2)
184  {
185  return ossia_variant_alias::visit(visitor, std::move(v1), std::move(v2));
186  }
187  else
188  {
189  ossia_do_throw(std::runtime_error, "apply_nonnull called on invalid variant");
190  }
191 }
192 
193 template <typename... Ts>
194 OSSIA_MAXIMUM_INLINE constexpr bool
195 operator==(const nullable_variant<Ts...>& lhs, const nullable_variant<Ts...>& rhs)
196 {
197  return ((const typename nullable_variant<Ts...>::base&)lhs)
198  == ((const typename nullable_variant<Ts...>::base&)rhs);
199 }
200 template <typename... Ts>
201 OSSIA_MAXIMUM_INLINE constexpr bool
202 operator!=(const nullable_variant<Ts...>& lhs, const nullable_variant<Ts...>& rhs)
203 {
204  return ((const typename nullable_variant<Ts...>::base&)lhs)
205  != ((const typename nullable_variant<Ts...>::base&)rhs);
206 }
207 template <typename... Ts>
208 OSSIA_MAXIMUM_INLINE constexpr bool
209 operator<(const nullable_variant<Ts...>& lhs, const nullable_variant<Ts...>& rhs)
210 {
211  return ((const typename nullable_variant<Ts...>::base&)lhs)
212  < ((const typename nullable_variant<Ts...>::base&)rhs);
213 }
214 template <typename... Ts>
215 OSSIA_MAXIMUM_INLINE constexpr bool
216 operator>(const nullable_variant<Ts...>& lhs, const nullable_variant<Ts...>& rhs)
217 {
218  return ((const typename nullable_variant<Ts...>::base&)lhs)
219  > ((const typename nullable_variant<Ts...>::base&)rhs);
220 }
221 template <typename... Ts>
222 OSSIA_MAXIMUM_INLINE constexpr bool
223 operator<=(const nullable_variant<Ts...>& lhs, const nullable_variant<Ts...>& rhs)
224 {
225  return ((const typename nullable_variant<Ts...>::base&)lhs)
226  <= ((const typename nullable_variant<Ts...>::base&)rhs);
227 }
228 template <typename... Ts>
229 OSSIA_MAXIMUM_INLINE constexpr bool
230 operator>=(const nullable_variant<Ts...>& lhs, const nullable_variant<Ts...>& rhs)
231 {
232  return ((const typename nullable_variant<Ts...>::base&)lhs)
233  >= ((const typename nullable_variant<Ts...>::base&)rhs);
234 }
235 
236 template <typename L, typename... Ts>
237 OSSIA_MAXIMUM_INLINE constexpr bool
238 operator==(const L& lhs, const nullable_variant<Ts...>& rhs)
239 {
240  constexpr auto lhs_idx = nullable_variant<Ts...>::template index_of<L>();
241  static_assert(lhs_idx != nullable_variant<Ts...>::npos);
242  {
243  if(lhs_idx != rhs.which())
244  return false;
245  else
246  return lhs == *rhs.template target<L>();
247  }
248 }
249 template <typename L, typename... Ts>
250 OSSIA_MAXIMUM_INLINE constexpr bool
251 operator!=(const L& lhs, const nullable_variant<Ts...>& rhs)
252 {
253  constexpr auto lhs_idx = nullable_variant<Ts...>::template index_of<L>();
254  static_assert(lhs_idx != nullable_variant<Ts...>::npos);
255  {
256  if(lhs_idx != rhs.which())
257  return true;
258  else
259  return lhs != *rhs.template target<L>();
260  }
261 }
262 
263 template <typename L, typename... Ts>
264 OSSIA_MAXIMUM_INLINE constexpr bool
265 operator<(const L& lhs, const nullable_variant<Ts...>& rhs)
266 {
267  constexpr auto lhs_idx = nullable_variant<Ts...>::template index_of<L>();
268  static_assert(lhs_idx != nullable_variant<Ts...>::npos);
269  {
270  if(lhs_idx < rhs.which())
271  return true;
272  else if(lhs_idx > rhs.which())
273  return false;
274  else
275  return lhs < *rhs.template target<L>();
276  }
277 }
278 
279 template <typename L, typename... Ts>
280 OSSIA_MAXIMUM_INLINE constexpr bool
281 operator>(const L& lhs, const nullable_variant<Ts...>& rhs)
282 {
283  constexpr auto lhs_idx = nullable_variant<Ts...>::template index_of<L>();
284  static_assert(lhs_idx != nullable_variant<Ts...>::npos);
285  {
286  if(lhs_idx > rhs.which())
287  return true;
288  else if(lhs_idx < rhs.which())
289  return false;
290  else
291  return lhs > *rhs.template target<L>();
292  }
293 }
294 template <typename L, typename... Ts>
295 OSSIA_MAXIMUM_INLINE constexpr bool
296 operator<=(const L& lhs, const nullable_variant<Ts...>& rhs)
297 {
298  constexpr auto lhs_idx = nullable_variant<Ts...>::template index_of<L>();
299  static_assert(lhs_idx != nullable_variant<Ts...>::npos);
300  {
301  if(lhs_idx < rhs.which())
302  return true;
303  else if(lhs_idx > rhs.which())
304  return false;
305  else
306  return lhs <= *rhs.template target<L>();
307  }
308 }
309 template <typename L, typename... Ts>
310 OSSIA_MAXIMUM_INLINE constexpr bool
311 operator>=(const L& lhs, const nullable_variant<Ts...>& rhs)
312 {
313  constexpr auto lhs_idx = nullable_variant<Ts...>::template index_of<L>();
314  static_assert(lhs_idx != nullable_variant<Ts...>::npos);
315  {
316  if(lhs_idx > rhs.which())
317  return true;
318  else if(lhs_idx < rhs.which())
319  return false;
320  else
321  return lhs >= *rhs.template target<L>();
322  }
323 }
324 template <typename R, typename... Ts>
325 OSSIA_MAXIMUM_INLINE constexpr bool
326 operator==(const nullable_variant<Ts...>& lhs, const R& rhs)
327 {
328  constexpr auto rhs_idx = nullable_variant<Ts...>::template index_of<R>();
329  static_assert(rhs_idx != nullable_variant<Ts...>::npos);
330  {
331  if(lhs.which() != rhs_idx)
332  return false;
333  else
334  return *lhs.template target<R>() == rhs;
335  }
336 }
337 
338 template <typename R, typename... Ts>
339 OSSIA_MAXIMUM_INLINE constexpr bool
340 operator!=(const nullable_variant<Ts...>& lhs, const R& rhs)
341 {
342  constexpr auto rhs_idx = nullable_variant<Ts...>::template index_of<R>();
343  static_assert(rhs_idx != nullable_variant<Ts...>::npos);
344  {
345  if(lhs.which() != rhs_idx)
346  return true;
347  else
348  return *lhs.template target<R>() != rhs;
349  }
350 }
351 
352 template <typename R, typename... Ts>
353 OSSIA_MAXIMUM_INLINE constexpr bool
354 operator<(const nullable_variant<Ts...>& lhs, const R& rhs)
355 {
356  constexpr auto rhs_idx = nullable_variant<Ts...>::template index_of<R>();
357  static_assert(rhs_idx != nullable_variant<Ts...>::npos);
358  {
359  if(lhs.which() < rhs_idx)
360  return true;
361  else if(lhs.which() > rhs_idx)
362  return false;
363  else
364  return *lhs.template target<R>() < rhs;
365  }
366 }
367 template <typename R, typename... Ts>
368 OSSIA_MAXIMUM_INLINE constexpr bool
369 operator>(const nullable_variant<Ts...>& lhs, const R& rhs)
370 {
371  constexpr auto rhs_idx = nullable_variant<Ts...>::template index_of<R>();
372  static_assert(rhs_idx != nullable_variant<Ts...>::npos);
373  {
374  if(lhs.which() > rhs_idx)
375  return true;
376  else if(lhs.which() < rhs_idx)
377  return false;
378  else
379  return *lhs.template target<R>() > rhs;
380  }
381 }
382 template <typename R, typename... Ts>
383 OSSIA_MAXIMUM_INLINE constexpr bool
384 operator<=(const nullable_variant<Ts...>& lhs, const R& rhs)
385 {
386  constexpr auto rhs_idx = nullable_variant<Ts...>::template index_of<R>();
387  static_assert(rhs_idx != nullable_variant<Ts...>::npos);
388  {
389  if(lhs.which() < rhs_idx)
390  return true;
391  else if(lhs.which() > rhs_idx)
392  return false;
393  else
394  return *lhs.template target<R>() <= rhs;
395  }
396 }
397 template <typename R, typename... Ts>
398 OSSIA_MAXIMUM_INLINE constexpr bool
399 operator>=(const nullable_variant<Ts...>& lhs, const R& rhs)
400 {
401  constexpr auto rhs_idx = nullable_variant<Ts...>::template index_of<R>();
402  static_assert(rhs_idx != nullable_variant<Ts...>::npos);
403  {
404  if(lhs.which() > rhs_idx)
405  return true;
406  else if(lhs.which() < rhs_idx)
407  return false;
408  else
409  return *lhs.template target<R>() >= rhs;
410  }
411 }
412 
413 }
Definition: git_info.h:7