7#include <initializer_list>
10#ifndef PLUGIFY_VARIANT_NO_CONSTEXPR_EMPLACE
16#ifndef PLUGIFY_VARIANT_NO_STD_HASH
20#define PLG_FWD(x) static_cast<decltype(x)&&>(x)
21#define PLG_MOV(x) static_cast< std::remove_reference_t<decltype(x)>&& >(x)
28 class bad_variant_access final :
public std::exception {
29 const char* message =
"";
31 explicit bad_variant_access(
const char* str) noexcept : message{str} {}
32 bad_variant_access() noexcept = default;
33 bad_variant_access(const bad_variant_access&) noexcept = default;
34 bad_variant_access& operator=(const bad_variant_access&) noexcept = default;
35 const
char* what() const noexcept
override {
return 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>
190 template<
class A,
class B>
191 static constexpr auto elem_size =
not(std::is_same_v<B, dummy_type>) ? 2 : 1;
193 template<std::
size_t,
class>
194 static constexpr char ctor_branch = 0;
199 template<
class A,
class B>
200 static constexpr auto elem_size = A::elem_size + B::elem_size;
202 template<std::
size_t Index,
class A>
203 static constexpr char ctor_branch = (
Index < A::elem_size) ? 1 : 2;
206 template<
bool IsLeaf,
class A,
class B>
217 template<std::size_t
Index,
class...
Args>
223 template<std::size_t
Index,
class...
Args>
226 : b{in_place_index<
Index - A::elem_size>,
static_cast<Args&&
>(
args)...}
229 template<
class...
Args>
235 template<
class...
Args>
242 requires (std::is_same_v<dummy_type, B>)
246 template<union_index_t Index>
247 constexpr auto& get() {
249 if constexpr (
Index == 0)
254 if constexpr (
Index < A::elem_size)
257 return b.template get<
Index - A::elem_size>();
261 template<union_index_t Index>
262 constexpr const auto& get()
const {
269#undef INJECT_UNION_SFM
277 constexpr unsigned char pick_next(
unsigned remaining) {
281 template<
unsigned char Pick,
unsigned char GoOn,
bool FirstPass>
284 template<
bool IsFirstPass>
304 template<
unsigned,
class A>
309 template<
bool IsFirstPass>
314 pick_next(
sizeof...(
Ts)),
315 (
sizeof...(Ts) != 1),
318 ::template f<
sizeof...(Ts),
Ts...>;
325 using f =
typename make_tree<0,
sizeof...(Ts) != 0,
false>
333 using f =
typename make_tree<0,
sizeof...(Ts) != 0,
false>
337 template<
class...
Ts>
338 using make_tree_union =
typename
339 make_tree<pick_next(
sizeof...(
Ts)), 1,
true>::template f<
sizeof...(Ts),
Ts...>;
344 template<std::size_t
Num,
class...
Ts>
351 namespace swap_trait {
355 concept able =
requires (A a, A b) { swap(a, b); };
358 inline constexpr bool nothrow =
noexcept(swap(std::declval<A&>(), std::declval<A&>()));
361#ifndef PLUGIFY_VARIANT_NO_STD_HASH
363 inline constexpr bool has_std_hash =
requires (
T t) {
364 std::size_t(::std::hash<std::remove_cvref_t<T>>{}(
t));
369 inline constexpr T* addressof(T& obj)
noexcept {
370#if PLUGIFY_COMPILER_GCC || PLUGIFY_COMPILER_CLANG
371 return __builtin_addressof(obj);
372#elif defined(PLUGIFY_VARIANT_NO_CONSTEXPR_EMPLACE)
374 if constexpr (
requires { obj.operator&(); })
375 return reinterpret_cast<T*
>
376 (&
const_cast<char&
>(
reinterpret_cast<const volatile char&
>(obj)));
380 return std::addressof(obj);
386 template<
class Fn,
class... Vars>
387 using rtype_visit =
decltype((std::declval<Fn>()(std::declval<Vars>().template unsafe_get<0>()...)));
389 template<
class Fn,
class Var>
390 using rtype_index_visit =
decltype((std::declval<Fn>()(std::declval<Var>().template unsafe_get<0>(),
391 std::integral_constant<std::size_t, 0>{}))
394 inline namespace v1 {
396#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)
398#define SEQ30(N) DEC((N) + 0) DEC((N) + 10) DEC((N) + 20)
399#define SEQ100(N) SEQ30((N) + 0) SEQ30((N) + 30) SEQ30((N) + 60) DEC((N) + 90)
400#define SEQ200(N) SEQ100((N) + 0) SEQ100((N) + 100)
401#define SEQ400(N) SEQ200((N) + 0) SEQ200((N) + 200)
402#define CAT(M, N) M##N
403#define CAT2(M, N) CAT(M, N)
404#define INJECTSEQ(N) CAT2(SEQ, N)(0)
408 template<
unsigned Offset,
class Rtype,
class Fn,
class V>
409 constexpr Rtype single_visit_tail(Fn&& fn, V&& v) {
411 constexpr auto RemainingIndex = std::decay_t<V>::size - Offset;
413#define X(N) case (N + Offset) : \
414 if constexpr (N < RemainingIndex) { \
415 return static_cast<Fn&&>(fn)(static_cast<V&&>(v).template unsafe_get<N+Offset>()); \
417 } else PLUGIFY_UNREACHABLE();
426 if constexpr (SEQSIZE < RemainingIndex)
427 return detail::single_visit_tail<Offset + SEQSIZE, Rtype>(
static_cast<Fn&&
>(fn),
static_cast<V&&
>(v));
429 PLUGIFY_UNREACHABLE();
436 template<
unsigned Offset,
class Rtype,
class Fn,
class V>
437 constexpr Rtype single_visit_w_index_tail(Fn&& fn, V&& v) {
439 constexpr auto RemainingIndex = std::decay_t<V>::size - Offset;
441#define X(N) case (N + Offset) : \
442 if constexpr (N < RemainingIndex) { \
443 return static_cast<Fn&&>(fn)(static_cast<V&&>(v).template unsafe_get<N+Offset>(), std::integral_constant<unsigned, N+Offset>{}); \
445 } else PLUGIFY_UNREACHABLE();
454 if constexpr (SEQSIZE < RemainingIndex)
455 return detail::single_visit_w_index_tail<Offset + SEQSIZE, Rtype>(
static_cast<Fn&&
>(fn),
static_cast<V&&
>(v));
457 PLUGIFY_UNREACHABLE();
464 template<
class Fn,
class V>
465 constexpr decltype(
auto) visit(Fn&& fn, V&& v) {
466 return detail::single_visit_tail<0, rtype_visit<Fn&&, V&&>>(PLG_FWD(fn), PLG_FWD(v));
471 template<
class Fn,
class V>
472 constexpr decltype(
auto) visit_with_index(V&& v, Fn&& fn) {
473 return detail::single_visit_w_index_tail<0, rtype_index_visit<Fn&&, V&&>>(PLG_FWD(fn), PLG_FWD(v));
476 template<
class Fn,
class Head,
class... Tail>
477 constexpr decltype(
auto) multi_visit(Fn&& fn, Head&& head, Tail&&... tail) {
480 auto vis = [&fn, &head] (
auto&&... args) ->
decltype(
auto) {
481 return detail::visit([&fn, &args...] (
auto&& elem) ->
decltype(
auto) {
482 return PLG_FWD(fn)(PLG_FWD(elem), PLG_FWD(args)...);
486 if constexpr (
sizeof...(tail) == 0)
487 return PLG_FWD(vis)();
488 else if constexpr (
sizeof...(tail) == 1)
489 return detail::visit(PLG_FWD(vis), PLG_FWD(tail)...);
491 return detail::multi_visit(PLG_FWD(vis), PLG_FWD(tail)...);
507 constexpr bool operator==(
T idx)
const noexcept {
return idx == std::numeric_limits<T>::max(); }
513 template<
class...
Ts>
519 template<
typename...
Ts>
529 template<
class...
Ts>
531 (std::is_array_v<Ts> || ...)
532 || (std::is_reference_v<Ts> || ...)
533 || (std::is_void_v<Ts> || ...)
534 ||
sizeof...(Ts) == 0
537 static_assert(
sizeof...(Ts) > 0,
"A variant cannot be empty.");
538 static_assert(
not(std::is_reference_v<Ts> || ...),
"A variant cannot contain references, consider using reference wrappers instead.");
539 static_assert(
not(std::is_void_v<Ts> || ...),
"A variant cannot contains void.");
540 static_assert(
not(std::is_array_v<Ts> || ...),
"A variant cannot contain a raw array type, consider using std::array instead.");
543 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>>)
584 requires trivial_copy_ctor
590 requires (has_copy_ctor
and not trivial_copy_ctor)
597 requires trivial_move_ctor
602 noexcept((std::is_nothrow_move_constructible_v<Ts> && ...))
603 requires (has_move_ctor
and not trivial_move_ctor)
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>>
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>)
617 template<std::size_t
Index,
class...
Args>
624 template<
class T,
class...
Args>
625 requires (detail::appears_exactly_once<
T,
Ts...> && std::is_constructible_v<
T,
Args&&...>)
631 template<std::size_t
Index,
class U,
class...
Args>
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&&...>
651 constexpr ~variant()
requires trivial_dtor =
default;
661 requires trivial_copy_assign && trivial_copy_ctor
666 requires (has_copy_assign
and not(trivial_copy_assign && trivial_copy_ctor)) {
675 constexpr bool do_simple_copy = std::is_nothrow_copy_constructible_v<type>
676 or not std::is_nothrow_move_constructible_v<type>;
690 requires (trivial_move_assign
and trivial_move_ctor
and trivial_dtor)
695 noexcept((std::is_nothrow_move_constructible_v<Ts> && ...) && (std::is_nothrow_move_assignable_v<Ts> && ...))
696 requires (has_move_assign && has_move_ctor
and not(trivial_move_assign
and trivial_move_ctor
and trivial_dtor)) {
713 noexcept(std::is_nothrow_assignable_v<detail::best_overload_match<
T&&,
Ts...>,
T&&>
714 && std::is_nothrow_constructible_v<detail::best_overload_match<
T&&,
Ts...>,
T&&>) {
722 std::is_nothrow_constructible_v<related_type, T>
723 or not std::is_nothrow_move_constructible_v<related_type>;
738 template<
class T,
class...
Args>
739 requires (std::is_constructible_v<
T,
Args&&...> && detail::appears_exactly_once<
T,
Ts...>)
744 template<std::size_t
Idx,
class...
Args>
746 constexpr auto& emplace(
Args&&...
args) {
751 template<std::size_t
Idx,
class U,
class...
Args>
753 && std::is_constructible_v<alternative<Idx>, std::initializer_list<U>&,
Args&&...>)
754 constexpr auto& emplace(std::initializer_list<U>
list,
Args&&...
args) {
758 template<
class T,
class U,
class...
Args>
759 requires (std::is_constructible_v<T, std::initializer_list<U>&,
Args&&...>
760 && detail::appears_exactly_once<
T,
Ts...>)
761 constexpr T& emplace(std::initializer_list<U>
list,
Args&&...
args) {
767 constexpr bool valueless_by_exception()
const noexcept {
768 if constexpr (can_be_valueless)
769 return _current == npos;
773 constexpr index_type index()
const noexcept {
780 noexcept((std::is_nothrow_move_constructible_v<Ts> && ...)
781 && (detail::swap_trait::template
nothrow<Ts> && ...))
782 requires (has_move_ctor && (detail::swap_trait::template
able<Ts> && ...)) {
783 if constexpr (can_be_valueless) {
788 full.reset_no_check();
789 full._current = npos;
792 switch(
static_cast<int>(index() == npos) +
static_cast<int>(
o.index() == npos) * 2) {
809 assert(
not(valueless_by_exception() &&
o.valueless_by_exception()));
823 detail::destruct<alternative<this_index>>(
this_elem);
829 detail::destruct<alternative<idx_t::value>>(
elem);
838 template<detail::union_index_t Idx>
839 constexpr auto& unsafe_get() &
noexcept {
840 static_assert(
Idx < size);
842 return _storage.template
get<Idx>();
845 template<detail::union_index_t Idx>
846 constexpr auto&& unsafe_get() &&
noexcept {
847 static_assert(
Idx < size);
849 return PLG_MOV(_storage.template
get<Idx>());
852 template<detail::union_index_t Idx>
853 constexpr const auto& unsafe_get()
const &
noexcept {
854 static_assert(
Idx < size);
856 return _storage.template
get<Idx>();
859 template<detail::union_index_t Idx>
860 constexpr const auto&& unsafe_get()
const &&
noexcept {
861 static_assert(
Idx < size);
863 return PLG_MOV(_storage.template
get<Idx>());
868 template<
class Other,
class Fn>
869 constexpr void assign_from(
Other&&
o,
Fn&&
fn) {
870 if constexpr (can_be_valueless) {
871 if (
o.index() == npos) {
872 if (_current != npos) {
880 detail::visit_with_index(PLG_FWD(
o), PLG_FWD(
fn));
883 template<
unsigned Idx,
class...
Args>
884 constexpr auto& emplace_impl(
Args&&...
args) {
891 template<
unsigned Idx,
class...
Args>
892 constexpr void emplace_no_dtor(
Args&&...
args) {
895 if constexpr (
not std::is_nothrow_constructible_v<
T,
Args&&...>)
897 if constexpr (std::is_nothrow_move_constructible_v<T>)
901 else if constexpr (std::is_nothrow_copy_constructible_v<T>)
908 static_assert(can_be_valueless && (
Idx ==
Idx),
909 "Internal error : the possibly valueless branch of emplace was taken despite |can_be_valueless| being false");
918 template<
unsigned Idx,
class...
Args>
919 constexpr void do_emplace_no_dtor(
Args&&...
args) {
920 _current =
static_cast<index_type
>(
Idx);
924#ifdef PLUGIFY_VARIANT_NO_CONSTEXPR_EMPLACE
926 new (
const_cast<void*
>(ptr))
t(PLG_FWD(
args)...);
928 std::construct_at(ptr, PLG_FWD(
args)...);
933 constexpr void reset() {
934 if constexpr (can_be_valueless)
935 if (valueless_by_exception())
return;
940 constexpr void reset_no_check() {
942 if constexpr (
not trivial_dtor) {
943 detail::visit_with_index(*
this, [](
auto&
elem,
auto index_cst) {
944 detail::destruct<alternative<index_cst>>(
elem);
950 template<
class Other>
951 constexpr void construct_from(
Other&&
o) {
952 if constexpr (can_be_valueless)
953 if (
o.valueless_by_exception()) {
965#if INTPTR_MAX == INT32_MAX
966 volatile char pad[8];
973 template<
class T,
class...
Ts>
975 static_assert((std::is_same_v<T, Ts> || ...),
"Requested type is not contained in the variant");
977 return v.index() ==
Index;
982 template<std::size_t Idx,
class... Ts>
983 constexpr auto& get(variant<Ts...>& v) {
984 static_assert(Idx <
sizeof...(Ts),
"Index exceeds the variant size. ");
985 PLUGIFY_ASSERT(v.index() == Idx,
"plg::variant:get(): Bad variant access in get.", bad_variant_access);
986 return (v.template unsafe_get<Idx>());
989 template<std::size_t Idx,
class... Ts>
990 constexpr const auto& get(
const variant<Ts...>& v) {
994 template<std::size_t Idx,
class... Ts>
995 constexpr auto&& get(variant<Ts...>&& v) {
999 template<std::size_t Idx,
class... Ts>
1000 constexpr const auto&& get(
const variant<Ts...>&& v) {
1006 template<
class T,
class... Ts>
1007 constexpr T& get(variant<Ts...>& v) {
1008 return plg::get<variant<Ts...>::template index_of<T> >(v);
1011 template<
class T,
class... Ts>
1012 constexpr const T& get(
const variant<Ts...>& v) {
1013 return plg::get<variant<Ts...>::template index_of<T> >(v);
1016 template<
class T,
class... Ts>
1017 constexpr T&& get(variant<Ts...>&& v) {
1018 return plg::get<variant<Ts...>::template index_of<T> >(PLG_FWD(v));
1021 template<
class T,
class... Ts>
1022 constexpr const T&& get(
const variant<Ts...>&& v) {
1023 return plg::get<variant<Ts...>::template index_of<T> >(PLG_FWD(v));
1028 template<std::size_t Idx,
class... Ts>
1029 constexpr const auto* get_if(
const variant<Ts...>* v)
noexcept {
1030 using rtype =
typename variant<Ts...>::template alternative<Idx>*;
1031 if (v ==
nullptr || v->index() != Idx)
1032 return rtype{
nullptr};
1034 return detail::addressof(v->template unsafe_get<Idx>());
1037 template<std::size_t Idx,
class... Ts>
1038 constexpr auto* get_if(variant<Ts...>* v)
noexcept {
1039 using rtype =
typename variant<Ts...>::template alternative<Idx>;
1040 return const_cast<rtype*
>(
1047 template<
class T,
class... Ts>
1048 constexpr T* get_if(variant<Ts...>* v)
noexcept {
1049 static_assert((std::is_same_v<T, Ts> || ...),
"Requested type is not contained in the variant");
1050 return plg::get_if<variant<Ts...>::template index_of<T> >(v);
1053 template<
class T,
class... Ts>
1054 constexpr const T* get_if(
const variant<Ts...>* v)
noexcept {
1055 static_assert((std::is_same_v<T, Ts> || ...),
"Requested type is not contained in the variant");
1056 return plg::get_if<variant<Ts...>::template index_of<T> >(v);
1061 template<
class Fn,
class... Vs>
1062 constexpr decltype(
auto) visit(Fn&& fn, Vs&&... vs) {
1063 if constexpr ((std::decay_t<Vs>::can_be_valueless || ...))
1064 PLUGIFY_ASSERT(!(vs.valueless_by_exception() || ...),
"plg::variant:visit(): Bad variant access in visit.", bad_variant_access);
1066 if constexpr (
sizeof...(Vs) == 1)
1067 return detail::visit(PLG_FWD(fn), PLG_FWD(vs)...);
1069 return detail::multi_visit(PLG_FWD(fn), PLG_FWD(vs)...);
1073 constexpr decltype(
auto) visit(Fn&& fn) {
1074 return PLG_FWD(fn)();
1077 template<
class R,
class Fn,
class... Vs>
1078 requires (is_variant_v<Vs> && ...)
1079 constexpr R visit(Fn&& fn, Vs&&... vars) {
1080 return static_cast<R
>(plg::visit(PLG_FWD(fn), PLG_FWD(vars)...));
1085 template<
class... Ts>
1086 requires (detail::has_eq_comp<Ts> && ...)
1087 constexpr bool operator==(
const variant<Ts...>& v1,
const variant<Ts...>& v2) {
1088 if (v1.index() != v2.index())
1090 if constexpr (variant<Ts...>::can_be_valueless)
1091 if (v1.valueless_by_exception())
return true;
1092 return detail::visit_with_index(v2, [&v1](
auto& elem,
auto index) ->
bool {
1093 return (v1.template unsafe_get<index>() == elem);
1097 template<
class... Ts>
1098 constexpr bool operator!=(
const variant<Ts...>& v1,
const variant<Ts...>& v2)
1099 requires requires { v1 == v2; }
1101 return not(v1 == v2);
1104 template<
class... Ts>
1105 requires (detail::has_lesser_comp<const Ts&> && ...)
1106 constexpr bool operator<(
const variant<Ts...>& v1,
const variant<Ts...>& v2) {
1107 if constexpr (variant<Ts...>::can_be_valueless) {
1108 if (v2.valueless_by_exception())
return false;
1109 if (v1.valueless_by_exception())
return true;
1111 if (v1.index() == v2.index()) {
1112 return detail::visit_with_index(v1, [&v2](
auto& elem,
auto index) ->
bool {
1113 return (elem < v2.template unsafe_get<index>());
1117 return (v1.index() < v2.index());
1120 template<
class... Ts>
1121 constexpr bool operator>(
const variant<Ts...>& v1,
const variant<Ts...>& v2)
1122 requires requires { v2 < v1; }
1127 template<
class... Ts>
1128 requires (detail::has_less_or_eq_comp<const Ts&> && ...)
1129 constexpr bool operator<=(
const variant<Ts...>& v1,
const variant<Ts...>& v2) {
1130 if constexpr (variant<Ts...>::can_be_valueless) {
1131 if (v1.valueless_by_exception())
return true;
1132 if (v2.valueless_by_exception())
return false;
1134 if (v1.index() == v2.index()) {
1135 return detail::visit_with_index(v1, [&v2](
auto& elem,
auto index) ->
bool {
1136 return (elem <= v2.template unsafe_get<index>());
1140 return (v1.index() < v2.index());
1143 template<
class... Ts>
1144 constexpr bool operator>=(
const variant<Ts...>& v1,
const variant<Ts...>& v2)
1145 requires requires { v2 <= v1; }
1154 constexpr bool operator> (monostate, monostate)
noexcept {
return false; }
1155 constexpr bool operator< (monostate, monostate)
noexcept {
return false; }
1156 constexpr bool operator<=(monostate, monostate)
noexcept {
return true; }
1157 constexpr bool operator>=(monostate, monostate)
noexcept {
return true; }
1161 template<
class... Ts>
1162 constexpr void swap(variant<Ts...>& a, variant<Ts...>& b)
1163 noexcept(
noexcept(a.swap(b)))
1164 requires requires { a.swap(b); }
1172 requires is_variant_v<T>
1173 inline constexpr std::size_t variant_size_v = std::decay_t<T>::size;
1177 requires is_variant_v<T>
1178 struct variant_size : std::integral_constant<std::size_t, variant_size_v<T>> {};
1182 template<
bool IsVolatile>
1183 struct var_alt_impl {
1184 template<std::
size_t Idx,
class T>
1185 using type = std::remove_reference_t<decltype(std::declval<T>().template
unsafe_get<Idx>())>;
1189 struct var_alt_impl<true> {
1190 template<std::
size_t Idx,
class T>
1191 using type =
volatile typename var_alt_impl<false>::template type<Idx, std::remove_volatile_t<T>>;
1195 template<std::
size_t Idx,
class T>
1196 requires (Idx < variant_size_v<T>)
1197 using variant_alternative_t =
typename detail::var_alt_impl<std::is_volatile_v<T>>::template type<Idx, T>;
1199 template<std::
size_t Idx,
class T>
1200 requires is_variant_v<T>
1207 template<std::
size_t Idx,
class Var>
1209 constexpr auto&& unsafe_get(
Var&&
var)
noexcept {
1214 template<
class T,
class Var>
1215 requires is_variant_v<Var>
1216 constexpr auto&& unsafe_get(Var&& var)
noexcept {
1223#ifndef PLUGIFY_VARIANT_NO_STD_HASH
1225 template<
class... Ts>
1226 requires (plg::detail::has_std_hash<Ts> && ...)
1227 struct hash<plg::variant<Ts...>> {
1230 if (v.valueless_by_exception())
1231 return static_cast<std::size_t
>(-1);
1233 return plg::detail::visit_with_index(v, [](
auto& elem,
auto index_) {
1234 using type = std::remove_cvref_t<
decltype(elem)>;
1235 return std::hash<type>{}(elem) + index_;
1241 struct hash<plg::monostate> {
1242 constexpr std::size_t operator()(
plg::monostate)
const noexcept {
return static_cast<size_t>(-1); }