OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
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>
9namespace ossia
10{
11struct 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};
21OSSIA_MAXIMUM_INLINE constexpr bool
22operator==(nullable_variant_index lhs, nullable_variant_index rhs) noexcept
23{
24 return lhs.value == rhs.value;
25}
26OSSIA_MAXIMUM_INLINE constexpr bool
27operator!=(nullable_variant_index lhs, nullable_variant_index rhs) noexcept
28{
29 return lhs.value != rhs.value;
30}
31OSSIA_MAXIMUM_INLINE constexpr bool
32operator<(nullable_variant_index lhs, nullable_variant_index rhs) noexcept
33{
34 return lhs.value < rhs.value;
35}
36
37template <typename... Args>
38struct 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/*
84template<typename F, typename... Args>
85OSSIA_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*/
91template <typename F, typename... Args>
92OSSIA_MAXIMUM_INLINE auto apply(F&& visitor, ossia::nullable_variant<Args...>& variant)
93 -> decltype(auto)
94{
95 return ossia_variant_alias::visit(visitor, variant);
96}
97template <typename F, typename... Args>
98OSSIA_MAXIMUM_INLINE auto
99apply(F&& visitor, const ossia::nullable_variant<Args...>& variant) -> decltype(auto)
100{
101 return ossia_variant_alias::visit(visitor, variant);
102}
103template <typename F, typename... Args>
104OSSIA_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
110template <typename F, typename... Args>
111OSSIA_MAXIMUM_INLINE auto
112apply_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}
123template <typename F, typename... Args>
124OSSIA_MAXIMUM_INLINE auto
125apply_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}
137template <typename F, typename... Args>
138OSSIA_MAXIMUM_INLINE auto
139apply_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}
150template <typename F, typename... Args>
151OSSIA_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}
164template <typename F, typename... Args>
165OSSIA_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}
178template <typename F, typename... Args>
179OSSIA_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
193template <typename... Ts>
194OSSIA_MAXIMUM_INLINE constexpr bool
195operator==(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}
200template <typename... Ts>
201OSSIA_MAXIMUM_INLINE constexpr bool
202operator!=(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}
207template <typename... Ts>
208OSSIA_MAXIMUM_INLINE constexpr bool
209operator<(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}
214template <typename... Ts>
215OSSIA_MAXIMUM_INLINE constexpr bool
216operator>(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}
221template <typename... Ts>
222OSSIA_MAXIMUM_INLINE constexpr bool
223operator<=(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}
228template <typename... Ts>
229OSSIA_MAXIMUM_INLINE constexpr bool
230operator>=(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
236template <typename L, typename... Ts>
237OSSIA_MAXIMUM_INLINE constexpr bool
238operator==(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}
249template <typename L, typename... Ts>
250OSSIA_MAXIMUM_INLINE constexpr bool
251operator!=(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
263template <typename L, typename... Ts>
264OSSIA_MAXIMUM_INLINE constexpr bool
265operator<(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
279template <typename L, typename... Ts>
280OSSIA_MAXIMUM_INLINE constexpr bool
281operator>(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}
294template <typename L, typename... Ts>
295OSSIA_MAXIMUM_INLINE constexpr bool
296operator<=(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}
309template <typename L, typename... Ts>
310OSSIA_MAXIMUM_INLINE constexpr bool
311operator>=(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}
324template <typename R, typename... Ts>
325OSSIA_MAXIMUM_INLINE constexpr bool
326operator==(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
338template <typename R, typename... Ts>
339OSSIA_MAXIMUM_INLINE constexpr bool
340operator!=(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
352template <typename R, typename... Ts>
353OSSIA_MAXIMUM_INLINE constexpr bool
354operator<(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}
367template <typename R, typename... Ts>
368OSSIA_MAXIMUM_INLINE constexpr bool
369operator>(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}
382template <typename R, typename... Ts>
383OSSIA_MAXIMUM_INLINE constexpr bool
384operator<=(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}
397template <typename R, typename... Ts>
398OSSIA_MAXIMUM_INLINE constexpr bool
399operator>=(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