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>
103 requires requires {
arr1<A>{std::declval<T>()}; }
108 template<
class Seq,
class...
Args>
111 template<std::size_t...
Idx,
class...
Args>
117 template<
class T,
class...
Ts>
118 using best_overload_match =
typename decltype(
120 (std::declval<T>(), std::declval<T>())
124 template<
class T,
class...
Ts>
126 requires {
typename best_overload_match<
T,
Ts...>; };
130 template<
class From,
class To>
131 concept convertible = std::is_convertible_v<From, To>;
134 concept has_eq_comp =
requires (T a, T b) {
135 { a == b } -> convertible<bool>;
139 concept has_lesser_comp =
requires (T a, T b) {
140 { a < b } -> convertible<bool>;
144 concept has_less_or_eq_comp =
requires (T a, T b) {
145 { a <= b } -> convertible<bool>;
151 template<
class T,
class NT, NT N>
152 constexpr void operator()(
T&&
elem, std::integral_constant<NT, N>
index_)
const {
158 template<
class E,
class T>
159 constexpr void destruct(
T&
obj) {
160 if constexpr (
not std::is_trivially_destructible_v<E>)
173#define TRAIT(trait) (std::is_##trait##_v<A> && std::is_##trait##_v<B>)
176# define SFM_DEF_REQ(trait) \
177 requires (TRAIT(trait) and not TRAIT(trivially_##trait))
179# define SFM_DEF_REQ(trait)
182#define SFM(signature, impl) \
186#define SFM2(signature, req, impl) \
187 signature = default; \
192#if __cpp_constexpr >= 201907L
193# define SFM_DTOR(X) constexpr ~X()
195# define SFM_DTOR(X) ~X()
201# define INJECT_UNION_SFM(X) \
202 SFM2(constexpr X (const X &), SFM_DEF_REQ(copy_constructible), {}) \
203 SFM2(constexpr X (X&&) noexcept, SFM_DEF_REQ(move_constructible), {}) \
204 SFM2(constexpr X& operator=(const X&), SFM_DEF_REQ(copy_assignable), { return *this; }) \
205 SFM2(constexpr X& operator=(X&&) noexcept, SFM_DEF_REQ(move_assignable), { return *this; }) \
206 SFM2(SFM_DTOR(X), SFM_DEF_REQ(destructible), {})
208# define INJECT_UNION_SFM(X) \
209 SFM(constexpr X (const X &), {}) \
210 SFM(constexpr X (X&&) noexcept, {}) \
211 SFM(constexpr X& operator=(const X&), { return *this; }) \
212 SFM(constexpr X& operator=(X&&) noexcept, { return *this; }) \
216 template<
bool IsLeaf>
222 template<
class A,
class B>
223 static constexpr auto elem_size =
not(std::is_same_v<B, dummy_type>) ? 2 : 1;
225 template<std::
size_t,
class>
226 static constexpr char ctor_branch = 0;
231 template<
class A,
class B>
232 static constexpr auto elem_size = A::elem_size + B::elem_size;
234 template<std::
size_t Index,
class A>
235 static constexpr char ctor_branch = (
Index < A::elem_size) ? 1 : 2;
238 template<
bool IsLeaf,
class A,
class B>
249 template<std::size_t
Index,
class...
Args>
258 template<std::size_t
Index,
class...
Args>
261 : b{in_place_index<
Index - A::elem_size>,
static_cast<Args&&
>(
args)...}
265 template<
class...
Args>
273 template<
class...
Args>
283 requires (std::is_same_v<dummy_type, B>)
288 template<union_index_t Index>
289 constexpr auto& get() {
291 if constexpr (
Index == 0)
296 if constexpr (
Index < A::elem_size)
299 return b.template get<
Index - A::elem_size>();
303 template<union_index_t Index>
304 constexpr const auto& get()
const {
311#undef INJECT_UNION_SFM
319 constexpr unsigned char pick_next(
unsigned remaining) {
323 template<
unsigned char Pick,
unsigned char GoOn,
bool FirstPass>
326 template<
bool IsFirstPass>
346 template<
unsigned,
class A>
351 template<
bool IsFirstPass>
356 pick_next(
sizeof...(
Ts)),
357 (
sizeof...(Ts) != 1),
360 ::template f<
sizeof...(Ts),
Ts...>;
367 using f =
typename make_tree<0,
sizeof...(Ts) != 0,
false>
375 using f =
typename make_tree<0,
sizeof...(Ts) != 0,
false>
379 template<
class...
Ts>
380 using make_tree_union =
typename
381 make_tree<pick_next(
sizeof...(
Ts)), 1,
true>::template f<
sizeof...(Ts),
Ts...>;
386 template<std::size_t
Num,
class...
Ts>
393 namespace swap_trait {
398 concept able =
requires (
A a,
A b) { swap(a, b); };
402 inline constexpr bool nothrow =
noexcept(swap(std::declval<A&>(), std::declval<A&>()));
405#ifndef PLUGIFY_VARIANT_NO_STD_HASH
406# ifdef __cpp_concepts
408 inline constexpr bool has_std_hash =
411 std::size_t(::std::hash<std::remove_cvref_t<T>>{}(t));
417 inline constexpr T* addressof(T& obj)
noexcept {
418#if defined(__GNUC__) || defined(__clang__)
419 return __builtin_addressof(obj);
420#elif defined(PLUGIFY_VARIANT_NO_CONSTEXPR_EMPLACE)
422 if constexpr (
requires { obj.operator&(); })
423 return reinterpret_cast<T*
>
424 (&
const_cast<char&
>(
reinterpret_cast<const volatile char&
>(obj)));
428 return std::addressof(obj);
434 template<
class Fn,
class... Vars>
435 using rtype_visit =
decltype((std::declval<Fn>()(std::declval<Vars>().template unsafe_get<0>()...)));
437 template<
class Fn,
class Var>
438 using rtype_index_visit =
decltype((std::declval<Fn>()(std::declval<Var>().template unsafe_get<0>(),
439 std::integral_constant<std::size_t, 0>{}))
442 inline namespace v1 {
444#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)
446#define SEQ30(N) DEC((N) + 0) DEC((N) + 10) DEC((N) + 20)
447#define SEQ100(N) SEQ30((N) + 0) SEQ30((N) + 30) SEQ30((N) + 60) DEC((N) + 90)
448#define SEQ200(N) SEQ100((N) + 0) SEQ100((N) + 100)
449#define SEQ400(N) SEQ200((N) + 0) SEQ200((N) + 200)
450#define CAT(M, N) M##N
451#define CAT2(M, N) CAT(M, N)
452#define INJECTSEQ(N) CAT2(SEQ, N)(0)
456 template<
unsigned Offset,
class Rtype,
class Fn,
class V>
457 constexpr Rtype single_visit_tail(Fn&& fn, V&& v) {
459 constexpr auto RemainingIndex = std::decay_t<V>::size - Offset;
461#define X(N) case (N + Offset) : \
462 if constexpr (N < RemainingIndex) { \
463 return static_cast<Fn&&>(fn)(static_cast<V&&>(v).template unsafe_get<N+Offset>()); \
465 } else PLUGIFY_UNREACHABLE();
474 if constexpr (SEQSIZE < RemainingIndex)
475 return detail::single_visit_tail<Offset + SEQSIZE, Rtype>(
static_cast<Fn&&
>(fn),
static_cast<V&&
>(v));
477 PLUGIFY_UNREACHABLE();
484 template<
unsigned Offset,
class Rtype,
class Fn,
class V>
485 constexpr Rtype single_visit_w_index_tail(Fn&& fn, V&& v) {
487 constexpr auto RemainingIndex = std::decay_t<V>::size - Offset;
489#define X(N) case (N + Offset) : \
490 if constexpr (N < RemainingIndex) { \
491 return static_cast<Fn&&>(fn)(static_cast<V&&>(v).template unsafe_get<N+Offset>(), std::integral_constant<unsigned, N+Offset>{}); \
493 } else PLUGIFY_UNREACHABLE();
502 if constexpr (SEQSIZE < RemainingIndex)
503 return detail::single_visit_w_index_tail<Offset + SEQSIZE, Rtype>(
static_cast<Fn&&
>(fn),
static_cast<V&&
>(v));
505 PLUGIFY_UNREACHABLE();
512 template<
class Fn,
class V>
513 constexpr decltype(
auto) visit(Fn&& fn, V&& v) {
514 return detail::single_visit_tail<0, rtype_visit<Fn&&, V&&>>(PLG_FWD(fn), PLG_FWD(v));
519 template<
class Fn,
class V>
520 constexpr decltype(
auto) visit_with_index(V&& v, Fn&& fn) {
521 return detail::single_visit_w_index_tail<0, rtype_index_visit<Fn&&, V&&>>(PLG_FWD(fn), PLG_FWD(v));
524 template<
class Fn,
class Head,
class... Tail>
525 constexpr decltype(
auto) multi_visit(Fn&& fn, Head&& head, Tail&&... tail) {
528 auto vis = [&fn, &head] (
auto&&... args) ->
decltype(
auto) {
529 return detail::visit([&fn, &args...] (
auto&& elem) ->
decltype(
auto) {
530 return PLG_FWD(fn)(PLG_FWD(elem), PLG_FWD(args)...);
534 if constexpr (
sizeof...(tail) == 0)
535 return PLG_FWD(vis)();
536 else if constexpr (
sizeof...(tail) == 1)
537 return detail::visit(PLG_FWD(vis), PLG_FWD(tail)...);
539 return detail::multi_visit(PLG_FWD(vis), PLG_FWD(tail)...);
555 constexpr bool operator==(
T idx)
const noexcept {
return idx == std::numeric_limits<T>::max(); }
561 template<
class...
Ts>
567 template<
typename...
Ts>
578 template<
class...
Ts>
580 (std::is_array_v<Ts> || ...)
581 || (std::is_reference_v<Ts> || ...)
582 || (std::is_void_v<Ts> || ...)
583 ||
sizeof...(Ts) == 0
586 static_assert(
sizeof...(Ts) > 0,
"A variant cannot be empty.");
587 static_assert(
not(std::is_reference_v<Ts> || ...),
"A variant cannot contain references, consider using reference wrappers instead.");
588 static_assert(
not(std::is_void_v<Ts> || ...),
"A variant cannot contains void.");
589 static_assert(
not(std::is_array_v<Ts> || ...),
"A variant cannot contain a raw array type, consider using std::array instead.");
593 template<
class... Ts>
597 static constexpr bool is_trivial = std::is_trivial_v<storage>;
598 static constexpr bool has_copy_ctor = std::is_copy_constructible_v<storage>;
599 static constexpr bool trivial_copy_ctor = is_trivial || std::is_trivially_copy_constructible_v<storage>;
600 static constexpr bool has_copy_assign = std::is_copy_constructible_v<storage>;
601 static constexpr bool trivial_copy_assign = is_trivial || std::is_trivially_copy_assignable_v<storage>;
602 static constexpr bool has_move_ctor = std::is_move_constructible_v<storage>;
603 static constexpr bool trivial_move_ctor = is_trivial || std::is_trivially_move_constructible_v<storage>;
604 static constexpr bool has_move_assign = std::is_move_assignable_v<storage>;
605 static constexpr bool trivial_move_assign = is_trivial || std::is_trivially_move_assignable_v<storage>;
606 static constexpr bool trivial_dtor = std::is_trivially_destructible_v<storage>;
609 template<std::
size_t Idx>
610 using alternative = std::remove_reference_t<decltype(std::declval<storage&>().template
get<Idx>())>;
612 static constexpr bool can_be_valueless =
not is_trivial;
614 static constexpr unsigned size =
sizeof...(Ts);
616 using index_type = detail::smallest_suitable_integer_type<
sizeof...(Ts) + can_be_valueless,
unsigned char,
unsigned short,
unsigned>;
618 static constexpr index_type npos =
static_cast<index_type
>(-1);
621 static constexpr int index_of = detail::find_first_true({std::is_same_v<T, Ts>...});
627 noexcept(std::is_nothrow_default_constructible_v<alternative<0>>)
637 requires trivial_copy_ctor
645 requires (has_copy_ctor
and not trivial_copy_ctor)
654 requires trivial_move_ctor
660 noexcept((std::is_nothrow_move_constructible_v<Ts> && ...))
662 requires (has_move_ctor
and not trivial_move_ctor)
665 construct_from(
static_cast<variant&&
>(
o));
669 template<
class T,
class M = detail::best_overload_match<
T&&,
Ts...>,
class D = std::decay_t<T>>
671 noexcept(std::is_nothrow_constructible_v<M, T&&>)
673 requires (
not std::is_same_v<D, variant>
and not std::is_base_of_v<detail::emplacer_tag, D>)
679 template<std::size_t
Index,
class...
Args>
688 template<
class T,
class...
Args>
690 requires (detail::appears_exactly_once<
T,
Ts...> && std::is_constructible_v<
T,
Args&&...>)
697 template<std::size_t
Index,
class U,
class...
Args>
708 template<
class T,
class U,
class...
Args>
711 detail::appears_exactly_once<
T,
Ts...>
712 && std::is_constructible_v<T, std::initializer_list<U>&,
Args&&...>
722# if __cpp_constexpr >= 201907L
723 constexpr ~variant()
requires trivial_dtor =
default;
728 ~variant()
requires trivial_dtor =
default;
744 requires trivial_copy_assign && trivial_copy_ctor
751 requires (has_copy_assign
and not(trivial_copy_assign && trivial_copy_ctor))
763 std::is_nothrow_copy_constructible_v<type>
764 or not std::is_nothrow_move_constructible_v<type>;
779 requires (trivial_move_assign
and trivial_move_ctor
and trivial_dtor)
785 noexcept((std::is_nothrow_move_constructible_v<Ts> && ...) && (std::is_nothrow_move_assignable_v<Ts> && ...))
787 requires (has_move_assign && has_move_ctor
and not(trivial_move_assign
and trivial_move_ctor
and trivial_dtor))
805 requires detail::has_non_ambiguous_match<
T,
Ts...>
808 noexcept(std::is_nothrow_assignable_v<detail::best_overload_match<
T&&,
Ts...>,
T&&>
809 && std::is_nothrow_constructible_v<detail::best_overload_match<
T&&,
Ts...>,
T&&>) {
817 std::is_nothrow_constructible_v<related_type, T>
818 or not std::is_nothrow_move_constructible_v<related_type>;
833 template<
class T,
class...
Args>
835 requires (std::is_constructible_v<
T,
Args&&...> && detail::appears_exactly_once<
T,
Ts...>)
841 template<std::size_t
Idx,
class...
Args>
845 constexpr auto& emplace(
Args&&...
args) {
850 template<std::size_t
Idx,
class U,
class...
Args>
853 && std::is_constructible_v<alternative<Idx>, std::initializer_list<U>&,
Args&&...>)
855 constexpr auto& emplace(std::initializer_list<U>
list,
Args&&...
args) {
859 template<
class T,
class U,
class...
Args>
861 requires (std::is_constructible_v<T, std::initializer_list<U>&,
Args&&...>
862 && detail::appears_exactly_once<
T,
Ts...>)
864 constexpr T& emplace(std::initializer_list<U>
list,
Args&&...
args) {
870 [[
nodiscard]]
constexpr bool valueless_by_exception()
const noexcept {
871 if constexpr (can_be_valueless)
872 return _current == npos;
876 [[
nodiscard]]
constexpr index_type index()
const noexcept {
883 noexcept((std::is_nothrow_move_constructible_v<Ts> && ...)
884 && (detail::swap_trait::template
nothrow<Ts> && ...))
886 requires (has_move_ctor && (detail::swap_trait::template
able<Ts> && ...))
889 if constexpr (can_be_valueless) {
894 full.reset_no_check();
895 full._current = npos;
898 switch(
static_cast<int>(index() == npos) +
static_cast<int>(
o.index() == npos) * 2) {
915 assert(
not(valueless_by_exception() &&
o.valueless_by_exception()));
929 detail::destruct<alternative<this_index>>(
this_elem);
935 detail::destruct<alternative<idx_t::value>>(
elem);
944 template<detail::union_index_t Idx>
945 [[
nodiscard]]
constexpr auto& unsafe_get() &
noexcept {
946 static_assert(
Idx < size);
948 return _storage.template
get<Idx>();
951 template<detail::union_index_t Idx>
952 [[
nodiscard]]
constexpr auto&& unsafe_get() &&
noexcept {
953 static_assert(
Idx < size);
955 return PLG_MOV(_storage.template
get<Idx>());
958 template<detail::union_index_t Idx>
959 [[
nodiscard]]
constexpr const auto& unsafe_get()
const &
noexcept {
960 static_assert(
Idx < size);
962 return _storage.template
get<Idx>();
965 template<detail::union_index_t Idx>
966 [[
nodiscard]]
constexpr const auto&& unsafe_get()
const &&
noexcept {
967 static_assert(
Idx < size);
969 return PLG_MOV(_storage.template
get<Idx>());
974 template<
class Other,
class Fn>
975 constexpr void assign_from(
Other&&
o,
Fn&&
fn) {
976 if constexpr (can_be_valueless) {
977 if (
o.index() == npos) {
978 if (_current != npos) {
986 detail::visit_with_index(PLG_FWD(
o), PLG_FWD(
fn));
989 template<
unsigned Idx,
class...
Args>
990 constexpr auto& emplace_impl(
Args&&...
args) {
997 template<
unsigned Idx,
class...
Args>
998 constexpr void emplace_no_dtor(
Args&&...
args) {
1001 if constexpr (
not std::is_nothrow_constructible_v<
T,
Args&&...>)
1003 if constexpr (std::is_nothrow_move_constructible_v<T>)
1007 else if constexpr (std::is_nothrow_copy_constructible_v<T>)
1014 static_assert(can_be_valueless,
1015 "Internal error : the possibly valueless branch of emplace was taken despite |can_be_valueless| being false");
1024 template<
unsigned Idx,
class...
Args>
1025 constexpr void do_emplace_no_dtor(
Args&&...
args) {
1026 _current =
static_cast<index_type
>(
Idx);
1030#ifdef PLUGIFY_VARIANT_NO_CONSTEXPR_EMPLACE
1032 new ((
void*)(ptr))
t(PLG_FWD(
args)...);
1034 PLUGIFY_CONSTRUCT_AT(ptr, PLG_FWD(
args)...);
1039 constexpr void reset() {
1040 if constexpr (can_be_valueless)
1041 if (valueless_by_exception())
return;
1046 constexpr void reset_no_check() {
1048 if constexpr (
not trivial_dtor) {
1049 detail::visit_with_index(*
this, [](
auto&
elem,
auto index_cst) {
1050 detail::destruct<alternative<index_cst>>(
elem);
1056 template<
class Other>
1057 constexpr void construct_from(
Other&&
o) {
1058 if constexpr (can_be_valueless)
1059 if (
o.valueless_by_exception()) {
1071 index_type _current;
1076 template<
class T,
class...
Ts>
1078 static_assert((std::is_same_v<T, Ts> || ...),
"Requested type is not contained in the variant");
1080 return v.index() ==
Index;
1085 template<std::size_t Idx,
class... Ts>
1086 [[nodiscard]]
constexpr auto& get(variant<Ts...>& v) {
1087 static_assert(Idx <
sizeof...(Ts),
"Index exceeds the variant size. ");
1088 PLUGIFY_ASSERT(v.index() == Idx,
"plg::variant:get(): Bad variant access in get.", bad_variant_access);
1089 return (v.template unsafe_get<Idx>());
1092 template<std::size_t Idx,
class... Ts>
1093 [[nodiscard]]
constexpr const auto& get(
const variant<Ts...>& v) {
1097 template<std::size_t Idx,
class... Ts>
1098 [[nodiscard]]
constexpr auto&& get(variant<Ts...>&& v) {
1102 template<std::size_t Idx,
class... Ts>
1103 [[nodiscard]]
constexpr const auto&& get(
const variant<Ts...>&& v) {
1109 template<
class T,
class... Ts>
1110 [[nodiscard]]
constexpr T& get(variant<Ts...>& v) {
1111 return plg::get<variant<Ts...>::template index_of<T> >(v);
1114 template<
class T,
class... Ts>
1115 [[nodiscard]]
constexpr const T& get(
const variant<Ts...>& v) {
1116 return plg::get<variant<Ts...>::template index_of<T> >(v);
1119 template<
class T,
class... Ts>
1120 [[nodiscard]]
constexpr T&& get(variant<Ts...>&& v) {
1121 return plg::get<variant<Ts...>::template index_of<T> >(PLG_FWD(v));
1124 template<
class T,
class... Ts>
1125 [[nodiscard]]
constexpr const T&& get(
const variant<Ts...>&& v) {
1126 return plg::get<variant<Ts...>::template index_of<T> >(PLG_FWD(v));
1131 template<std::size_t Idx,
class... Ts>
1132 [[nodiscard]]
constexpr const auto* get_if(
const variant<Ts...>* v)
noexcept {
1133 using rtype =
typename variant<Ts...>::template alternative<Idx>*;
1134 if (v ==
nullptr || v->index() != Idx)
1135 return rtype{
nullptr};
1137 return detail::addressof(v->template unsafe_get<Idx>());
1140 template<std::size_t Idx,
class... Ts>
1141 [[nodiscard]]
constexpr auto* get_if(variant<Ts...>* v)
noexcept {
1142 using rtype =
typename variant<Ts...>::template alternative<Idx>;
1143 return const_cast<rtype*
>(
1150 template<
class T,
class... Ts>
1151 [[nodiscard]]
constexpr T* get_if(variant<Ts...>* v)
noexcept {
1152 static_assert((std::is_same_v<T, Ts> || ...),
"Requested type is not contained in the variant");
1153 return plg::get_if<variant<Ts...>::template index_of<T> >(v);
1156 template<
class T,
class... Ts>
1157 [[nodiscard]]
constexpr const T* get_if(
const variant<Ts...>* v)
noexcept {
1158 static_assert((std::is_same_v<T, Ts> || ...),
"Requested type is not contained in the variant");
1159 return plg::get_if<variant<Ts...>::template index_of<T> >(v);
1164 template<
class Fn,
class... Vs>
1165 constexpr decltype(
auto) visit(Fn&& fn, Vs&&... vs) {
1166 if constexpr ((std::decay_t<Vs>::can_be_valueless || ...))
1167 PLUGIFY_ASSERT(!(vs.valueless_by_exception() || ...),
"plg::variant:visit(): Bad variant access in visit.", bad_variant_access);
1169 if constexpr (
sizeof...(Vs) == 1)
1170 return detail::visit(PLG_FWD(fn), PLG_FWD(vs)...);
1172 return detail::multi_visit(PLG_FWD(fn), PLG_FWD(vs)...);
1176 constexpr decltype(
auto) visit(Fn&& fn) {
1177 return PLG_FWD(fn)();
1180 template<
class R,
class Fn,
class... Vs>
1181#ifdef __cpp_concepts
1182 requires (is_variant_v<Vs> && ...)
1184 constexpr R visit(Fn&& fn, Vs&&... vars) {
1185 return static_cast<R
>(plg::visit(PLG_FWD(fn), PLG_FWD(vars)...));
1190 template<
class... Ts>
1191#ifdef __cpp_concepts
1192 requires (detail::has_eq_comp<Ts> && ...)
1194 [[nodiscard]]
constexpr bool operator==(
const variant<Ts...>& v1,
const variant<Ts...>& v2) {
1195 if (v1.index() != v2.index())
1197 if constexpr (variant<Ts...>::can_be_valueless)
1198 if (v1.valueless_by_exception())
return true;
1199 return detail::visit_with_index(v2, [&v1](
auto& elem,
auto index) ->
bool {
1200 return (v1.template unsafe_get<index>() == elem);
1204 template<
class... Ts>
1205 [[nodiscard]]
constexpr bool operator!=(
const variant<Ts...>& v1,
const variant<Ts...>& v2)
1206#ifdef __cpp_concepts
1207 requires requires { v1 == v2; }
1210 return not(v1 == v2);
1213 template<
class... Ts>
1214#ifdef __cpp_concepts
1215 requires (detail::has_lesser_comp<const Ts&> && ...)
1217 [[nodiscard]]
constexpr bool operator<(
const variant<Ts...>& v1,
const variant<Ts...>& v2) {
1218 if constexpr (variant<Ts...>::can_be_valueless) {
1219 if (v2.valueless_by_exception())
return false;
1220 if (v1.valueless_by_exception())
return true;
1222 if (v1.index() == v2.index()) {
1223 return detail::visit_with_index(v1, [&v2](
auto& elem,
auto index) ->
bool {
1224 return (elem < v2.template unsafe_get<index>());
1228 return (v1.index() < v2.index());
1231 template<
class... Ts>
1232 [[nodiscard]]
constexpr bool operator>(
const variant<Ts...>& v1,
const variant<Ts...>& v2)
1233#ifdef __cpp_concepts
1234 requires requires { v2 < v1; }
1240 template<
class... Ts>
1241#ifdef __cpp_concepts
1242 requires (detail::has_less_or_eq_comp<const Ts&> && ...)
1244 [[nodiscard]]
constexpr bool operator<=(
const variant<Ts...>& v1,
const variant<Ts...>& v2) {
1245 if constexpr (variant<Ts...>::can_be_valueless) {
1246 if (v1.valueless_by_exception())
return true;
1247 if (v2.valueless_by_exception())
return false;
1249 if (v1.index() == v2.index()) {
1250 return detail::visit_with_index(v1, [&v2](
auto& elem,
auto index) ->
bool {
1251 return (elem <= v2.template unsafe_get<index>());
1255 return (v1.index() < v2.index());
1258 template<
class... Ts>
1259 [[nodiscard]]
constexpr bool operator>=(
const variant<Ts...>& v1,
const variant<Ts...>& v2)
1260#ifdef __cpp_concepts
1261 requires requires { v2 <= v1; }
1271 [[nodiscard]]
constexpr bool operator> (monostate, monostate)
noexcept {
return false; }
1272 [[nodiscard]]
constexpr bool operator< (monostate, monostate)
noexcept {
return false; }
1273 [[nodiscard]]
constexpr bool operator<=(monostate, monostate)
noexcept {
return true; }
1274 [[nodiscard]]
constexpr bool operator>=(monostate, monostate)
noexcept {
return true; }
1278 template<
class... Ts>
1279 constexpr void swap(variant<Ts...>& a, variant<Ts...>& b)
1280 noexcept(
noexcept(a.swap(b)))
1281#ifdef __cpp_concepts
1282 requires requires { a.swap(b); }
1291#ifdef __cpp_concepts
1292 requires is_variant_v<T>
1294 inline constexpr std::size_t variant_size_v = std::decay_t<T>::size;
1298#ifdef __cpp_concepts
1299 requires is_variant_v<T>
1301 struct variant_size : std::integral_constant<std::size_t, variant_size_v<T>> {};
1305 template<
bool IsVolatile>
1306 struct var_alt_impl {
1307 template<std::
size_t Idx,
class T>
1308 using type = std::remove_reference_t<decltype(std::declval<T>().template
unsafe_get<Idx>())>;
1312 struct var_alt_impl<true> {
1313 template<std::
size_t Idx,
class T>
1314 using type =
volatile typename var_alt_impl<false>::template type<Idx, std::remove_volatile_t<T>>;
1318 template<std::
size_t Idx,
class T>
1319#ifdef __cpp_concepts
1320 requires (Idx < variant_size_v<T>)
1322 using variant_alternative_t =
typename detail::var_alt_impl<std::is_volatile_v<T>>::template type<Idx, T>;
1324 template<std::
size_t Idx,
class T>
1325#ifdef __cpp_concepts
1326 requires is_variant_v<T>
1334 template<std::
size_t Idx,
class Var>
1335#ifdef __cpp_concepts
1343 template<
class T,
class Var>
1344#ifdef __cpp_concepts
1345 requires is_variant_v<Var>
1347 [[nodiscard]]
constexpr auto&& unsafe_get(Var&& var)
noexcept {
1354#ifndef PLUGIFY_VARIANT_NO_STD_HASH
1356 template<
class... Ts>
1357#ifdef __cpp_concepts
1358 requires (plg::detail::has_std_hash<Ts> && ...)
1360 struct hash<plg::variant<Ts...>> {
1363 if (v.valueless_by_exception())
1364 return static_cast<std::size_t
>(-1);
1366 return plg::detail::visit_with_index(v, [](
auto& elem,
auto index_) {
1367 using type = std::remove_cvref_t<
decltype(elem)>;
1368 return std::hash<type>{}(elem) + index_;
1374 struct hash<plg::monostate> {
1375 constexpr std::size_t operator()(
plg::monostate)
const noexcept {
return static_cast<std::size_t
>(-1); }