1 #ifndef DONUT_VARIANT_HPP
2 #define DONUT_VARIANT_HPP
10 #include <initializer_list>
14 #include <type_traits>
27 template <
typename... Ts>
33 struct ConstantList {};
35 template <std::size_t N,
typename Union,
auto... MemberPointers>
36 struct get_n_member_pointers {
37 using type = ConstantList<MemberPointers..., &Union::head>;
40 template <std::size_t N,
typename Union,
auto... MemberPointers>
41 requires(N > 0) struct get_n_member_pointers<N, Union, MemberPointers...> : get_n_member_pointers<N - 1, typename Union::Tail, MemberPointers..., &Union::tail> {};
43 template <std::
size_t N,
typename Union>
44 using get_n_member_pointers_t =
typename get_n_member_pointers<N, Union>::type;
46 template <
auto... MemberPointers,
typename U>
47 [[nodiscard]] constexpr
auto& getUnionMemberImpl(ConstantList<MemberPointers...>, U&& u) noexcept {
48 return (std::forward<U>(u).*....*MemberPointers);
51 template <std::
size_t Index,
typename U>
52 [[nodiscard]] constexpr
auto& getUnionMember(U& u) noexcept {
53 return getUnionMemberImpl(get_n_member_pointers_t<Index, U>{}, u);
56 template <
typename... Ts>
58 UnionStorage() =
default;
60 template <std::size_t Index,
typename... Args>
61 UnionStorage(std::in_place_index_t<Index>, Args&&...) =
delete;
64 template <
typename First,
typename... Rest>
65 union UnionStorage<First, Rest...> {
66 static constexpr std::size_t size = 1 +
sizeof...(Rest);
69 using Tail = UnionStorage<Rest...>;
71 constexpr UnionStorage()
74 template <
typename... Args>
75 constexpr UnionStorage(std::in_place_index_t<0>, Args&&... args)
76 : head(std::forward<Args>(args)...) {}
78 template <std::size_t Index,
typename... Args>
79 constexpr UnionStorage(std::in_place_index_t<Index>, Args&&... args)
80 : tail(std::in_place_index<Index - 1>, std::forward<Args>(args)...) {}
82 constexpr UnionStorage(
const UnionStorage& other, std::size_t other_index) {
83 [&]<std::size_t... Indices>(std::index_sequence<Indices...>) ->
void {
84 (void)(((other_index == Indices) ? (create<Indices>(getUnionMember<Indices>(other)),
true) :
false) || ...);
85 }(std::make_index_sequence<size>{});
88 constexpr UnionStorage(UnionStorage&& other, std::size_t other_index) {
89 [&]<std::size_t... Indices>(std::index_sequence<Indices...>) ->
void {
90 (void)(((other_index == Indices) ? (create<Indices>(std::move(getUnionMember<Indices>(other))),
true) :
false) || ...);
91 }(std::make_index_sequence<size>{});
94 ~UnionStorage() =
default;
95 constexpr ~UnionStorage() requires(!std::is_trivially_destructible_v<Head> || !std::is_trivially_destructible_v<Tail>) {}
97 UnionStorage(
const UnionStorage&) =
default;
98 UnionStorage(UnionStorage&&) =
default;
99 UnionStorage& operator=(
const UnionStorage&) =
default;
100 UnionStorage& operator=(UnionStorage&&) =
default;
102 template <std::size_t Index,
typename... Args>
103 constexpr
void create(Args&&... args) {
104 std::construct_at(&getUnionMember<Index>(*
this), std::forward<Args>(args)...);
107 constexpr
void destroy(std::size_t index) noexcept {
108 [&]<std::size_t... Indices>(std::index_sequence<Indices...>) ->
void {
109 (void)(((index == Indices) ? (std::destroy_at(&getUnionMember<Indices>(*
this)),
true) :
false) || ...);
110 }(std::make_index_sequence<size>{});
117 template <
template <
typename...>
typename Template,
typename... TemplateArgs>
118 constexpr
void derivedFromTemplateSpecializationTest(
const Template<TemplateArgs...>&);
120 template <
typename T,
template <
typename...>
typename Template>
121 concept derived_from_template_specialization_of = requires(
const T& t) { derivedFromTemplateSpecializationTest<Template>(t); };
123 template <
typename T, std::size_t Index,
typename... Ts>
124 struct VariantIndexImpl;
126 template <
typename T, std::size_t Index,
typename First,
typename... Rest>
127 struct VariantIndexImpl<T, Index, First, Rest...> : VariantIndexImpl<T, Index + 1, Rest...> {};
129 template <
typename T, std::size_t Index,
typename... Rest>
130 struct VariantIndexImpl<T, Index, T, Rest...> : std::integral_constant<std::size_t, Index> {};
132 template <
typename... Functors>
134 using Functors::operator()...;
137 template <
typename... Functors>
140 template <
typename V>
144 template <
typename... Functors>
145 constexpr decltype(
auto) operator()(Functors&&... functors)
const {
146 return visit(detail::Overloaded{std::forward<Functors>(functors)...}, variant);
153 template <
typename T,
typename V>
154 struct variant_has_alternative;
156 template <
typename T,
typename First,
typename... Rest>
157 struct variant_has_alternative<T, Variant<First, Rest...>> : variant_has_alternative<T, Variant<Rest...>> {};
159 template <
typename T>
160 struct variant_has_alternative<T, Variant<>> : std::false_type {};
162 template <
typename T,
typename... Rest>
163 struct variant_has_alternative<T, Variant<T, Rest...>> : std::true_type {};
172 template <
typename T,
typename V>
176 template <
typename T,
typename V>
177 struct variant_index;
179 template <
typename T,
typename... Ts>
180 struct variant_index<T,
Variant<Ts...>> : detail::VariantIndexImpl<T, 0, Ts...> {};
189 template <
typename T,
typename V>
193 template <std::
size_t Index,
typename V>
194 struct variant_alternative;
196 template <std::size_t Index,
typename First,
typename... Rest>
197 struct variant_alternative<Index,
Variant<First, Rest...>> : variant_alternative<Index - 1, Variant<Rest...>> {};
199 template <
typename T,
typename... Rest>
200 struct variant_alternative<0, Variant<T, Rest...>> {
211 template <std::
size_t Index,
typename V>
215 template <
typename V>
218 template <
typename... Ts>
219 struct variant_size<
Variant<Ts...>> : std::integral_constant<std::size_t, sizeof...(Ts)> {};
227 template <
typename V>
259 return std::strong_ordering::equal;
285 [[nodiscard]] const
char*
what() const noexcept
override {
286 return "Bad variant access.";
290 template <
typename... Ts>
293 static constexpr
bool HAS_DEFAULT_CONSTRUCTOR = std::is_default_constructible_v<variant_alternative_t<0, Variant>>;
294 static constexpr
bool HAS_COPY_CONSTRUCTOR = (std::is_copy_constructible_v<Ts> && ...);
295 static constexpr
bool HAS_MOVE_CONSTRUCTOR = (std::is_move_constructible_v<Ts> && ...);
296 static constexpr
bool HAS_COPY_ASSIGNMENT = ((std::is_copy_constructible_v<Ts> && std::is_copy_assignable_v<Ts>)&&...);
297 static constexpr
bool HAS_MOVE_ASSIGNMENT = ((std::is_move_constructible_v<Ts> && std::is_move_assignable_v<Ts>)&&...);
298 static constexpr
bool HAS_TRIVIAL_COPY_CONSTRUCTOR = (std::is_trivially_copy_constructible_v<Ts> && ...);
299 static constexpr
bool HAS_TRIVIAL_MOVE_CONSTRUCTOR = (std::is_trivially_move_constructible_v<Ts> && ...);
300 static constexpr
bool HAS_TRIVIAL_COPY_ASSIGNMENT =
301 ((std::is_trivially_copy_constructible_v<Ts> && std::is_trivially_copy_assignable_v<Ts> && std::is_trivially_destructible_v<Ts>)&&...);
302 static constexpr
bool HAS_TRIVIAL_MOVE_ASSIGNMENT =
303 ((std::is_trivially_move_constructible_v<Ts> && std::is_trivially_move_assignable_v<Ts> && std::is_trivially_destructible_v<Ts>)&&...);
304 static constexpr
bool HAS_TRIVIAL_DESTRUCTOR = (std::is_trivially_destructible_v<Ts> && ...);
306 template <
typename T>
307 struct SelectAlternativeTypeOverload {
308 template <
typename U>
309 T operator()(T, U&& u) requires(requires { T{std::forward<U>(u)}; });
312 struct SelectAlternativeTypeOverloadSet : SelectAlternativeTypeOverload<Ts>... {
313 using SelectAlternativeTypeOverload<Ts>::operator()...;
316 template <
typename U>
317 static constexpr
auto F(U&& u) -> decltype(SelectAlternativeTypeOverloadSet{}(std::forward<U>(u), std::forward<U>(u)));
329 std::conditional_t<
sizeof...(Ts) < 255ull, std::uint8_t,
330 std::conditional_t<
sizeof...(Ts) < 65535ull, std::uint16_t,
331 std::conditional_t<
sizeof...(Ts) < 4294967295ull, std::uint32_t,
348 :
Variant(std::in_place_index<0>) {}
362 template <
typename U>
363 constexpr
Variant(U&& value) noexcept(std::is_nothrow_constructible_v<decltype(F(std::forward<U>(value)))>)
365 std::is_constructible_v<decltype(F(std::forward<U>(value))), U>)
379 template <
typename T,
typename... Args>
380 constexpr
explicit Variant(std::in_place_type_t<T> type, Args&&... args) requires(variant_has_alternative_v<T, Variant> && std::is_constructible_v<T, Args...>)
400 template <
typename T,
typename U,
typename... Args>
401 constexpr
explicit Variant(std::in_place_type_t<T> type, std::initializer_list<U>
ilist, Args&&... args)
402 requires(variant_has_alternative_v<T, Variant> && std::is_constructible_v<T, std::initializer_list<U>&, Args...>)
418 template <std::size_t Index,
typename... Args>
419 constexpr
explicit Variant(std::in_place_index_t<Index>
index, Args&&... args)
421 : storage(
index, std::forward<Args>(args)...)
422 , activeTypeIndex(Index) {}
439 template <std::size_t Index,
typename U,
typename... Args>
440 constexpr
explicit Variant(std::in_place_index_t<Index>
index, std::initializer_list<U>
ilist, Args&&... args)
442 : storage(
index,
ilist, std::forward<Args>(args)...)
443 , activeTypeIndex(Index) {}
451 constexpr
~Variant() requires(HAS_TRIVIAL_DESTRUCTOR) = default;
454 constexpr
Variant(const
Variant& other) requires(!HAS_COPY_CONSTRUCTOR) = delete;
457 constexpr
Variant(const
Variant& other) requires(HAS_COPY_CONSTRUCTOR && HAS_TRIVIAL_COPY_CONSTRUCTOR) = default;
460 constexpr
Variant(const
Variant& other) requires(HAS_COPY_CONSTRUCTOR && !HAS_TRIVIAL_COPY_CONSTRUCTOR)
461 : storage(other.storage, other.activeTypeIndex)
462 , activeTypeIndex(other.activeTypeIndex) {}
465 constexpr
Variant(
Variant&& other) noexcept requires(HAS_MOVE_CONSTRUCTOR && HAS_TRIVIAL_MOVE_CONSTRUCTOR) =
default;
469 (std::is_nothrow_move_constructible_v<Ts> && ...))
470 requires(HAS_MOVE_CONSTRUCTOR && !HAS_TRIVIAL_MOVE_CONSTRUCTOR)
471 : storage(std::move(other.storage), other.activeTypeIndex)
472 , activeTypeIndex(other.activeTypeIndex) {}
492 constexpr
Variant&
operator=(
Variant&& other) noexcept requires(HAS_MOVE_ASSIGNMENT && HAS_TRIVIAL_MOVE_ASSIGNMENT) =
default;
501 ((std::is_nothrow_move_constructible_v<Ts> &&
502 std::is_nothrow_move_assignable_v<Ts>)&&...)) requires(HAS_MOVE_ASSIGNMENT && !HAS_TRIVIAL_MOVE_ASSIGNMENT) {
503 if (activeTypeIndex == other.activeTypeIndex) {
504 [&]<std::size_t... Indices>(std::index_sequence<Indices...>) ->
void {
505 (void)(((is<Indices>()) ? ((as<Indices>() =
std::move(other.template as<Indices>())),
true) :
false) || ...);
506 }(std::make_index_sequence<
sizeof...(Ts)>{});
507 }
else if (other.activeTypeIndex ==
npos) {
511 [&]<std::size_t... Indices>(std::index_sequence<Indices...>) ->
void {
512 (void)(((other.template is<Indices>()) ? ((storage.template create<Indices>(
std::move(other.template as<Indices>()))),
true) :
false) || ...);
513 }(std::make_index_sequence<
sizeof...(Ts)>{});
514 activeTypeIndex = other.activeTypeIndex;
534 template <
typename U>
536 std::is_nothrow_assignable_v<decltype(F(std::forward<U>(value)))&, U>&& std::is_nothrow_constructible_v<decltype(F(std::forward<U>(value))), U>)
538 std::is_assignable_v<decltype(F(std::forward<U>(value))), U>) {
539 using T = decltype(F(std::forward<U>(value)));
541 as<T>() = std::forward<U>(value);
543 if constexpr (std::is_nothrow_constructible_v<T, U> || !std::is_nothrow_move_constructible_v<T>) {
544 emplace<T>(std::forward<U>(value));
546 emplace<T>(T(std::forward<U>(value)));
566 template <
typename T,
typename... Args>
567 constexpr T&
emplace(Args&&... args) requires(variant_has_alternative_v<T, Variant> && std::is_constructible_v<T, Args...>) {
568 return emplace<variant_index_v<T, Variant>>(std::forward<Args>(args)...);
589 template <
typename T,
typename U,
typename... Args>
591 requires(variant_has_alternative_v<T, Variant> && std::is_constructible_v<T, std::initializer_list<U>&, Args...>) {
592 return emplace<variant_index_v<T, Variant>>(
ilist, std::forward<Args>(args)...);
609 template <std::size_t Index,
typename... Args>
611 static_assert(Index <
sizeof...(Ts));
613 storage.template create<Index>(std::forward<Args>(args)...);
614 activeTypeIndex = Index;
636 template <std::size_t Index,
typename U,
typename... Args>
639 static_assert(Index <
sizeof...(Ts));
641 storage.template create<Index>(
ilist, std::forward<Args>(args)...);
642 activeTypeIndex = Index;
659 ((std::is_nothrow_move_constructible_v<Ts> && std::is_nothrow_swappable_v<Ts>)&&...)) {
660 if (activeTypeIndex == other.activeTypeIndex) {
662 [&]<std::size_t... Indices>(std::index_sequence<Indices...>) ->
void {
663 (void)(((is<Indices>()) ? ((
swap(as<Indices>(), other.template as<Indices>())),
true) :
false) || ...);
664 }(std::make_index_sequence<
sizeof...(Ts)>{});
697 return activeTypeIndex;
707 return activeTypeIndex ==
npos;
719 template <
typename T>
721 return activeTypeIndex == variant_index_v<T, Variant>;
734 template <std::
size_t Index>
735 [[nodiscard]] constexpr
bool is() const noexcept {
736 return activeTypeIndex == Index;
763 template <
typename T>
764 [[nodiscard]] constexpr T&
as() & noexcept requires(variant_has_alternative_v<T, Variant>) {
766 return as<variant_index_v<T, Variant>>();
793 template <
typename T>
796 return as<variant_index_v<T, Variant>>();
823 template <
typename T>
824 [[nodiscard]] constexpr T&&
as() && noexcept requires(variant_has_alternative_v<T, Variant>) {
853 template <
typename T>
884 template <std::
size_t Index>
887 return detail::getUnionMember<Index>(storage);
915 template <std::
size_t Index>
918 return detail::getUnionMember<Index>(storage);
946 template <std::
size_t Index>
949 return std::move(detail::getUnionMember<Index>(storage));
977 template <std::
size_t Index>
980 return std::move(detail::getUnionMember<Index>(storage));
997 template <
typename T>
998 [[nodiscard]] constexpr T&
get() &
999 requires(variant_has_alternative_v<T, Variant>) {
1020 template <
typename T>
1042 template <
typename T>
1043 [[nodiscard]] constexpr T&&
get() &&
1044 requires(variant_has_alternative_v<T, Variant>) {
1065 template <
typename T>
1088 template <std::
size_t Index>
1111 template <std::
size_t Index>
1134 template <std::
size_t Index>
1157 template <std::
size_t Index>
1178 template <
typename T>
1180 return (is<T>()) ? &as<T>() :
nullptr;
1197 template <
typename T>
1199 return (is<T>()) ? &as<T>() :
nullptr;
1215 template <std::
size_t Index>
1217 return (is<Index>()) ? &as<Index>() :
nullptr;
1234 template <std::
size_t Index>
1236 return (is<Index>()) ? &as<Index>() :
nullptr;
1256 template <
typename Visitor,
typename V>
1257 static constexpr decltype(
auto)
visit(Visitor&& visitor, V&& variant) {
1258 constexpr
bool IS_ALL_LVALUE_REFERENCE =
1259 (std::is_lvalue_reference_v<decltype(std::invoke(std::forward<Visitor>(visitor), std::forward<V>(variant).template as<Ts>()))> && ...);
1260 constexpr
bool IS_ANY_CONST =
1261 (std::is_const_v<std::remove_reference_t<decltype(std::invoke(std::forward<Visitor>(visitor), std::forward<V>(variant).template as<Ts>()))>> || ...);
1262 using R = std::common_type_t<decltype(std::invoke(std::forward<Visitor>(visitor), std::forward<V>(variant).template as<Ts>()))...>;
1263 if constexpr (std::is_void_v<R>) {
1264 [&]<std::size_t... Indices>(std::index_sequence<Indices...>) ->
void {
1265 if (!(((variant.template is<Indices>()) ? (std::invoke(std::forward<Visitor>(visitor), std::forward<V>(variant).template as<Indices>()),
true) :
false) || ...)) {
1268 }(std::make_index_sequence<
sizeof...(Ts)>{});
1269 }
else if constexpr (IS_ALL_LVALUE_REFERENCE) {
1270 std::conditional_t<IS_ANY_CONST, const R*, R*> result =
nullptr;
1271 [&]<std::size_t... Indices>(std::index_sequence<Indices...>) ->
void {
1272 if (!(((variant.template is<Indices>()) ? ((result = &std::invoke(std::forward<Visitor>(visitor), std::forward<V>(variant).template as<Indices>())),
true)
1277 }(std::make_index_sequence<
sizeof...(Ts)>{});
1280 std::optional<R> result{};
1281 [&]<std::size_t... Indices>(std::index_sequence<Indices...>) ->
void {
1282 if (!(((variant.template is<Indices>()) ? (result.emplace(std::invoke(std::forward<Visitor>(visitor), std::forward<V>(variant).template as<Indices>())),
true)
1287 }(std::make_index_sequence<
sizeof...(Ts)>{});
1293 void destroy() noexcept {
1294 if constexpr (!HAS_TRIVIAL_DESTRUCTOR) {
1295 storage.destroy(activeTypeIndex);
1297 activeTypeIndex =
npos;
1300 detail::UnionStorage<Ts..., Monostate> storage;
1321 template <
typename Visitor, detail::derived_from_
template_specialization_of<Variant> V>
1322 constexpr decltype(
auto)
visit(Visitor&& visitor, V&& variant) {
1339 template <
typename T,
typename... Ts>
1341 return variant.template is<T>();
1357 template <std::size_t Index,
typename... Ts>
1358 [[nodiscard]] constexpr
bool holds_alternative(
const Variant<Ts...>& variant) noexcept {
1359 return variant.template is<Index>();
1377 template <
typename T,
typename... Ts>
1379 return variant.template get<T>();
1397 template <
typename T,
typename... Ts>
1399 return variant.template get<T>();
1417 template <std::size_t Index,
typename... Ts>
1419 return variant.template get<Index>();
1437 template <std::size_t Index,
typename... Ts>
1439 return variant.template get<Index>();
1457 template <
typename T,
typename... Ts>
1460 return variant->template get_if<T>();
1479 template <
typename T,
typename... Ts>
1482 return variant->template get_if<T>();
1500 template <std::size_t Index,
typename... Ts>
1503 return variant->template get_if<Index>();
1521 template <std::size_t Index,
typename... Ts>
1524 return variant->template get_if<Index>();
1539 template <
typename... Ts>
1547 return visit([&]<
typename T>(
const T& value) ->
bool {
return value == b.template as<T>(); }, a);
1562 template <
typename... Ts>
1570 return visit([&]<
typename T>(
const T& value) ->
bool {
return value != b.template as<T>(); }, a);
1585 template <
typename... Ts>
1599 return visit([&]<
typename T>(
const T& value) ->
bool {
return value < b.template as<T>(); }, a);
1614 template <
typename... Ts>
1628 return visit([&]<
typename T>(
const T& value) ->
bool {
return value <= b.template as<T>(); }, a);
1643 template <
typename... Ts>
1657 return visit([&]<
typename T>(
const T& value) ->
bool {
return value > b.template as<T>(); }, a);
1672 template <
typename... Ts>
1686 return visit([&]<
typename T>(
const T& value) ->
bool {
return value >= b.template as<T>(); }, a);
1701 template <
typename... Ts>
1702 [[nodiscard]] constexpr std::common_comparison_category_t<std::compare_three_way_result_t<Ts>...>
operator<=>(
const Variant<Ts...>& a,
const Variant<Ts...>& b) {
1703 if (a.valueless_by_exception() && b.valueless_by_exception()) {
1704 return std::strong_ordering::equal;
1706 if (a.valueless_by_exception()) {
1707 return std::strong_ordering::less;
1709 if (b.valueless_by_exception()) {
1710 return std::strong_ordering::greater;
1712 if (a.index() != b.index()) {
1713 return a.index() <=> b.index();
1715 return visit([&]<
typename T>(
const T& value) -> std::common_comparison_category_t<std::compare_three_way_result_t<Ts>...> {
return value <=> b.template as<T>(); }, a);
1736 template <
typename V>
1737 [[nodiscard]] constexpr detail::Matcher<V>
match(V&& variant) {
1738 return detail::Matcher<V>{std::forward<V>(variant)};
1746 template <
typename... Ts>
1747 class std::hash<
donut::Variant<Ts...>> {
1750 return visit(hasher, variant);
1754 template <
typename T>
1757 [[nodiscard]] std::size_t operator()(
const T& value)
const {
1758 return hasher(value);
1762 [[no_unique_address]] std::hash<T> hasher{};
1765 class HashVisitor :
public Hash<Ts>... {
1767 using Hash<Ts>::operator()...;
1770 [[no_unique_address]] HashVisitor hasher{};
Tagged union value type that holds a value of one of the given types.
Definition: Variant.hpp:291
constexpr Variant(std::in_place_index_t< Index > index, Args &&... args) requires(Index< sizeof...(Ts) &&std
Construct a variant alternative in-place given its index.
Definition: Variant.hpp:419
constexpr index_type index() const noexcept
Get the alternative index of the currently active value held by the variant.
Definition: Variant.hpp:696
constexpr variant_alternative_t< Index, Variant > & emplace(std::initializer_list< U > ilist, Args &&... args) requires(std
Construct an alternative given its index, with an initializer list as the first constructor argument,...
Definition: Variant.hpp:637
constexpr Variant(std::in_place_type_t< T > type, std::initializer_list< U > ilist, Args &&... args) requires(variant_has_alternative_v< T
Construct a variant alternative in-place given its type, with an initializer list as the first constr...
constexpr T & emplace(Args &&... args) requires(variant_has_alternative_v< T
Construct an alternative given its type, destroying the old value.
constexpr ~Variant()
Destructor.
Definition: Variant.hpp:446
constexpr Variant(Variant &&other) noexcept((std::is_nothrow_move_constructible_v< Ts > &&...)) requires(HAS_MOVE_CONSTRUCTOR &&!HAS_TRIVIAL_MOVE_CONSTRUCTOR)
Move constructor.
Definition: Variant.hpp:468
constexpr variant_alternative_t< Index, Variant > && get() &&
Access the underlying value with the given index.
Definition: Variant.hpp:1135
constexpr T & emplace(std::initializer_list< U > ilist, Args &&... args) requires(variant_has_alternative_v< T
Construct an alternative given its type, with an initializer list as the first constructor argument,...
constexpr const variant_alternative_t< Index, Variant > && as() const &&noexcept
Access the underlying value with the given index without a safety check.
Definition: Variant.hpp:978
constexpr Variant & operator=(Variant &&other) noexcept requires(HAS_MOVE_ASSIGNMENT &&HAS_TRIVIAL_MOVE_ASSIGNMENT)=default
Trivial move assignment.
constexpr const T && as() const &&noexcept requires(variant_has_alternative_v< T
Access the underlying value with the given type without a safety check.
constexpr T && as() &&noexcept requires(variant_has_alternative_v< T
Access the underlying value with the given type without a safety check.
constexpr Variant ilist
Definition: Variant.hpp:403
constexpr Variant(Variant &&other) noexcept requires(HAS_MOVE_CONSTRUCTOR &&HAS_TRIVIAL_MOVE_CONSTRUCTOR)=default
Trivial move constructor.
constexpr void swap(Variant &other) noexcept(((std::is_nothrow_move_constructible_v< Ts > &&std::is_nothrow_swappable_v< Ts >)&&...))
Swap this variant's value with that of another.
Definition: Variant.hpp:658
constexpr Variant(std::in_place_type_t< T > type, Args &&... args) requires(variant_has_alternative_v< T
Construct a variant alternative in-place given its type.
constexpr const variant_alternative_t< Index, Variant > & as() const &noexcept
Access the underlying value with the given index without a safety check.
Definition: Variant.hpp:916
constexpr Variant & operator=(const Variant &other) requires(HAS_COPY_ASSIGNMENT &&!HAS_TRIVIAL_COPY_ASSIGNMENT)
Copy assignment.
Definition: Variant.hpp:486
constexpr T && get() &&requires(variant_has_alternative_v< T
Access the underlying value with the given type.
constexpr const T & as() const &noexcept requires(variant_has_alternative_v< T
Access the underlying value with the given type without a safety check.
constexpr Variant & operator=(const Variant &other) requires(HAS_COPY_ASSIGNMENT &&HAS_TRIVIAL_COPY_ASSIGNMENT)=default
Trivial copy assignment.
constexpr bool is() const noexcept
Check if the variant currently holds the alternative with the given index.
Definition: Variant.hpp:735
constexpr bool is() const noexcept requires(variant_has_alternative_v< T
Check if the variant currently holds the alternative with the given type.
constexpr Variant & operator=(Variant &&other) noexcept(((std::is_nothrow_move_constructible_v< Ts > &&//NOLINT(performance-noexcept-move-constructor, cppcoreguidelines-noexcept-move-operations) std::is_nothrow_move_assignable_v< Ts >)&&...)) requires(HAS_MOVE_ASSIGNMENT &&!HAS_TRIVIAL_MOVE_ASSIGNMENT)
Move assignment.
Definition: Variant.hpp:500
constexpr const variant_alternative_t< Index, Variant > * get_if() const noexcept
Access the underlying value with the given index if it is the currently active alternative.
Definition: Variant.hpp:1235
constexpr variant_alternative_t< Index, Variant > & get() &
Access the underlying value with the given index.
Definition: Variant.hpp:1089
constexpr const T & get() const &requires(variant_has_alternative_v< T
Access the underlying value with the given type.
constexpr Variant & operator=(U &&value) noexcept(std::is_nothrow_assignable_v< decltype(F(std::forward< U >(value)))&, U > &&std::is_nothrow_constructible_v< decltype(F(std::forward< U >(value))), U >) requires(!std
Converting assignment.
Definition: Variant.hpp:535
constexpr const variant_alternative_t< Index, Variant > && get() const &&
Access the underlying value with the given index.
Definition: Variant.hpp:1158
constexpr Variant(std::in_place_index_t< Index > index, std::initializer_list< U > ilist, Args &&... args) requires(Index< sizeof...(Ts) &&std
Construct a variant alternative in-place given its index, with an initializer list as the first const...
Definition: Variant.hpp:440
constexpr T & get() &requires(variant_has_alternative_v< T
Access the underlying value with the given type.
constexpr variant_alternative_t< Index, Variant > && as() &&noexcept
Access the underlying value with the given index without a safety check.
Definition: Variant.hpp:947
std::conditional_t< sizeof...(Ts)< 255ull, std::uint8_t, std::conditional_t< sizeof...(Ts)< 65535ull, std::uint16_t, std::conditional_t< sizeof...(Ts)< 4294967295ull, std::uint32_t, std::uint64_t > >> index_type
Index type used to encode the active alternative type.
Definition: Variant.hpp:332
constexpr variant_alternative_t< Index, Variant > & as() &noexcept
Access the underlying value with the given index without a safety check.
Definition: Variant.hpp:885
constexpr T * get_if() noexcept requires(variant_has_alternative_v< T
Access the underlying value with the given type if it is the currently active alternative.
constexpr friend void swap(Variant &a, Variant &b) noexcept(noexcept(a.swap(b)))
Swap the values of two variants.
Definition: Variant.hpp:685
constexpr T & as() &noexcept requires(variant_has_alternative_v< T
Access the underlying value with the given type without a safety check.
constexpr variant_alternative_t< Index, Variant > * get_if() noexcept
Access the underlying value with the given index if it is the currently active alternative.
Definition: Variant.hpp:1216
constexpr Variant & operator=(const Variant &other) requires(!HAS_COPY_ASSIGNMENT)=delete
Deleted copy assignment.
constexpr bool valueless_by_exception() const noexcept
Check if the variant is in the valueless by exception state.
Definition: Variant.hpp:706
constexpr Variant(U &&value) noexcept(std::is_nothrow_constructible_v< decltype(F(std::forward< U >(value)))>) requires(!std
Converting constructor.
Definition: Variant.hpp:363
static constexpr index_type npos
Invalid alternative index, representing the valueless by exception state.
Definition: Variant.hpp:338
return std::move(as< variant_index_v< T, Variant >>())
static constexpr decltype(auto) visit(Visitor &&visitor, V &&variant)
Call a visitor functor with the currently active underlying value of a variant.
Definition: Variant.hpp:1257
constexpr ~Variant() requires(HAS_TRIVIAL_DESTRUCTOR)=default
Trivial destructor.
constexpr variant_alternative_t< Index, Variant > & emplace(Args &&... args) requires(std
Construct an alternative given its index, destroying the old value.
Definition: Variant.hpp:610
constexpr const T * get_if() const noexcept requires(variant_has_alternative_v< T
Access the underlying value with the given type if it is the currently active alternative.
constexpr const variant_alternative_t< Index, Variant > & get() const &
Access the underlying value with the given index.
Definition: Variant.hpp:1112
constexpr Variant() noexcept(std::is_nothrow_default_constructible_v< variant_alternative_t< 0, Variant >>) requires(HAS_DEFAULT_CONSTRUCTOR)
Default-construct a variant with the first variant alternative, if it is default-constructible.
Definition: Variant.hpp:347
constexpr const T && get() const &&requires(variant_has_alternative_v< T
Access the underlying value with the given type.
std::size_t operator()(const donut::Monostate &) const
Definition: Variant.hpp:270
std::size_t operator()(const donut::Variant< Ts... > &variant) const
Definition: Variant.hpp:1749
void swap(Object &a, Object &b) noexcept
Definition: json.hpp:3980
Definition: Application.hpp:9
constexpr decltype(auto) visit(Visitor &&visitor, V &&variant)
Call a visitor functor with the currently active underlying value of a variant.
Definition: Variant.hpp:1322
constexpr bool operator!=(const Variant< Ts... > &a, const Variant< Ts... > &b)
Compare two variants for inequality.
Definition: Variant.hpp:1563
Overloaded(Functors...) -> Overloaded< Functors... >
constexpr T * get_if(Variant< Ts... > *variant) noexcept
Access the underlying value with the given type of a variant if it is the currently active alternativ...
Definition: Variant.hpp:1458
constexpr bool holds_alternative(const Variant< Ts... > &variant) noexcept
Check if a variant currently holds the alternative with the given type.
Definition: Variant.hpp:1340
constexpr bool operator==(Monostate, Monostate) noexcept
Compare two monostates for equality.
Definition: Variant.hpp:246
constexpr std::size_t variant_index_v
Get the index of the variant alternative with a given type in a variant type.
Definition: Variant.hpp:190
constexpr bool operator<=(const Variant< Ts... > &a, const Variant< Ts... > &b)
Check if a variant is less than or equal to another variant.
Definition: Variant.hpp:1615
constexpr std::size_t variant_size_v
Get the number of alternative types of a variant type.
Definition: Variant.hpp:228
constexpr bool operator>=(const Variant< Ts... > &a, const Variant< Ts... > &b)
Check if a variant is greater than or equal to another variant.
Definition: Variant.hpp:1673
constexpr bool variant_has_alternative_v
Check if a variant type has a given type as one of its possible alternatives.
Definition: Variant.hpp:173
constexpr T & get(Variant< Ts... > &variant)
Access the underlying value with the given type of a variant.
Definition: Variant.hpp:1378
constexpr bool operator<(const Variant< Ts... > &a, const Variant< Ts... > &b)
Check if a variant is less than another variant.
Definition: Variant.hpp:1586
constexpr bool operator>(const Variant< Ts... > &a, const Variant< Ts... > &b)
Check if a variant is greater than another variant.
Definition: Variant.hpp:1644
constexpr detail::Matcher< V > match(V &&variant)
Choose a function overload to execute based on the active alternative of a variant.
Definition: Variant.hpp:1737
typename variant_alternative< Index, V >::type variant_alternative_t
Get the type of the variant alternative with a given index in a variant type.
Definition: Variant.hpp:212
constexpr std::strong_ordering operator<=>(Monostate, Monostate) noexcept
Compare two monostates.
Definition: Variant.hpp:258
Exception type that is thrown on an attempt to erroneously access an inactive alternative of a Varian...
Definition: Variant.hpp:282
BadVariantAccess() noexcept=default
const char * what() const noexcept override
Definition: Variant.hpp:285
Unit type for representing an empty alternative in Variant.
Definition: Variant.hpp:236