7 #include <initializer_list>
10 #ifndef PLUGIFY_VARIANT_NO_CONSTEXPR_EMPLACE
16 #ifndef PLUGIFY_VARIANT_NO_STD_HASH
17 # include <functional>
20 #define PLG_FWD(x) static_cast<decltype(x)&&>(x)
21 #define PLG_MOV(x) static_cast< std::remove_reference_t<decltype(x)>&& >(x)
23 #include <plugify/macro.hpp>
26 #if PLUGIFY_EXCEPTIONS
27 class bad_variant_access final :
public std::exception {
28 const char* message =
"";
30 explicit bad_variant_access(
const char* str) noexcept : message{str} {}
31 bad_variant_access() noexcept = default;
32 bad_variant_access(const bad_variant_access&) noexcept = default;
33 bad_variant_access& operator=(const bad_variant_access&) noexcept = default;
34 const
char* what() const noexcept
override {
return message; }
46 template<std::
size_t Index>
49 template<std::
size_t Index>
57 constexpr
int find_first_true(
bool (&&arr)[N]) {
58 for (
int k = 0; k < N; ++k)
64 template<
class T,
class... Ts>
65 inline constexpr
bool appears_exactly_once = (
static_cast<unsigned short>(std::is_same_v<T, Ts>) + ...) == 1;
69 #if __has_builtin(__type_pack_element)
70 template<std::size_t K,
class... Ts>
71 using type_pack_element = __type_pack_element<K, Ts...>;
73 template<
unsigned char = 1>
78 template<std::size_t Idx,
class T,
class... Ts>
79 using f =
typename find_type_i<(Idx != 1)>::
template f<Idx - 1, Ts...>;
84 template<std::size_t,
class T,
class... Ts>
88 template<std::size_t K,
class... Ts>
89 using type_pack_element =
typename find_type_i<(K != 0)>::
template f<K, Ts...>;
97 template<std::
size_t N,
class A>
101 requires requires { arr1<A>{std::declval<T>()}; }
105 template<
class Seq,
class... Args>
108 template<std::size_t... Idx,
class... Args>
114 template<
class T,
class... Ts>
115 using best_overload_match =
typename decltype(
116 make_overload<std::make_index_sequence<
sizeof...(Ts)>, Ts...>{}
117 (std::declval<T>(), std::declval<T>())
120 template<
class T,
class... Ts>
121 concept has_non_ambiguous_match =
122 requires {
typename best_overload_match<T, Ts...>; };
126 template<
class From,
class To>
127 concept convertible = std::is_convertible_v<From, To>;
130 concept has_eq_comp = requires (T a, T b) {
131 { a == b } -> convertible<bool>;
135 concept has_lesser_comp = requires (T a, T b) {
136 { a < b } -> convertible<bool>;
140 concept has_less_or_eq_comp = requires (T a, T b) {
141 { a <= b } -> convertible<bool>;
147 constexpr
void operator()(T&& elem,
auto index_)
const {
148 a.template emplace_no_dtor<index_>(
static_cast<T&&
>(elem));
153 template<
class E,
class T>
154 constexpr
void destruct(T& obj) {
155 if constexpr (not std::is_trivially_destructible_v<E>)
166 using union_index_t = unsigned;
168 #define TRAIT(trait) (std::is_##trait##_v<A> && std::is_##trait##_v<B>)
170 #define SFM(signature, trait) \
171 signature = default; \
172 signature requires (TRAIT(trait) and not TRAIT(trivially_##trait)) {}
176 #define INJECT_UNION_SFM(X) \
177 SFM(constexpr X (const X &), copy_constructible) \
178 SFM(constexpr X (X&&) noexcept, move_constructible) \
179 SFM(constexpr X& operator=(const X&), copy_assignable) \
180 SFM(constexpr X& operator=(X&&) noexcept, move_assignable) \
181 SFM(constexpr ~X(), destructible)
183 template<
bool IsLeaf>
189 template<
class A,
class B>
190 static constexpr
auto elem_size = not(std::is_same_v<B, dummy_type>) ? 2 : 1;
192 template<std::
size_t,
class>
193 static constexpr
char ctor_branch = 0;
198 template<
class A,
class B>
199 static constexpr
auto elem_size = A::elem_size + B::elem_size;
201 template<std::
size_t Index,
class A>
202 static constexpr
char ctor_branch = (Index < A::elem_size) ? 1 : 2;
205 template<
bool IsLeaf,
class A,
class B>
216 template<std::size_t Index,
class... Args>
219 : a{in_place_index<Index>,
static_cast<Args&&
>(args)...}
222 template<std::size_t Index,
class... Args>
225 : b{in_place_index<Index - A::elem_size>,
static_cast<Args&&
>(args)...}
228 template<
class... Args>
231 : a{
static_cast<Args&&
>(args)...}
234 template<
class... Args>
237 : b{
static_cast<Args&&
>(args)...}
241 requires (std::is_same_v<dummy_type, B>)
245 template<union_index_t Index>
246 constexpr
auto& get() {
247 if constexpr (IsLeaf) {
248 if constexpr (Index == 0)
253 if constexpr (Index < A::elem_size)
254 return a.template get<Index>();
256 return b.template get<Index - A::elem_size>();
260 template<union_index_t Index>
261 constexpr
const auto& get()
const {
262 return const_cast<union_node&
>(*this).get<Index>();
268 #undef INJECT_UNION_SFM
276 constexpr
unsigned char pick_next(
unsigned remaining) {
277 return static_cast<unsigned char>(remaining >= 2 ? 2 : remaining);
280 template<
unsigned char Pick,
unsigned char GoOn,
bool FirstPass>
283 template<
bool IsFirstPass>
285 template<
unsigned Remaining,
class A,
class B,
class... Ts>
288 pick_next(Remaining - 2),
303 template<
unsigned,
class A>
308 template<
bool IsFirstPass>
310 template<
unsigned Remaining,
class... Ts>
313 pick_next(
sizeof...(Ts)),
314 (
sizeof...(Ts) != 1),
317 ::template f<
sizeof...(Ts), Ts...>;
323 template<
unsigned Remaining,
class A,
class... Ts>
324 using f =
typename make_tree<0,
sizeof...(Ts) != 0,
false>
325 ::
template f<0, Ts..., A>;
331 template<unsigned,
class A,
class... Ts>
332 using f =
typename make_tree<0,
sizeof...(Ts) != 0,
false>
336 template<
class... Ts>
337 using make_tree_union =
typename
338 make_tree<pick_next(
sizeof...(Ts)), 1,
true>::template f<
sizeof...(Ts), Ts...>;
343 template<std::size_t Num, class... Ts>
344 using smallest_suitable_integer_type =
345 type_pack_element<(
static_cast<unsigned char>(Num > std::numeric_limits<Ts>::max()) + ...),
350 namespace swap_trait {
354 concept able = requires (A a, A b) { swap(a, b); };
357 inline constexpr
bool nothrow = noexcept(swap(std::declval<A&>(), std::declval<A&>()));
360 #ifndef PLUGIFY_VARIANT_NO_STD_HASH
362 inline constexpr
bool has_std_hash = requires (T t) {
363 std::size_t(::std::hash<std::remove_cvref_t<T>>{}(t));
368 inline constexpr T* addressof(T& obj) noexcept {
369 #if defined(__GNUC__) || defined(__clang__)
370 return __builtin_addressof(obj);
371 #elif defined(PLUGIFY_VARIANT_NO_CONSTEXPR_EMPLACE)
373 if constexpr (requires { obj.operator&(); })
374 return reinterpret_cast<T*
>
375 (&
const_cast<char&
>(
reinterpret_cast<const volatile char&
>(obj)));
379 return std::addressof(obj);
385 template<
class Fn,
class... Vars>
386 using rtype_visit = decltype((std::declval<Fn>()(std::declval<Vars>().
template unsafe_get<0>()...)));
388 template<
class Fn,
class Var>
389 using rtype_index_visit = decltype((std::declval<Fn>()(std::declval<Var>().
template unsafe_get<0>(),
390 std::integral_constant<std::size_t, 0>{}))
393 inline namespace v1 {
395 #define DEC(N) X((N)) X((N) + 1) X((N) + 2) X((N) + 3) X((N) + 4) X((N) + 5) X((N) + 6) X((N) + 7) X((N) + 8) X((N) + 9)
397 #define SEQ30(N) DEC((N) + 0) DEC((N) + 10) DEC((N) + 20)
398 #define SEQ100(N) SEQ30((N) + 0) SEQ30((N) + 30) SEQ30((N) + 60) DEC((N) + 90)
399 #define SEQ200(N) SEQ100((N) + 0) SEQ100((N) + 100)
400 #define SEQ400(N) SEQ200((N) + 0) SEQ200((N) + 200)
401 #define CAT(M, N) M##N
402 #define CAT2(M, N) CAT(M, N)
403 #define INJECTSEQ(N) CAT2(SEQ, N)(0)
407 template<
unsigned Offset,
class Rtype,
class Fn,
class V>
408 constexpr Rtype single_visit_tail(Fn&& fn, V&& v) {
410 constexpr
auto RemainingIndex = std::decay_t<V>::size - Offset;
412 #define X(N) case (N + Offset) : \
413 if constexpr (N < RemainingIndex) { \
414 return static_cast<Fn&&>(fn)(static_cast<V&&>(v).template unsafe_get<N+Offset>()); \
416 } else PLUGIFY_UNREACHABLE();
425 if constexpr (SEQSIZE < RemainingIndex)
426 return detail::single_visit_tail<Offset + SEQSIZE, Rtype>(
static_cast<Fn&&
>(fn),
static_cast<V&&
>(v));
428 PLUGIFY_UNREACHABLE();
435 template<
unsigned Offset,
class Rtype,
class Fn,
class V>
436 constexpr Rtype single_visit_w_index_tail(Fn&& fn, V&& v) {
438 constexpr
auto RemainingIndex = std::decay_t<V>::size - Offset;
440 #define X(N) case (N + Offset) : \
441 if constexpr (N < RemainingIndex) { \
442 return static_cast<Fn&&>(fn)(static_cast<V&&>(v).template unsafe_get<N+Offset>(), std::integral_constant<unsigned, N+Offset>{}); \
444 } else PLUGIFY_UNREACHABLE();
453 if constexpr (SEQSIZE < RemainingIndex)
454 return detail::single_visit_w_index_tail<Offset + SEQSIZE, Rtype>(
static_cast<Fn&&
>(fn),
static_cast<V&&
>(v));
456 PLUGIFY_UNREACHABLE();
463 template<
class Fn,
class V>
464 constexpr decltype(
auto) visit(Fn&& fn, V&& v) {
465 return detail::single_visit_tail<0, rtype_visit<Fn&&, V&&>>(PLG_FWD(fn), PLG_FWD(v));
470 template<
class Fn,
class V>
471 constexpr decltype(
auto) visit_with_index(V&& v, Fn&& fn) {
472 return detail::single_visit_w_index_tail<0, rtype_index_visit<Fn&&, V&&>>(PLG_FWD(fn), PLG_FWD(v));
475 template<
class Fn,
class Head,
class... Tail>
476 constexpr decltype(
auto) multi_visit(Fn&& fn, Head&& head, Tail&&... tail) {
479 auto vis = [&fn, &head] (
auto&&... args) -> decltype(
auto) {
480 return detail::visit([&fn, &args...] (
auto&& elem) -> decltype(
auto) {
481 return PLG_FWD(fn)(PLG_FWD(elem), PLG_FWD(args)...);
485 if constexpr (
sizeof...(tail) == 0)
486 return PLG_FWD(vis)();
487 else if constexpr (sizeof...(tail) == 1)
488 return detail::visit(PLG_FWD(vis), PLG_FWD(tail)...);
490 return detail::multi_visit(PLG_FWD(vis), PLG_FWD(tail)...);
506 constexpr
bool operator==(T idx)
const noexcept {
return idx == std::numeric_limits<T>::max(); }
510 inline static constexpr detail::variant_npos_t variant_npos;
512 template<
class... Ts>
518 template<
typename... Ts>
525 inline constexpr
bool is_variant_v = is_variant<T>::value;
528 template<
class... Ts>
530 (std::is_array_v<Ts> || ...)
531 || (std::is_reference_v<Ts> || ...)
532 || (std::is_void_v<Ts> || ...)
533 ||
sizeof...(Ts) == 0
535 class variant<Ts...> {
536 static_assert(
sizeof...(Ts) > 0,
"A variant cannot be empty.");
537 static_assert(not(std::is_reference_v<Ts> || ...),
"A variant cannot contain references, consider using reference wrappers instead.");
538 static_assert(not(std::is_void_v<Ts> || ...),
"A variant cannot contains void.");
539 static_assert(not(std::is_array_v<Ts> || ...),
"A variant cannot contain a raw array type, consider using std::array instead.");
542 template<
class... Ts>
547 static constexpr
bool is_trivial = std::is_trivial_v<storage>;
548 static constexpr
bool has_copy_ctor = std::is_copy_constructible_v<storage>;
549 static constexpr
bool trivial_copy_ctor = is_trivial || std::is_trivially_copy_constructible_v<storage>;
550 static constexpr
bool has_copy_assign = std::is_copy_constructible_v<storage>;
551 static constexpr
bool trivial_copy_assign = is_trivial || std::is_trivially_copy_assignable_v<storage>;
552 static constexpr
bool has_move_ctor = std::is_move_constructible_v<storage>;
553 static constexpr
bool trivial_move_ctor = is_trivial || std::is_trivially_move_constructible_v<storage>;
554 static constexpr
bool has_move_assign = std::is_move_assignable_v<storage>;
555 static constexpr
bool trivial_move_assign = is_trivial || std::is_trivially_move_assignable_v<storage>;
556 static constexpr
bool trivial_dtor = std::is_trivially_destructible_v<storage>;
559 template<std::
size_t Idx>
560 using alternative = std::remove_reference_t<decltype(std::declval<storage&>().template get<Idx>())>;
562 static constexpr
bool can_be_valueless = not is_trivial;
564 static constexpr
unsigned size =
sizeof...(Ts);
566 using index_type = detail::smallest_suitable_integer_type<
sizeof...(Ts) + can_be_valueless,
unsigned char,
unsigned short,
unsigned>;
568 static constexpr index_type npos =
static_cast<index_type
>(-1);
571 static constexpr
int index_of = detail::find_first_true({std::is_same_v<T, Ts>...});
577 noexcept(std::is_nothrow_default_constructible_v<alternative<0>>)
578 requires std::is_default_constructible_v<alternative<0>>
579 : _storage{in_place_index<0>}, _current{0}
583 constexpr variant(
const variant&)
584 requires trivial_copy_ctor
589 constexpr variant(
const variant& o)
590 requires (has_copy_ctor and not trivial_copy_ctor)
591 : _storage{detail::dummy_type{}} {
596 constexpr variant(variant&&)
597 requires trivial_move_ctor
601 constexpr variant(variant&& o)
602 noexcept((std::is_nothrow_move_constructible_v<Ts> && ...))
603 requires (has_move_ctor and not trivial_move_ctor)
604 : _storage{detail::dummy_type{}} {
605 construct_from(
static_cast<variant&&
>(o));
609 template<
class T,
class M = detail::best_overload_match<T&&, Ts...>,
class D = std::decay_t<T>>
610 constexpr variant(T&& t)
611 noexcept(std::is_nothrow_constructible_v<M, T&&>)
612 requires (not std::is_same_v<D, variant> and not std::is_base_of_v<detail::emplacer_tag, D>)
613 : variant{in_place_index<index_of<M>>, static_cast<T&&>(t)}
617 template<std::size_t Index,
class... Args>
618 requires (Index < size && std::is_constructible_v<alternative<Index>, Args&&...>)
619 explicit constexpr variant(in_place_index_t<Index> tag, Args&&... args)
620 : _storage{tag,
static_cast<Args&&
>(args)...}, _current(Index)
624 template<
class T,
class... Args>
625 requires (detail::appears_exactly_once<T, Ts...> && std::is_constructible_v<T, Args&&...>)
626 explicit constexpr variant(in_place_type_t<T>, Args&&... args)
627 : variant{in_place_index<index_of<T>>, static_cast<Args&&>(args)...}
631 template<std::size_t Index,
class U,
class... Args>
634 std::is_constructible_v<alternative<Index>, std::initializer_list<U>&, Args&&...>
636 explicit constexpr variant(in_place_index_t<Index> tag, std::initializer_list<U> list, Args&&... args)
637 : _storage{tag, list, PLG_FWD(args)...}, _current{Index}
640 template<
class T,
class U,
class... Args>
642 detail::appears_exactly_once<T, Ts...>
643 && std::is_constructible_v<T, std::initializer_list<U>&, Args&&...>
645 explicit constexpr variant(in_place_type_t<T>, std::initializer_list<U> list, Args&&... args)
646 : _storage{in_place_index<index_of<T>>, list, PLG_FWD(args)...}, _current{index_of<T> }
651 constexpr ~variant() requires trivial_dtor = default;
653 constexpr ~variant() requires (not trivial_dtor) {
660 constexpr variant& operator=(
const variant& o)
661 requires trivial_copy_assign && trivial_copy_ctor
665 constexpr variant& operator=(
const variant& rhs)
666 requires (has_copy_assign and not(trivial_copy_assign && trivial_copy_ctor)) {
667 if (
this == &rhs) [[unlikely]]
670 assign_from(rhs, [&](
const auto& elem,
auto index_cst) {
671 if (index() == index_cst)
672 unsafe_get<index_cst>() = elem;
674 using type = alternative<index_cst>;
675 constexpr
bool do_simple_copy =
676 std::is_nothrow_copy_constructible_v<type>
677 or not std::is_nothrow_move_constructible_v<type>;
678 if constexpr (do_simple_copy)
679 emplace<index_cst>(elem);
681 alternative<index_cst> tmp = elem;
682 emplace<index_cst>(PLG_MOV(tmp));
690 constexpr variant& operator=(variant&& o)
691 requires (trivial_move_assign and trivial_move_ctor and trivial_dtor)
695 constexpr variant& operator=(variant&& o)
696 noexcept((std::is_nothrow_move_constructible_v<Ts> && ...) && (std::is_nothrow_move_assignable_v<Ts> && ...))
697 requires (has_move_assign && has_move_ctor and not(trivial_move_assign and trivial_move_ctor and trivial_dtor)) {
698 if (
this == &o) [[unlikely]]
701 assign_from(PLG_FWD(o), [&](
auto&& elem,
auto index_cst) {
702 if (index() == index_cst)
703 unsafe_get<index_cst>() = PLG_MOV(elem);
705 emplace<index_cst>(PLG_MOV(elem));
712 requires detail::has_non_ambiguous_match<T, Ts...>
713 constexpr variant& operator=(T&& t)
714 noexcept(std::is_nothrow_assignable_v<detail::best_overload_match<T&&, Ts...>, T&&>
715 && std::is_nothrow_constructible_v<detail::best_overload_match<T&&, Ts...>, T&&>) {
716 using related_type = detail::best_overload_match<T&&, Ts...>;
717 constexpr
auto new_index = index_of<related_type>;
719 if (_current == new_index)
720 unsafe_get<new_index>() = PLG_FWD(t);
722 constexpr
bool do_simple_emplace =
723 std::is_nothrow_constructible_v<related_type, T>
724 or not std::is_nothrow_move_constructible_v<related_type>;
726 if constexpr (do_simple_emplace)
727 emplace<new_index>(PLG_FWD(t));
729 related_type tmp = t;
730 emplace<new_index>(PLG_MOV(tmp));
739 template<
class T,
class... Args>
740 requires (std::is_constructible_v<T, Args&&...> && detail::appears_exactly_once<T, Ts...>)
741 constexpr T& emplace(Args&&... args) {
742 return emplace<index_of<T>>(
static_cast<Args&&
>(args)...);
745 template<std::size_t Idx,
class... Args>
746 requires (Idx < size and std::is_constructible_v<alternative<Idx>, Args&&...> )
747 constexpr auto& emplace(Args&&... args) {
748 return emplace_impl<Idx>(PLG_FWD(args)...);
752 template<std::size_t Idx,
class U,
class... Args>
754 && std::is_constructible_v<alternative<Idx>, std::initializer_list<U>&, Args&&...>)
755 constexpr auto& emplace(std::initializer_list<U> list, Args&&... args) {
756 return emplace_impl<Idx>(list, PLG_FWD(args)...);
759 template<
class T,
class U,
class... Args>
760 requires (std::is_constructible_v<T, std::initializer_list<U>&, Args&&...>
761 && detail::appears_exactly_once<T, Ts...>)
762 constexpr T& emplace(std::initializer_list<U> list, Args&&... args) {
763 return emplace_impl<index_of<T>>(list, PLG_FWD(args)...);
768 constexpr
bool valueless_by_exception() const noexcept {
769 if constexpr (can_be_valueless)
770 return _current == npos;
774 constexpr index_type index() const noexcept {
780 constexpr
void swap(variant& o)
781 noexcept((std::is_nothrow_move_constructible_v<Ts> && ...)
782 && (detail::swap_trait::template nothrow<Ts> && ...))
783 requires (has_move_ctor && (detail::swap_trait::template able<Ts> && ...)) {
784 if constexpr (can_be_valueless) {
787 constexpr
auto impl_one_valueless = [](
auto&& full,
auto& empty) {
788 detail::visit_with_index(PLG_FWD(full), detail::emplace_no_dtor_from_elem<variant&>{empty});
789 full.reset_no_check();
790 full._current = npos;
793 switch(
static_cast<int>(index() == npos) +
static_cast<int>(o.index() == npos) * 2) {
798 impl_one_valueless(PLG_MOV(o), *
this);
802 impl_one_valueless(PLG_MOV(*
this), o);
810 assert(not(valueless_by_exception() && o.valueless_by_exception()));
812 detail::visit_with_index(o, [&o,
this](
auto&& elem,
auto index_cst) {
813 if (index() == index_cst) {
815 swap(unsafe_get<index_cst>(), elem);
819 using idx_t = decltype(index_cst);
820 detail::visit_with_index(*
this, [
this, &o, &elem](
auto&& this_elem,
auto this_index) {
821 auto tmp { PLG_MOV(this_elem) };
824 detail::destruct<alternative<this_index>>(this_elem);
827 emplace_no_dtor<idx_t::value>(PLG_MOV(elem));
830 detail::destruct<alternative<idx_t::value>>(elem);
831 o.template emplace_no_dtor<(unsigned)(this_index) >(PLG_MOV(tmp));
839 template<detail::union_index_t Idx>
840 constexpr
auto& unsafe_get() & noexcept {
841 static_assert(Idx < size);
842 assert(_current == Idx);
843 return _storage.template get<Idx>();
846 template<detail::union_index_t Idx>
847 constexpr
auto&& unsafe_get() && noexcept {
848 static_assert(Idx < size);
849 assert(_current == Idx);
850 return PLG_MOV(_storage.template get<Idx>());
853 template<detail::union_index_t Idx>
854 constexpr
const auto& unsafe_get() const & noexcept {
855 static_assert(Idx < size);
856 assert(_current == Idx);
857 return _storage.template get<Idx>();
860 template<detail::union_index_t Idx>
861 constexpr
const auto&& unsafe_get() const && noexcept {
862 static_assert(Idx < size);
863 assert(_current == Idx);
864 return PLG_MOV(_storage.template get<Idx>());
869 template<
class Other,
class Fn>
870 constexpr
void assign_from(Other&& o, Fn&& fn) {
871 if constexpr (can_be_valueless) {
872 if (o.index() == npos) {
873 if (_current != npos) {
880 assert(not o.valueless_by_exception());
881 detail::visit_with_index(PLG_FWD(o), PLG_FWD(fn));
884 template<
unsigned Idx,
class... Args>
885 constexpr
auto& emplace_impl(Args&&... args) {
887 emplace_no_dtor<Idx>(PLG_FWD(args)...);
888 return unsafe_get<Idx>();
892 template<
unsigned Idx,
class... Args>
893 constexpr
void emplace_no_dtor(Args&&... args) {
894 using T = alternative<Idx>;
896 if constexpr (not std::is_nothrow_constructible_v<T, Args&&...>)
898 if constexpr (std::is_nothrow_move_constructible_v<T>)
900 do_emplace_no_dtor<Idx>(T{PLG_FWD(args)...});
902 else if constexpr (std::is_nothrow_copy_constructible_v<T>)
904 T tmp {PLG_FWD(args)...};
905 do_emplace_no_dtor<Idx>(tmp);
909 static_assert(can_be_valueless && Idx == Idx,
910 "Internal error : the possibly valueless branch of emplace was taken despite |can_be_valueless| being false");
912 do_emplace_no_dtor<Idx>(PLG_FWD(args)...);
916 do_emplace_no_dtor<Idx>(PLG_FWD(args)...);
919 template<
unsigned Idx,
class... Args>
920 constexpr
void do_emplace_no_dtor(Args&&... args) {
921 _current =
static_cast<index_type
>(Idx);
923 auto* ptr = detail::addressof(unsafe_get<Idx>());
925 #ifdef PLUGIFY_VARIANT_NO_CONSTEXPR_EMPLACE
926 using T = alternative<Idx>;
927 new (
const_cast<void*
>(ptr)) t(PLG_FWD(args)...);
929 std::construct_at(ptr, PLG_FWD(args)...);
934 constexpr
void reset() {
935 if constexpr (can_be_valueless)
936 if (valueless_by_exception())
return;
941 constexpr
void reset_no_check() {
942 assert(index() < size);
943 if constexpr (not trivial_dtor) {
944 detail::visit_with_index(*
this, [](
auto& elem,
auto index_cst) {
945 detail::destruct<alternative<index_cst>>(elem);
951 template<
class Other>
952 constexpr
void construct_from(Other&& o) {
953 if constexpr (can_be_valueless)
954 if (o.valueless_by_exception()) {
959 detail::visit_with_index(PLG_FWD(o), detail::emplace_no_dtor_from_elem<variant&>{*
this});
963 friend struct detail::emplace_no_dtor_from_elem;
971 template<
class T,
class... Ts>
972 constexpr
bool holds_alternative(
const variant<Ts...>& v) noexcept {
973 static_assert((std::is_same_v<T, Ts> || ...),
"Requested type is not contained in the variant");
974 constexpr
auto Index = variant<Ts...>::template index_of<T>;
975 return v.index() == Index;
980 template<std::size_t Idx,
class... Ts>
981 constexpr
auto& get(variant<Ts...>& v) {
982 static_assert(Idx <
sizeof...(Ts),
"Index exceeds the variant size. ");
983 PLUGIFY_ASSERT(v.index() == Idx,
"plg::variant:get(): Bad variant access in get.", bad_variant_access);
984 return (v.template unsafe_get<Idx>());
987 template<std::size_t Idx,
class... Ts>
988 constexpr
const auto& get(
const variant<Ts...>& v) {
989 return plg::get<Idx>(
const_cast<variant<Ts...
>&>(v));
992 template<std::size_t Idx,
class... Ts>
993 constexpr
auto&& get(variant<Ts...>&& v) {
994 return PLG_MOV(plg::get<Idx>(v));
997 template<std::size_t Idx,
class... Ts>
998 constexpr
const auto&& get(
const variant<Ts...>&& v) {
999 return PLG_MOV(plg::get<Idx>(v));
1004 template<
class T,
class... Ts>
1005 constexpr T& get(variant<Ts...>& v) {
1006 return plg::get<variant<Ts...>::template index_of<T> >(v);
1009 template<
class T,
class... Ts>
1010 constexpr
const T& get(
const variant<Ts...>& v) {
1011 return plg::get<variant<Ts...>::template index_of<T> >(v);
1014 template<
class T,
class... Ts>
1015 constexpr T&& get(variant<Ts...>&& v) {
1016 return plg::get<variant<Ts...>::template index_of<T> >(PLG_FWD(v));
1019 template<
class T,
class... Ts>
1020 constexpr
const T&& get(
const variant<Ts...>&& v) {
1021 return plg::get<variant<Ts...>::template index_of<T> >(PLG_FWD(v));
1026 template<std::size_t Idx,
class... Ts>
1027 constexpr
const auto* get_if(
const variant<Ts...>* v) noexcept {
1028 using rtype =
typename variant<Ts...>::template alternative<Idx>*;
1029 if (v ==
nullptr || v->index() != Idx)
1030 return rtype{
nullptr};
1032 return detail::addressof(v->template unsafe_get<Idx>());
1035 template<std::size_t Idx,
class... Ts>
1036 constexpr
auto* get_if(variant<Ts...>* v) noexcept {
1037 using rtype =
typename variant<Ts...>::template alternative<Idx>;
1038 return const_cast<rtype*
>(
1039 plg::get_if<Idx>(
static_cast<const variant<Ts...
>*>(v))
1045 template<
class T,
class... Ts>
1046 constexpr T* get_if(variant<Ts...>* v) noexcept {
1047 static_assert((std::is_same_v<T, Ts> || ...),
"Requested type is not contained in the variant");
1048 return plg::get_if<variant<Ts...>::template index_of<T> >(v);
1051 template<
class T,
class... Ts>
1052 constexpr
const T* get_if(
const variant<Ts...>* v) noexcept {
1053 static_assert((std::is_same_v<T, Ts> || ...),
"Requested type is not contained in the variant");
1054 return plg::get_if<variant<Ts...>::template index_of<T> >(v);
1059 template<
class Fn,
class... Vs>
1060 constexpr decltype(
auto) visit(Fn&& fn, Vs&&... vs) {
1061 if constexpr ((std::decay_t<Vs>::can_be_valueless || ...))
1062 PLUGIFY_ASSERT(!(vs.valueless_by_exception() || ...), "plg::variant:visit(): Bad variant access in visit.", bad_variant_access);
1064 if constexpr (sizeof...(Vs) == 1)
1065 return detail::visit(PLG_FWD(fn), PLG_FWD(vs)...);
1067 return detail::multi_visit(PLG_FWD(fn), PLG_FWD(vs)...);
1071 constexpr decltype(auto) visit(Fn&& fn) {
1072 return PLG_FWD(fn)();
1075 template<
class R,
class Fn,
class... Vs>
1076 requires (is_variant_v<Vs> && ...)
1077 constexpr R visit(Fn&& fn, Vs&&... vars) {
1078 return static_cast<R
>(plg::visit(PLG_FWD(fn), PLG_FWD(vars)...));
1083 template<
class... Ts>
1084 requires (detail::has_eq_comp<Ts> && ...)
1085 constexpr
bool operator==(const variant<Ts...>& v1, const variant<Ts...>& v2) {
1086 if (v1.index() != v2.index())
1088 if constexpr (variant<Ts...>::can_be_valueless)
1089 if (v1.valueless_by_exception())
return true;
1090 return detail::visit_with_index(v2, [&v1](
auto& elem,
auto index) ->
bool {
1091 return (v1.template unsafe_get<index>() == elem);
1095 template<
class... Ts>
1096 constexpr
bool operator!=(
const variant<Ts...>& v1,
const variant<Ts...>& v2)
1097 requires requires { v1 == v2; }
1099 return not(v1 == v2);
1102 template<
class... Ts>
1103 requires (detail::has_lesser_comp<const Ts&> && ...)
1104 constexpr
bool operator<(const variant<Ts...>& v1, const variant<Ts...>& v2) {
1105 if constexpr (variant<Ts...>::can_be_valueless) {
1106 if (v2.valueless_by_exception())
return false;
1107 if (v1.valueless_by_exception())
return true;
1109 if (v1.index() == v2.index()) {
1110 return detail::visit_with_index(v1, [&v2](
auto& elem,
auto index) ->
bool {
1111 return (elem < v2.template unsafe_get<index>());
1115 return (v1.index() < v2.index());
1118 template<
class... Ts>
1119 constexpr
bool operator>(
const variant<Ts...>& v1,
const variant<Ts...>& v2)
1120 requires requires { v2 < v1; }
1125 template<
class... Ts>
1126 requires (detail::has_less_or_eq_comp<const Ts&> && ...)
1127 constexpr
bool operator<=(const variant<Ts...>& v1, const variant<Ts...>& v2) {
1128 if constexpr (variant<Ts...>::can_be_valueless) {
1129 if (v1.valueless_by_exception())
return true;
1130 if (v2.valueless_by_exception())
return false;
1132 if (v1.index() == v2.index()) {
1133 return detail::visit_with_index(v1, [&v2](
auto& elem,
auto index) ->
bool {
1134 return (elem <= v2.template unsafe_get<index>());
1138 return (v1.index() < v2.index());
1141 template<
class... Ts>
1142 constexpr
bool operator>=(
const variant<Ts...>& v1,
const variant<Ts...>& v2)
1143 requires requires { v2 <= v1; }
1151 constexpr
bool operator==(monostate, monostate) noexcept {
return true; }
1152 constexpr
bool operator> (monostate, monostate) noexcept {
return false; }
1153 constexpr
bool operator< (monostate, monostate) noexcept {
return false; }
1154 constexpr
bool operator<=(monostate, monostate) noexcept {
return true; }
1155 constexpr
bool operator>=(monostate, monostate) noexcept {
return true; }
1159 template<
class... Ts>
1160 constexpr
void swap(variant<Ts...>& a, variant<Ts...>& b)
1161 noexcept(noexcept(a.swap(b)))
1162 requires requires { a.swap(b); }
1170 requires is_variant_v<T>
1171 inline constexpr std::size_t variant_size_v = std::decay_t<T>::size;
1175 requires is_variant_v<T>
1176 struct variant_size : std::integral_constant<std::size_t, variant_size_v<T>> {};
1180 template<
bool IsVolatile>
1182 template<std::
size_t Idx,
class T>
1183 using type = std::remove_reference_t<decltype(std::declval<T>().template unsafe_get<Idx>())>;
1188 template<std::
size_t Idx,
class T>
1193 template<std::
size_t Idx,
class T>
1194 requires (Idx < variant_size_v<T>)
1195 using variant_alternative_t = typename detail::var_alt_impl<std::is_volatile_v<T>>::template type<Idx, T>;
1197 template<std::
size_t Idx, class T>
1198 requires is_variant_v<T>
1200 using type = variant_alternative_t<Idx, T>;
1205 template<std::
size_t Idx,
class Var>
1206 requires is_variant_v<Var>
1207 constexpr
auto&& unsafe_get(Var&& var) noexcept {
1208 static_assert(Idx < std::decay_t<Var>::size,
"Index exceeds the variant size.");
1209 return PLG_FWD(var).template unsafe_get<Idx>();
1212 template<
class T,
class Var>
1213 requires is_variant_v<Var>
1214 constexpr
auto&& unsafe_get(Var&& var) noexcept {
1215 return plg::unsafe_get<std::decay_t<Var>::template index_of<T>>(PLG_FWD(var));
1221 #ifndef PLUGIFY_VARIANT_NO_STD_HASH
1223 template<
class... Ts>
1224 requires (plg::detail::has_std_hash<Ts> && ...)
1225 struct hash<plg::variant<Ts...>> {
1228 if (v.valueless_by_exception())
1229 return static_cast<std::size_t
>(-1);
1231 return plg::detail::visit_with_index(v, [](
auto& elem,
auto index_) {
1232 using type = std::remove_cvref_t<decltype(elem)>;
1233 return std::hash<type>{}(elem) + index_;
1239 struct hash<plg::monostate> {
1240 constexpr std::size_t operator()(plg::monostate)
const noexcept {
return static_cast<size_t>(-1); }