2#include <ossia/detail/config.hpp>
4#include <ossia/detail/variant.hpp>
6#include <boost/mp11.hpp>
11struct nullable_variant_index
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
21OSSIA_MAXIMUM_INLINE
constexpr bool
22operator==(nullable_variant_index lhs, nullable_variant_index rhs)
noexcept
24 return lhs.value == rhs.value;
26OSSIA_MAXIMUM_INLINE
constexpr bool
27operator!=(nullable_variant_index lhs, nullable_variant_index rhs)
noexcept
29 return lhs.value != rhs.value;
31OSSIA_MAXIMUM_INLINE
constexpr bool
32operator<(nullable_variant_index lhs, nullable_variant_index rhs)
noexcept
34 return lhs.value < rhs.value;
37template <
typename... Args>
38struct nullable_variant
39 :
public ossia_variant_alias::variant<ossia_variant_alias::monostate, Args...>
42 typename ossia_variant_alias::variant<ossia_variant_alias::monostate, Args...>;
45 static constexpr nullable_variant_index npos{0};
48 static constexpr nullable_variant_index index_of() noexcept
50 if constexpr(!boost::mp11::mp_contains<base, T>::value)
53 return {boost::mp11::mp_find<base, T>::value};
56 OSSIA_MAXIMUM_INLINE
constexpr operator bool() const noexcept
58 return this->index() != 0;
61 OSSIA_MAXIMUM_INLINE
constexpr nullable_variant_index which() const noexcept
63 return nullable_variant_index{this->index()};
67 OSSIA_MAXIMUM_INLINE
constexpr T* target() noexcept
69 return ossia_variant_alias::get_if<T>(
this);
72 OSSIA_MAXIMUM_INLINE
constexpr const T* target() const noexcept
74 return ossia_variant_alias::get_if<T>(
this);
78 OSSIA_MAXIMUM_INLINE
constexpr void* target() noexcept {
return this; }
80 OSSIA_MAXIMUM_INLINE
constexpr const void* target() const noexcept {
return this; }
91template <
typename F,
typename... Args>
92OSSIA_MAXIMUM_INLINE
auto apply(F&& visitor, ossia::nullable_variant<Args...>& variant)
95 return ossia_variant_alias::visit(visitor, variant);
97template <
typename F,
typename... Args>
98OSSIA_MAXIMUM_INLINE
auto
99apply(F&& visitor,
const ossia::nullable_variant<Args...>& variant) ->
decltype(
auto)
101 return ossia_variant_alias::visit(visitor, variant);
103template <
typename F,
typename... Args>
104OSSIA_MAXIMUM_INLINE
auto apply(F&& visitor, ossia::nullable_variant<Args...>&& variant)
107 return ossia_variant_alias::visit(visitor, std::move(variant));
110template <
typename F,
typename... Args>
111OSSIA_MAXIMUM_INLINE
auto
112apply_nonnull(F&& visitor, ossia::nullable_variant<Args...>& variant) ->
decltype(
auto)
116 return ossia_variant_alias::visit(visitor, variant);
120 ossia_do_throw(std::runtime_error,
"apply_nonnull called on invalid variant");
123template <
typename F,
typename... Args>
124OSSIA_MAXIMUM_INLINE
auto
125apply_nonnull(F&& visitor,
const ossia::nullable_variant<Args...>& variant)
130 return ossia_variant_alias::visit(visitor, variant);
134 ossia_do_throw(std::runtime_error,
"apply_nonnull called on invalid variant");
137template <
typename F,
typename... Args>
138OSSIA_MAXIMUM_INLINE
auto
139apply_nonnull(F&& visitor, ossia::nullable_variant<Args...>&& variant) ->
decltype(
auto)
143 return ossia_variant_alias::visit(visitor, std::move(variant));
147 ossia_do_throw(std::runtime_error,
"apply_nonnull called on invalid variant");
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)
157 return ossia_variant_alias::visit(visitor, v1, v2);
161 ossia_do_throw(std::runtime_error,
"apply_nonnull called on invalid variant");
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)
171 return ossia_variant_alias::visit(visitor, v1, v2);
175 ossia_do_throw(std::runtime_error,
"apply_nonnull called on invalid variant");
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)
185 return ossia_variant_alias::visit(visitor, std::move(v1), std::move(v2));
189 ossia_do_throw(std::runtime_error,
"apply_nonnull called on invalid variant");
193template <
typename... Ts>
194OSSIA_MAXIMUM_INLINE
constexpr bool
195operator==(
const nullable_variant<Ts...>& lhs,
const nullable_variant<Ts...>& rhs)
197 return ((
const typename nullable_variant<Ts...>::base&)lhs)
198 == ((
const typename nullable_variant<Ts...>::base&)rhs);
200template <
typename... Ts>
201OSSIA_MAXIMUM_INLINE
constexpr bool
202operator!=(
const nullable_variant<Ts...>& lhs,
const nullable_variant<Ts...>& rhs)
204 return ((
const typename nullable_variant<Ts...>::base&)lhs)
205 != ((
const typename nullable_variant<Ts...>::base&)rhs);
207template <
typename... Ts>
208OSSIA_MAXIMUM_INLINE
constexpr bool
209operator<(
const nullable_variant<Ts...>& lhs,
const nullable_variant<Ts...>& rhs)
211 return ((
const typename nullable_variant<Ts...>::base&)lhs)
212 < ((
const typename nullable_variant<Ts...>::base&)rhs);
214template <
typename... Ts>
215OSSIA_MAXIMUM_INLINE
constexpr bool
216operator>(
const nullable_variant<Ts...>& lhs,
const nullable_variant<Ts...>& rhs)
218 return ((
const typename nullable_variant<Ts...>::base&)lhs)
219 > ((
const typename nullable_variant<Ts...>::base&)rhs);
221template <
typename... Ts>
222OSSIA_MAXIMUM_INLINE
constexpr bool
223operator<=(
const nullable_variant<Ts...>& lhs,
const nullable_variant<Ts...>& rhs)
225 return ((
const typename nullable_variant<Ts...>::base&)lhs)
226 <= ((
const typename nullable_variant<Ts...>::base&)rhs);
228template <
typename... Ts>
229OSSIA_MAXIMUM_INLINE
constexpr bool
230operator>=(
const nullable_variant<Ts...>& lhs,
const nullable_variant<Ts...>& rhs)
232 return ((
const typename nullable_variant<Ts...>::base&)lhs)
233 >= ((
const typename nullable_variant<Ts...>::base&)rhs);
236template <
typename L,
typename... Ts>
237OSSIA_MAXIMUM_INLINE
constexpr bool
238operator==(
const L& lhs,
const nullable_variant<Ts...>& rhs)
240 constexpr auto lhs_idx = nullable_variant<Ts...>::template index_of<L>();
241 static_assert(lhs_idx != nullable_variant<Ts...>::npos);
243 if(lhs_idx != rhs.which())
246 return lhs == *rhs.template target<L>();
249template <
typename L,
typename... Ts>
250OSSIA_MAXIMUM_INLINE
constexpr bool
251operator!=(
const L& lhs,
const nullable_variant<Ts...>& rhs)
253 constexpr auto lhs_idx = nullable_variant<Ts...>::template index_of<L>();
254 static_assert(lhs_idx != nullable_variant<Ts...>::npos);
256 if(lhs_idx != rhs.which())
259 return lhs != *rhs.template target<L>();
263template <
typename L,
typename... Ts>
264OSSIA_MAXIMUM_INLINE
constexpr bool
265operator<(
const L& lhs,
const nullable_variant<Ts...>& rhs)
267 constexpr auto lhs_idx = nullable_variant<Ts...>::template index_of<L>();
268 static_assert(lhs_idx != nullable_variant<Ts...>::npos);
270 if(lhs_idx < rhs.which())
272 else if(lhs_idx > rhs.which())
275 return lhs < *rhs.template target<L>();
279template <
typename L,
typename... Ts>
280OSSIA_MAXIMUM_INLINE
constexpr bool
281operator>(
const L& lhs,
const nullable_variant<Ts...>& rhs)
283 constexpr auto lhs_idx = nullable_variant<Ts...>::template index_of<L>();
284 static_assert(lhs_idx != nullable_variant<Ts...>::npos);
286 if(lhs_idx > rhs.which())
288 else if(lhs_idx < rhs.which())
291 return lhs > *rhs.template target<L>();
294template <
typename L,
typename... Ts>
295OSSIA_MAXIMUM_INLINE
constexpr bool
296operator<=(
const L& lhs,
const nullable_variant<Ts...>& rhs)
298 constexpr auto lhs_idx = nullable_variant<Ts...>::template index_of<L>();
299 static_assert(lhs_idx != nullable_variant<Ts...>::npos);
301 if(lhs_idx < rhs.which())
303 else if(lhs_idx > rhs.which())
306 return lhs <= *rhs.template target<L>();
309template <
typename L,
typename... Ts>
310OSSIA_MAXIMUM_INLINE
constexpr bool
311operator>=(
const L& lhs,
const nullable_variant<Ts...>& rhs)
313 constexpr auto lhs_idx = nullable_variant<Ts...>::template index_of<L>();
314 static_assert(lhs_idx != nullable_variant<Ts...>::npos);
316 if(lhs_idx > rhs.which())
318 else if(lhs_idx < rhs.which())
321 return lhs >= *rhs.template target<L>();
324template <
typename R,
typename... Ts>
325OSSIA_MAXIMUM_INLINE
constexpr bool
326operator==(
const nullable_variant<Ts...>& lhs,
const R& rhs)
328 constexpr auto rhs_idx = nullable_variant<Ts...>::template index_of<R>();
329 static_assert(rhs_idx != nullable_variant<Ts...>::npos);
331 if(lhs.which() != rhs_idx)
334 return *lhs.template target<R>() == rhs;
338template <
typename R,
typename... Ts>
339OSSIA_MAXIMUM_INLINE
constexpr bool
340operator!=(
const nullable_variant<Ts...>& lhs,
const R& rhs)
342 constexpr auto rhs_idx = nullable_variant<Ts...>::template index_of<R>();
343 static_assert(rhs_idx != nullable_variant<Ts...>::npos);
345 if(lhs.which() != rhs_idx)
348 return *lhs.template target<R>() != rhs;
352template <
typename R,
typename... Ts>
353OSSIA_MAXIMUM_INLINE
constexpr bool
354operator<(
const nullable_variant<Ts...>& lhs,
const R& rhs)
356 constexpr auto rhs_idx = nullable_variant<Ts...>::template index_of<R>();
357 static_assert(rhs_idx != nullable_variant<Ts...>::npos);
359 if(lhs.which() < rhs_idx)
361 else if(lhs.which() > rhs_idx)
364 return *lhs.template target<R>() < rhs;
367template <
typename R,
typename... Ts>
368OSSIA_MAXIMUM_INLINE
constexpr bool
369operator>(
const nullable_variant<Ts...>& lhs,
const R& rhs)
371 constexpr auto rhs_idx = nullable_variant<Ts...>::template index_of<R>();
372 static_assert(rhs_idx != nullable_variant<Ts...>::npos);
374 if(lhs.which() > rhs_idx)
376 else if(lhs.which() < rhs_idx)
379 return *lhs.template target<R>() > rhs;
382template <
typename R,
typename... Ts>
383OSSIA_MAXIMUM_INLINE
constexpr bool
384operator<=(
const nullable_variant<Ts...>& lhs,
const R& rhs)
386 constexpr auto rhs_idx = nullable_variant<Ts...>::template index_of<R>();
387 static_assert(rhs_idx != nullable_variant<Ts...>::npos);
389 if(lhs.which() < rhs_idx)
391 else if(lhs.which() > rhs_idx)
394 return *lhs.template target<R>() <= rhs;
397template <
typename R,
typename... Ts>
398OSSIA_MAXIMUM_INLINE
constexpr bool
399operator>=(
const nullable_variant<Ts...>& lhs,
const R& rhs)
401 constexpr auto rhs_idx = nullable_variant<Ts...>::template index_of<R>();
402 static_assert(rhs_idx != nullable_variant<Ts...>::npos);
404 if(lhs.which() > rhs_idx)
406 else if(lhs.which() < rhs_idx)
409 return *lhs.template target<R>() >= rhs;