6#include <initializer_list>
8#ifndef PLUGIFY_VARIANT_NO_CONSTEXPR_EMPLACE
14#ifndef PLUGIFY_VARIANT_NO_STD_HASH
18#define PLG_FWD(x) static_cast<decltype(x)&&>(x)
19#define PLG_MOV(x) static_cast< std::remove_reference_t<decltype(x)>&& >(x)
21#include "plg/config.hpp"
22#include "plg/concepts.hpp"
26#if PLUGIFY_HAS_EXCEPTIONS
27 class bad_variant_access :
public std::exception {
29 explicit bad_variant_access(
const char* str) noexcept : message_{str} {}
30 bad_variant_access() noexcept = default;
31 bad_variant_access(const bad_variant_access&) noexcept = default;
32 bad_variant_access& operator=(const bad_variant_access&) noexcept = default;
33 const
char* what() const noexcept
override {
return message_; }
35 const char* message_ =
"";
47 template<std::
size_t Index>
50 template<std::
size_t Index>
58 constexpr int find_first_true(
bool (&&
arr)[
N]) {
59 for (
int k = 0;
k <
N; ++
k)
65 template<
class T,
class... Ts>
66 inline constexpr bool appears_exactly_once = (
static_cast<unsigned short>(std::is_same_v<T, Ts>) + ...) == 1;
70#if __has_builtin(__type_pack_element)
71 template<std::size_t K,
class... Ts>
72 using type_pack_element = __type_pack_element<K, Ts...>;
74 template<
unsigned char = 1>
79 template<std::size_t
Idx,
class T,
class...
Ts>
85 template<std::size_t,
class T,
class...
Ts>
89 template<std::size_t
K,
class...
Ts>
98 template<std::
size_t N,
class A>
102 requires requires {
arr1<A>{std::declval<T>()}; }
106 template<
class Seq,
class...
Args>
109 template<std::size_t...
Idx,
class...
Args>
115 template<
class T,
class...
Ts>
116 using best_overload_match =
typename decltype(
118 (std::declval<T>(), std::declval<T>())
121 template<
class T,
class...
Ts>
123 requires {
typename best_overload_match<T, Ts...>; };
127 template<
class From,
class To>
148 constexpr void operator()(T&&
elem,
auto index_)
const {
154 template<
class E,
class T>
155 constexpr void destruct(T&
obj) {
156 if constexpr (
not std::is_trivially_destructible_v<E>)
169#define TRAIT(trait) (std::is_##trait##_v<A> && std::is_##trait##_v<B>)
171#define SFM(signature, trait) \
172 signature = default; \
173 signature requires (TRAIT(trait) and not TRAIT(trivially_##trait)) {};
177#define INJECT_UNION_SFM(X) \
178 SFM(constexpr X (const X &), copy_constructible) \
179 SFM(constexpr X (X&&) noexcept, move_constructible) \
180 SFM(constexpr X& operator=(const X&), copy_assignable) \
181 SFM(constexpr X& operator=(X&&) noexcept, move_assignable) \
182 SFM(constexpr ~X(), destructible)
184 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>
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>
234 template<
class...
Args>
241 requires (std::is_same_v<dummy_type, B>)
245 template<union_index_t Index>
246 constexpr auto& get() {
248 if constexpr (
Index == 0)
253 if constexpr (
Index < A::elem_size)
256 return b.template get<
Index - A::elem_size>();
260 template<union_index_t Index>
261 constexpr const auto& get()
const {
268#undef INJECT_UNION_SFM
276 constexpr unsigned char pick_next(
unsigned remaining) {
280 template<
unsigned char Pick,
unsigned char GoOn,
bool FirstPass>
283 template<
bool IsFirstPass>
303 template<
unsigned,
class A>
308 template<
bool IsFirstPass>
313 pick_next(
sizeof...(
Ts)),
314 (
sizeof...(Ts) != 1),
317 ::template f<
sizeof...(Ts),
Ts...>;
324 using f =
typename make_tree<0,
sizeof...(Ts) != 0,
false>
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>
348 namespace swap_trait {
352 concept able =
requires (A a, A b) { swap(a, b); };
355 inline constexpr bool nothrow =
noexcept(swap(std::declval<A&>(), std::declval<A&>()));
358#ifndef PLUGIFY_VARIANT_NO_STD_HASH
360 inline constexpr bool has_std_hash =
requires (T
t) {
361 std::size_t(::std::hash<std::remove_cvref_t<T>>{}(
t));
366 inline constexpr T* addressof(T& obj)
noexcept {
367#if PLUGIFY_COMPILER_GCC || PLUGIFY_COMPILER_CLANG
368 return __builtin_addressof(obj);
369#elif defined(PLUGIFY_VARIANT_NO_CONSTEXPR_EMPLACE)
371 if constexpr (
requires { obj.operator&(); })
372 return reinterpret_cast<T*
>
373 (&
const_cast<char&
>(
reinterpret_cast<const volatile char&
>(obj)));
377 return std::addressof(obj);
383 template<
class Fn,
class... Vars>
384 using rtype_visit =
decltype((std::declval<Fn>()(std::declval<Vars>().template unsafe_get<0>()...)));
386 template<
class Fn,
class Var>
387 using rtype_index_visit =
decltype((std::declval<Fn>()(std::declval<Var>().template unsafe_get<0>(),
388 std::integral_constant<std::size_t, 0>{}))
391 inline namespace v1 {
393#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)
395#define SEQ30(N) DEC((N) + 0) DEC((N) + 10) DEC((N) + 20)
396#define SEQ100(N) SEQ30((N) + 0) SEQ30((N) + 30) SEQ30((N) + 60) DEC((N) + 90)
397#define SEQ200(N) SEQ100((N) + 0) SEQ100((N) + 100)
398#define SEQ400(N) SEQ200((N) + 0) SEQ200((N) + 200)
399#define CAT(M, N) M##N
400#define CAT2(M, N) CAT(M, N)
401#define INJECTSEQ(N) CAT2(SEQ, N)(0)
405 template<
unsigned Offset,
class Rtype,
class Fn,
class V>
406 constexpr Rtype single_visit_tail(Fn&& fn, V&& v) {
408 constexpr auto RemainingIndex = std::decay_t<V>::size - Offset;
410#define X(N) case (N + Offset) : \
411 if constexpr (N < RemainingIndex) { \
412 return static_cast<Fn&&>(fn)(static_cast<V&&>(v).template unsafe_get<N+Offset>()); \
414 } else PLUGIFY_UNREACHABLE();
423 if constexpr (SEQSIZE < RemainingIndex)
424 return detail::single_visit_tail<Offset + SEQSIZE, Rtype>(
static_cast<Fn&&
>(fn),
static_cast<V&&
>(v));
426 PLUGIFY_UNREACHABLE();
433 template<
unsigned Offset,
class Rtype,
class Fn,
class V>
434 constexpr Rtype single_visit_w_index_tail(Fn&& fn, V&& v) {
436 constexpr auto RemainingIndex = std::decay_t<V>::size - Offset;
438#define X(N) case (N + Offset) : \
439 if constexpr (N < RemainingIndex) { \
440 return static_cast<Fn&&>(fn)(static_cast<V&&>(v).template unsafe_get<N+Offset>(), std::integral_constant<unsigned, N+Offset>{}); \
442 } else PLUGIFY_UNREACHABLE();
451 if constexpr (SEQSIZE < RemainingIndex)
452 return detail::single_visit_w_index_tail<Offset + SEQSIZE, Rtype>(
static_cast<Fn&&
>(fn),
static_cast<V&&
>(v));
454 PLUGIFY_UNREACHABLE();
461 template<
class Fn,
class V>
462 constexpr decltype(
auto) visit(Fn&& fn, V&& v) {
463 return detail::single_visit_tail<0, rtype_visit<Fn&&, V&&>>(PLG_FWD(fn), PLG_FWD(v));
468 template<
class Fn,
class V>
469 constexpr decltype(
auto) visit_with_index(V&& v, Fn&& fn) {
470 return detail::single_visit_w_index_tail<0, rtype_index_visit<Fn&&, V&&>>(PLG_FWD(fn), PLG_FWD(v));
473 template<
class Fn,
class Head,
class... Tail>
474 constexpr decltype(
auto) multi_visit(Fn&& fn, Head&& head, Tail&&... tail) {
477 auto vis = [&fn, &head] (
auto&&... args) ->
decltype(
auto) {
478 return detail::visit([&fn, &args...] (
auto&& elem) ->
decltype(
auto) {
479 return PLG_FWD(fn)(PLG_FWD(elem), PLG_FWD(args)...);
483 if constexpr (
sizeof...(tail) == 0)
484 return PLG_FWD(vis)();
485 else if constexpr (
sizeof...(tail) == 1)
486 return detail::visit(PLG_FWD(vis), PLG_FWD(tail)...);
488 return detail::multi_visit(PLG_FWD(vis), PLG_FWD(tail)...);
504 constexpr bool operator==(T
idx)
const noexcept {
return idx == std::numeric_limits<T>::max(); }
510 template<
class...
Ts>
516 template<
typename...
Ts>
526 template<
class...
Ts>
528 (std::is_array_v<Ts> || ...)
529 || (std::is_reference_v<Ts> || ...)
530 || (std::is_void_v<Ts> || ...)
531 ||
sizeof...(Ts) == 0
534 static_assert(
sizeof...(Ts) > 0,
"A variant cannot be empty.");
535 static_assert(
not(std::is_reference_v<Ts> || ...),
"A variant cannot contain references, consider using reference wrappers instead.");
536 static_assert(
not(std::is_void_v<Ts> || ...),
"A variant cannot contains void.");
537 static_assert(
not(std::is_array_v<Ts> || ...),
"A variant cannot contain a raw array type, consider using std::array instead.");
540 template<
class...
Ts>
544 static constexpr bool is_trivial = std::is_trivial_v<storage>;
545 static constexpr bool has_copy_ctor = std::is_copy_constructible_v<storage>;
546 static constexpr bool trivial_copy_ctor = is_trivial || std::is_trivially_copy_constructible_v<storage>;
547 static constexpr bool has_copy_assign = std::is_copy_constructible_v<storage>;
548 static constexpr bool trivial_copy_assign = is_trivial || std::is_trivially_copy_assignable_v<storage>;
549 static constexpr bool has_move_ctor = std::is_move_constructible_v<storage>;
550 static constexpr bool trivial_move_ctor = is_trivial || std::is_trivially_move_constructible_v<storage>;
551 static constexpr bool has_move_assign = std::is_move_assignable_v<storage>;
552 static constexpr bool trivial_move_assign = is_trivial || std::is_trivially_move_assignable_v<storage>;
553 static constexpr bool trivial_dtor = std::is_trivially_destructible_v<storage>;
556 using trivially_relocatable = std::conditional_t<std::conjunction_v<is_trivially_relocatable<Ts>...>,
variant,
void>;
558 template<std::
size_t Idx>
559 using alternative = std::remove_reference_t<decltype(std::declval<storage&>().template
get<Idx>())>;
561 static constexpr bool can_be_valueless =
not is_trivial;
563 static constexpr unsigned size =
sizeof...(Ts);
565 using index_type = detail::smallest_suitable_integer_type<
sizeof...(Ts) + can_be_valueless,
unsigned char,
unsigned short,
unsigned>;
567 static constexpr index_type npos =
static_cast<index_type
>(-1);
570 static constexpr int index_of = detail::find_first_true({std::is_same_v<T, Ts>...});
576 noexcept(std::is_nothrow_default_constructible_v<alternative<0>>)
583 requires trivial_copy_ctor
589 requires (has_copy_ctor
and not trivial_copy_ctor)
596 requires trivial_move_ctor
601 noexcept((std::is_nothrow_move_constructible_v<Ts> && ...))
602 requires (has_move_ctor
and not trivial_move_ctor)
604 construct_from(
static_cast<variant&&
>(
o));
608 template<
class T,
class M = detail::best_overload_match<T&&,
Ts...>,
class D = std::decay_t<T>>
610 noexcept(std::is_nothrow_constructible_v<M, T&&>)
611 requires (
not std::is_same_v<D, variant>
and not std::is_base_of_v<detail::emplacer_tag, D>)
616 template<std::size_t
Index,
class...
Args>
623 template<
class T,
class...
Args>
624 requires (detail::appears_exactly_once<T,
Ts...> && std::is_constructible_v<T,
Args&&...>)
630 template<std::size_t
Index,
class U,
class...
Args>
639 template<
class T,
class U,
class...
Args>
641 detail::appears_exactly_once<T,
Ts...>
642 && std::is_constructible_v<T, std::initializer_list<U>&,
Args&&...>
650 constexpr ~variant()
requires trivial_dtor =
default;
660 requires trivial_copy_assign && trivial_copy_ctor
665 requires (has_copy_assign
and not(trivial_copy_assign && trivial_copy_ctor)) {
674 constexpr bool do_simple_copy = std::is_nothrow_copy_constructible_v<type>
675 or not std::is_nothrow_move_constructible_v<type>;
689 requires (trivial_move_assign
and trivial_move_ctor
and trivial_dtor)
694 noexcept((std::is_nothrow_move_constructible_v<Ts> && ...) && (std::is_nothrow_move_assignable_v<Ts> && ...))
695 requires (has_move_assign && has_move_ctor
and not(trivial_move_assign
and trivial_move_ctor
and trivial_dtor)) {
712 noexcept(std::is_nothrow_assignable_v<detail::best_overload_match<T&&,
Ts...>, T&&>
713 && std::is_nothrow_constructible_v<detail::best_overload_match<T&&,
Ts...>, T&&>) {
721 std::is_nothrow_constructible_v<related_type, T>
722 or not std::is_nothrow_move_constructible_v<related_type>;
737 template<
class T,
class...
Args>
738 requires (std::is_constructible_v<T,
Args&&...> && detail::appears_exactly_once<T,
Ts...>)
739 constexpr T& emplace(
Args&&...
args) {
743 template<std::size_t
Idx,
class...
Args>
745 constexpr auto& emplace(
Args&&...
args) {
750 template<std::size_t
Idx,
class U,
class...
Args>
752 && std::is_constructible_v<alternative<Idx>, std::initializer_list<U>&,
Args&&...>)
753 constexpr auto& emplace(std::initializer_list<U>
list,
Args&&...
args) {
757 template<
class T,
class U,
class...
Args>
758 requires (std::is_constructible_v<T, std::initializer_list<U>&,
Args&&...>
759 && detail::appears_exactly_once<T,
Ts...>)
760 constexpr T& emplace(std::initializer_list<U>
list,
Args&&...
args) {
766 constexpr bool valueless_by_exception()
const noexcept {
767 if constexpr (can_be_valueless)
768 return current_ == npos;
772 constexpr index_type index()
const noexcept {
779 noexcept((std::is_nothrow_move_constructible_v<Ts> && ...)
780 && (detail::swap_trait::template
nothrow<Ts> && ...))
781 requires (has_move_ctor && (detail::swap_trait::template
able<Ts> && ...)) {
782 if constexpr (can_be_valueless) {
787 full.reset_no_check();
788 full.current_ = npos;
791 switch (
static_cast<int>(index() == npos) +
static_cast<int>(
o.index() == npos) * 2) {
822 detail::destruct<alternative<this_index>>(
this_elem);
828 detail::destruct<alternative<idx_t::value>>(
elem);
837 template<detail::union_index_t Idx>
838 constexpr auto& unsafe_get() &
noexcept {
839 static_assert(
Idx < size);
841 return storage_.template
get<Idx>();
844 template<detail::union_index_t Idx>
845 constexpr auto&& unsafe_get() &&
noexcept {
846 static_assert(
Idx < size);
848 return PLG_MOV(storage_.template
get<Idx>());
851 template<detail::union_index_t Idx>
852 constexpr const auto& unsafe_get()
const &
noexcept {
853 static_assert(
Idx < size);
855 return storage_.template
get<Idx>();
858 template<detail::union_index_t Idx>
859 constexpr const auto&& unsafe_get()
const &&
noexcept {
860 static_assert(
Idx < size);
862 return PLG_MOV(storage_.template
get<Idx>());
867 template<
class Other,
class Fn>
868 constexpr void assign_from(
Other&&
o,
Fn&&
fn) {
869 if constexpr (can_be_valueless) {
870 if (
o.index() == npos) {
871 if (current_ != npos) {
879 detail::visit_with_index(PLG_FWD(
o), PLG_FWD(
fn));
882 template<
unsigned Idx,
class...
Args>
883 constexpr auto& emplace_impl(
Args&&...
args) {
890 template<
unsigned Idx,
class...
Args>
891 constexpr void emplace_no_dtor(
Args&&...
args) {
894 if constexpr (
not std::is_nothrow_constructible_v<T,
Args&&...>)
896 if constexpr (std::is_nothrow_move_constructible_v<T>)
900 else if constexpr (std::is_nothrow_copy_constructible_v<T>)
907 static_assert(can_be_valueless,
908 "Internal error : the possibly valueless branch of emplace was taken despite |can_be_valueless| being false");
917 template<
unsigned Idx,
class...
Args>
918 constexpr void do_emplace_no_dtor(
Args&&...
args) {
919 current_ =
static_cast<index_type
>(
Idx);
923#ifdef PLUGIFY_VARIANT_NO_CONSTEXPR_EMPLACE
925 new (
const_cast<void*
>(ptr))
t(PLG_FWD(
args)...);
927 std::construct_at(ptr, PLG_FWD(
args)...);
932 constexpr void reset() {
933 if constexpr (can_be_valueless)
934 if (valueless_by_exception())
return;
939 constexpr void reset_no_check() {
941 if constexpr (
not trivial_dtor) {
942 detail::visit_with_index(*
this, [](
auto&
elem,
auto index_cst) {
943 detail::destruct<alternative<index_cst>>(
elem);
949 template<
class Other>
950 constexpr void construct_from(
Other&&
o) {
951 if constexpr (can_be_valueless)
952 if (
o.valueless_by_exception()) {
964#if INTPTR_MAX == INT32_MAX
965 volatile char padding_[8];
972 template<
class T,
class...
Ts>
973 constexpr bool holds_alternative(
const variant<Ts...>& v)
noexcept {
974 static_assert((std::is_same_v<T, Ts> || ...),
"Requested type is not contained in the variant");
976 return v.index() == index;
981 template<std::size_t Idx,
class... Ts>
982 constexpr auto& get(variant<Ts...>& v) {
983 static_assert(Idx <
sizeof...(Ts),
"Index exceeds the variant size. ");
984 if (v.index() != Idx) {
985 PLUGIFY_THROW(
"bad variant access in get", bad_variant_access);
987 return (v.template unsafe_get<Idx>());
990 template<std::size_t Idx,
class... Ts>
991 constexpr const auto& get(
const variant<Ts...>& v) {
995 template<std::size_t Idx,
class... Ts>
996 constexpr auto&& get(variant<Ts...>&& v) {
1000 template<std::size_t Idx,
class... Ts>
1001 constexpr const auto&& get(
const variant<Ts...>&& v) {
1007 template<
class T,
class... Ts>
1008 constexpr T& get(variant<Ts...>& v) {
1009 return plg::get<variant<Ts...>::template index_of<T> >(v);
1012 template<
class T,
class... Ts>
1013 constexpr const T& get(
const variant<Ts...>& v) {
1014 return plg::get<variant<Ts...>::template index_of<T> >(v);
1017 template<
class T,
class... Ts>
1018 constexpr T&& get(variant<Ts...>&& v) {
1019 return plg::get<variant<Ts...>::template index_of<T> >(PLG_FWD(v));
1022 template<
class T,
class... Ts>
1023 constexpr const T&& get(
const variant<Ts...>&& v) {
1024 return plg::get<variant<Ts...>::template index_of<T> >(PLG_FWD(v));
1029 template<std::size_t Idx,
class... Ts>
1030 constexpr const auto* get_if(
const variant<Ts...>* v)
noexcept {
1031 using rtype =
typename variant<Ts...>::template alternative<Idx>*;
1032 if (v ==
nullptr || v->index() != Idx)
1033 return rtype{
nullptr};
1035 return detail::addressof(v->template unsafe_get<Idx>());
1038 template<std::size_t Idx,
class... Ts>
1039 constexpr auto* get_if(variant<Ts...>* v)
noexcept {
1040 using rtype =
typename variant<Ts...>::template alternative<Idx>;
1041 return const_cast<rtype*
>(
1048 template<
class T,
class... Ts>
1049 constexpr T* get_if(variant<Ts...>* v)
noexcept {
1050 static_assert((std::is_same_v<T, Ts> || ...),
"Requested type is not contained in the variant");
1051 return plg::get_if<variant<Ts...>::template index_of<T> >(v);
1054 template<
class T,
class... Ts>
1055 constexpr const T* get_if(
const variant<Ts...>* v)
noexcept {
1056 static_assert((std::is_same_v<T, Ts> || ...),
"Requested type is not contained in the variant");
1057 return plg::get_if<variant<Ts...>::template index_of<T> >(v);
1062 template<
class Fn,
class... Vs>
1063 constexpr decltype(
auto) visit(Fn&& fn, Vs&&... vs) {
1064 if constexpr ((std::decay_t<Vs>::can_be_valueless || ...))
1065 if ((vs.valueless_by_exception() || ...)) {
1066 PLUGIFY_THROW(
"bad variant access in visit", bad_variant_access);
1068 if constexpr (
sizeof...(Vs) == 1)
1069 return detail::visit(PLG_FWD(fn), PLG_FWD(vs)...);
1071 return detail::multi_visit(PLG_FWD(fn), PLG_FWD(vs)...);
1075 constexpr decltype(
auto) visit(Fn&& fn) {
1076 return PLG_FWD(fn)();
1079 template<
class R,
class Fn,
class... Vs>
1080 requires (is_variant_v<Vs> && ...)
1081 constexpr R visit(Fn&& fn, Vs&&... vars) {
1082 return static_cast<R
>(plg::visit(PLG_FWD(fn), PLG_FWD(vars)...));
1087 template<
class... Ts>
1088 requires (detail::has_eq_comp<Ts> && ...)
1089 constexpr bool operator==(
const variant<Ts...>& v1,
const variant<Ts...>& v2) {
1090 if (v1.index() != v2.index())
1092 if constexpr (variant<Ts...>::can_be_valueless)
1093 if (v1.valueless_by_exception())
return true;
1094 return detail::visit_with_index(v2, [&v1](
auto& elem,
auto index) ->
bool {
1095 return (v1.template unsafe_get<index>() == elem);
1099 template<
class... Ts>
1100 constexpr bool operator!=(
const variant<Ts...>& v1,
const variant<Ts...>& v2)
1101 requires requires { v1 == v2; }
1103 return not(v1 == v2);
1106 template<
class... Ts>
1107 requires (detail::has_lesser_comp<const Ts&> && ...)
1108 constexpr bool operator<(
const variant<Ts...>& v1,
const variant<Ts...>& v2) {
1109 if constexpr (variant<Ts...>::can_be_valueless) {
1110 if (v2.valueless_by_exception())
return false;
1111 if (v1.valueless_by_exception())
return true;
1113 if (v1.index() == v2.index()) {
1114 return detail::visit_with_index(v1, [&v2](
auto& elem,
auto index) ->
bool {
1115 return (elem < v2.template unsafe_get<index>());
1119 return (v1.index() < v2.index());
1122 template<
class... Ts>
1123 constexpr bool operator>(
const variant<Ts...>& v1,
const variant<Ts...>& v2)
1124 requires requires { v2 < v1; }
1129 template<
class... Ts>
1130 requires (detail::has_less_or_eq_comp<const Ts&> && ...)
1131 constexpr bool operator<=(
const variant<Ts...>& v1,
const variant<Ts...>& v2) {
1132 if constexpr (variant<Ts...>::can_be_valueless) {
1133 if (v1.valueless_by_exception())
return true;
1134 if (v2.valueless_by_exception())
return false;
1136 if (v1.index() == v2.index()) {
1137 return detail::visit_with_index(v1, [&v2](
auto& elem,
auto index) ->
bool {
1138 return (elem <= v2.template unsafe_get<index>());
1142 return (v1.index() < v2.index());
1145 template<
class... Ts>
1146 constexpr bool operator>=(
const variant<Ts...>& v1,
const variant<Ts...>& v2)
1147 requires requires { v2 <= v1; }
1156 constexpr std::strong_ordering operator<=>(monostate, monostate)
noexcept {
1157 return std::strong_ordering::equal;
1162 template<
class... Ts>
1163 constexpr void swap(variant<Ts...>& a, variant<Ts...>& b)
1164 noexcept(
noexcept(a.swap(b)))
1165 requires requires { a.swap(b); }
1173 requires is_variant_v<T>
1174 inline constexpr std::size_t variant_size_v = std::decay_t<T>::size;
1178 requires is_variant_v<T>
1179 struct variant_size : std::integral_constant<std::size_t, variant_size_v<T>> {};
1183 template<
bool IsVolatile>
1184 struct var_alt_impl {
1185 template<std::
size_t Idx,
class T>
1186 using type = std::remove_reference_t<decltype(std::declval<T>().template
unsafe_get<Idx>())>;
1190 struct var_alt_impl<true> {
1191 template<std::
size_t Idx,
class T>
1192 using type =
volatile typename var_alt_impl<false>::template type<Idx, std::remove_volatile_t<T>>;
1196 template<std::
size_t Idx,
class T>
1197 requires (Idx < variant_size_v<T>)
1198 using variant_alternative_t =
typename detail::var_alt_impl<std::is_volatile_v<T>>::template type<Idx, T>;
1200 template<std::
size_t Idx,
class T>
1201 requires is_variant_v<T>
1208 template<std::
size_t Idx,
class Var>
1210 constexpr auto&& unsafe_get(
Var&&
var)
noexcept {
1215 template<
class T,
class Var>
1216 requires is_variant_v<Var>
1217 constexpr auto&& unsafe_get(Var&& var)
noexcept {
1224#ifndef PLUGIFY_VARIANT_NO_STD_HASH
1226 template<
class... Ts>
1227 requires (plg::detail::has_std_hash<Ts> && ...)
1228 struct hash<plg::variant<Ts...>> {
1231 if (v.valueless_by_exception())
1232 return static_cast<std::size_t
>(-1);
1234 return plg::detail::visit_with_index(v, [](
auto& elem,
auto index_) {
1235 using type = std::remove_cvref_t<
decltype(elem)>;
1236 return std::hash<type>{}(elem) + index_;
1242 struct hash<plg::monostate> {
1243 constexpr std::size_t operator()(
plg::monostate)
const noexcept {
return static_cast<size_t>(66740831); }