15 #ifndef SHAKA_EMBEDDED_VARIANT_H_ 16 #define SHAKA_EMBEDDED_VARIANT_H_ 23 #include <type_traits> 35 template <
typename... Choices>
40 #define SHAKA_MAX(a, b) ((a) > (b) ? (a) : (b)) 42 template <
typename... Types>
46 template <
typename T,
typename... Rest>
48 : std::integral_constant<size_t, SHAKA_MAX(sizeof(T),
49 get_max_size<Rest...>::value)> {
56 template <
size_t I,
typename... Choices>
58 template <
size_t I,
typename T,
typename... Choices>
60 static_assert(I > 0,
"Bad specialization chosen.");
63 template <
typename T,
typename... Choices>
68 template <
size_t I,
typename... Choices>
71 template <
size_t I,
typename... Choices>
73 typename std::add_lvalue_reference<
typename std::add_const<
77 template <
typename T,
typename... Choices>
79 template <
typename T,
typename... Choices>
81 static constexpr
const size_t index = 0;
83 template <
typename T,
typename A,
typename... Choices>
85 static_assert(!std::is_same<T, A>::value,
"Bad specialization chosen");
86 static constexpr
const size_t index =
94 template <
typename Arg,
typename T,
typename... Choices>
99 template <
bool CanConstruct,
typename Dummy =
void>
101 static constexpr
const size_t index = 0;
103 template <
typename Dummy>
104 struct Helper<false, Dummy> {
105 static constexpr
const size_t index =
110 static constexpr
const size_t index =
111 Helper<std::is_constructible<T, Arg&&>::value>::index;
119 template <
typename T,
typename... Rest>
129 new (&value_) T(other.
value_);
138 new (&value_) T(std::move(other.value_));
141 rest_.
move(std::move(other.rest_), i - 1);
146 get_const_reference_at_t<I, T, Rest...>
get()
const {
156 template <
size_t I,
typename... U>
158 EmplaceHelper<I, U...>::emplace(
this, std::forward<U>(args)...);
166 rest_.~union_<Rest...>();
172 return value_ == other.
value_;
174 return rest_.equals(other.
rest_, i - 1);
178 template <
size_t I,
typename... U>
179 struct EmplaceHelper {
180 static void emplace(
union_* that, U&&... args) {
182 that->
rest_.template emplace<I - 1>(std::forward<U>(args)...);
185 template <
typename... U>
186 struct EmplaceHelper<0, U...> {
187 static void emplace(
union_* that, U&&... args) {
188 new (&that->
value_) T(std::forward<U>(args)...);
192 template <
size_t I,
typename Dummy =
void>
194 static get_const_reference_at_t<I, T, Rest...>
get(
const union_* that) {
195 return that->rest_.template
get<I - 1>();
199 return that->rest_.template
get<I - 1>();
202 template <
typename Dummy>
203 struct GetHelper<0, Dummy> {
204 static const T&
get(
const union_* that) {
208 static T&
get(
union_* that) {
219 template <
typename T>
229 new (&value_) T(other.
value_);
234 new (&value_) T(std::move(other.value_));
238 const T&
get()
const {
239 static_assert(I == 0,
"Index out of range");
245 static_assert(I == 0,
"Index out of range");
250 template <
size_t I,
typename... U>
252 static_assert(I == 0,
"Index out of range");
253 new (&value_) T(std::forward<U>(args)...);
263 return value_ == other.
value_;
273 template <
typename T>
275 template <
typename... Choices>
280 template <
size_t I,
typename Variant>
282 template <
size_t I,
typename... Choices>
287 template <
size_t I,
typename Variant>
300 template <
typename... Types>
304 union_.template emplace<0>();
311 union_.template emplace<I>(std::forward<U>(value));
316 union_.copy(other.union_, other.index_);
320 union_.move(std::move(other.union_), other.index_);
324 union_.reset(index_);
328 union_.reset(index_);
329 union_.copy(other.union_, other.index_);
330 index_ = other.index_;
334 union_.reset(index_);
335 union_.move(std::move(other.union_), other.index_);
336 index_ = other.index_;
344 template <
typename T,
typename... Args>
347 union_.reset(index_);
348 union_.template emplace<I>(std::forward<Args>(args)...);
350 return union_.template get<I>();
353 template <
size_t I,
typename... Args>
355 union_.reset(index_);
356 union_.template emplace<I>(std::forward<Args>(args)...);
358 return union_.template get<I>();
362 template <
typename...>
364 template <
typename... Choices>
368 template <
size_t I,
typename... Choices>
371 template <
size_t I,
typename... Choices>
374 template <
typename T,
typename... Choices>
375 friend const T&
get(
const variant<Choices...>&);
376 template <
typename T,
typename... Choices>
377 friend T&
get(
variant<Choices...>&);
378 template <
typename T,
typename... Choices>
379 friend T&&
get(
variant<Choices...>&&);
381 template <
size_t I,
typename... Choices>
382 friend typename std::add_const<
385 template <
size_t I,
typename... Choices>
388 template <
typename T,
typename... Choices>
390 template <
typename T,
typename... Choices>
401 using size_type =
typename std::conditional<
402 sizeof...(Types) <= std::numeric_limits<uint8_t>::max(), uint8_t,
403 typename std::conditional<
sizeof...(Types) <=
404 std::numeric_limits<uint16_t>::max(),
408 bool equals(
const variant& other)
const {
409 return index_ == other.index_ && union_.equals(other.union_, index_);
415 return union_.template get<I>();
421 return union_.template get<I>();
427 return std::move(union_.template get<I>());
435 template <
typename... Choices>
438 return lhs.equals(rhs);
441 template <
typename... Choices>
444 return !(lhs == rhs);
448 template <
typename T,
typename... Choices>
451 return variant.
index() == I;
455 template <
size_t I,
typename... Choices>
458 return variant.template get<I>();
461 template <
size_t I,
typename... Choices>
464 return variant.template get<I>();
467 template <
typename T,
typename... Choices>
470 return variant.template get<I>();
473 template <
typename T,
typename... Choices>
476 return variant.template get<I>();
479 template <
typename T,
typename... Choices>
482 return std::move(
variant.template get<I>());
486 template <
size_t I,
typename... Choices>
489 if (variant.
index() == I)
490 return &variant.template get<I>();
495 template <
size_t I,
typename... Choices>
498 if (variant.
index() == I)
499 return &variant.template get<I>();
504 template <
typename T,
typename... Choices>
507 if (variant.
index() == I)
508 return &variant.template get<I>();
513 template <
typename T,
typename... Choices>
516 if (variant.
index() == I)
517 return &variant.template get<I>();
524 #endif // SHAKA_EMBEDDED_VARIANT_H_
bool equals(const union_ &other, size_t i) const
void move(union_ &&other, size_t i)
bool operator==(const optional< A > &lhs, const optional< B > &rhs)
T && get(variant< Choices... > &&variant)
bool operator!=(const optional< A > &lhs, const optional< B > &rhs)
std::add_const< variant_alternative_t< I, variant< Choices... > > >::type * get_if(const variant< Choices... > &variant)
#define SHAKA_NON_COPYABLE_OR_MOVABLE_TYPE(Type)
void copy(const union_ &other, size_t i)
T & emplace(Args &&... args)
variant & operator=(variant &&other)
bool equals(const union_ &other, size_t i) const
variant & operator=(const variant &other)
void move(union_ &&other, size_t i)
typename get_type_at< I - 1, Choices... >::type type
void emplace(U &&... args)
variant_alternative_t< I, variant > & emplace(Args &&... args)
variant(const variant &other)
typename std::add_lvalue_reference< typename std::add_const< typename get_type_at< I, Choices... >::type >::type >::type get_const_reference_at_t
typename impl::get_type_at< I, Choices... >::type type
typename get_type_at< I, Choices... >::type get_type_at_t
void copy(const union_ &other, size_t i)
void emplace(U &&... args)
bool holds_alternative(const variant< Choices... > &variant)
typename variant_alternative< I, Variant >::type variant_alternative_t