16 #ifndef SUMTY_VARIANT_HPP
17 #define SUMTY_VARIANT_HPP
19 #include "sumty/detail/fwd.hpp"
20 #include "sumty/detail/traits.hpp"
21 #include "sumty/detail/utils.hpp"
22 #include "sumty/detail/variant_impl.hpp"
23 #include "sumty/exceptions.hpp"
24 #include "sumty/utils.hpp"
29 #include <initializer_list>
30 #include <type_traits>
38 struct variant_size_helper;
40 template <
typename... T>
41 struct variant_size_helper<variant<T...>> : std::integral_constant<size_t,
sizeof...(T)> {};
43 template <
typename... T>
44 struct variant_size_helper<
const variant<T...>>
45 : std::integral_constant<size_t,
sizeof...(T)> {};
47 template <size_t I,
typename T>
48 struct variant_alternative_helper;
50 template <size_t I,
typename... T>
51 struct variant_alternative_helper<I, variant<T...>> {
52 using type = detail::select_t<I, T...>;
55 template <size_t I,
typename... T>
56 struct variant_alternative_helper<I,
const variant<T...>>
57 : variant_alternative_helper<I, variant<T...>> {};
59 template <size_t IDX,
typename V,
typename U>
61 constexpr decltype(
auto) jump_table_entry(V&& visitor, U&& var) {
62 if constexpr (std::is_void_v<
decltype(std::forward<U>(var)[sumty::index<IDX>])>) {
63 return std::invoke(std::forward<V>(visitor), void_v);
65 return std::invoke(std::forward<V>(visitor),
66 std::forward<U>(var)[sumty::index<IDX>]);
70 template <
typename V,
typename U, size_t... IDX>
71 consteval auto make_jump_table([[maybe_unused]] std::index_sequence<IDX...> seq) {
72 using ret_t =
decltype(jump_table_entry<0>(std::declval<V&&>(), std::declval<U&&>()));
73 return std::array<ret_t (*)(V&&, U&&),
sizeof...(IDX)>{
74 {&jump_table_entry<IDX, V, U>...}};
77 template <
typename V,
typename U,
typename... T>
78 consteval auto make_jump_table()
noexcept {
79 return make_jump_table<V, U>(std::make_index_sequence<
sizeof...(T)>{});
82 template <
typename V,
typename U,
typename... T>
83 static constexpr auto jump_table = make_jump_table<V, U, T...>();
85 template <
typename V,
typename U,
typename... T>
87 constexpr decltype(
auto) visit_impl(V&& visitor, U&& var) {
88 return jump_table<V, U, T...>[var.index()](std::forward<V>(visitor),
89 std::forward<U>(var));
92 template <size_t IDX,
typename V>
93 struct alternative_info {
94 static inline constexpr size_t index = IDX;
95 using type =
typename variant_alternative_helper<IDX, V>::type;
98 template <size_t IDX,
typename V,
typename U>
100 constexpr decltype(
auto) informed_jump_table_entry(V&& visitor, [[maybe_unused]] U&& var) {
101 if constexpr (std::is_void_v<
decltype(std::forward<U>(var)[sumty::index<IDX>])>) {
102 return std::invoke(std::forward<V>(visitor), void_v,
103 alternative_info<IDX, std::remove_cvref_t<U>>{});
105 return std::invoke(std::forward<V>(visitor),
106 std::forward<U>(var)[sumty::index<IDX>],
107 alternative_info<IDX, std::remove_cvref_t<U>>{});
111 template <
typename V,
typename U, size_t... IDX>
112 consteval auto make_informed_jump_table([[maybe_unused]] std::index_sequence<IDX...> seq) {
114 decltype(informed_jump_table_entry<0>(std::declval<V&&>(), std::declval<U&&>()));
115 return std::array<ret_t (*)(V&&, U&&),
sizeof...(IDX)>{
116 {&informed_jump_table_entry<IDX, V, U>...}};
119 template <
typename V,
typename U,
typename... T>
120 consteval auto make_informed_jump_table()
noexcept {
121 return make_informed_jump_table<V, U>(std::make_index_sequence<
sizeof...(T)>{});
124 template <
typename V,
typename U,
typename... T>
125 static constexpr auto informed_jump_table = make_informed_jump_table<V, U, T...>();
127 template <
typename V,
typename U,
typename... T>
129 constexpr decltype(
auto) visit_informed_impl(V&& visitor, U&& var) {
130 return informed_jump_table<V, U, T...>[var.index()](std::forward<V>(visitor),
131 std::forward<U>(var));
207 template <
typename... T>
208 class variant : detail::variant_impl<
void, T...> {
210 [[nodiscard]]
constexpr detail::variant_impl<
void, T...>& data_() &
noexcept {
211 return *
static_cast<detail::variant_impl<
void, T...>*>(
this);
214 [[nodiscard]]
constexpr const detail::variant_impl<
void, T...>& data_()
216 return *
static_cast<
const detail::variant_impl<
void, T...>*>(
this);
219 [[nodiscard]]
constexpr detail::variant_impl<
void, T...>& data_() && {
220 return std::move(*
static_cast<detail::variant_impl<
void, T...>*>(
this));
223 [[nodiscard]]
constexpr const detail::variant_impl<
void, T...>& data_()
const&& {
224 return std::move(*
static_cast<
const detail::variant_impl<
void, T...>*>(
this));
227 template <size_t IDX,
typename U>
228 [[nodiscard]]
constexpr bool holds_alt_impl()
const noexcept {
229 if constexpr (IDX ==
sizeof...(T)) {
231 }
else if constexpr (std::is_same_v<detail::select_t<IDX, T...>, U>) {
235 return holds_alt_impl<IDX + 1, U>();
238 return holds_alt_impl<IDX + 1, U>();
242 template <size_t IDX>
243 struct emplace_construct_t {};
245 template <size_t IDX,
typename U>
246 requires(detail::traits<detail::select_t<IDX, T...>>::
template is_constructible<U>)
247 constexpr explicit variant([[maybe_unused]] emplace_construct_t<IDX> tag, U&& value)
248 : variant(std::in_place_index<IDX>, std::forward<U>(value)) {}
250 template <size_t IDX,
typename U>
251 requires(!detail::traits<detail::select_t<IDX, T...>>::
template is_constructible<U>)
252 constexpr explicit variant([[maybe_unused]] emplace_construct_t<IDX> tag, U&& value)
253 : variant(emplace_construct_t<IDX + 1>{}, std::forward<U>(value)) {}
256 constexpr variant([[maybe_unused]] detail::uninit_t tag)
noexcept
257 : detail::variant_impl<
void, T...>(tag) {}
259 template <size_t I,
typename... Args>
260 constexpr void uninit_emplace(Args&&... args) {
261 data_().
template uninit_emplace<I>(std::forward<Args>(args)...);
264 friend class error_set<T...>;
266 template <
typename,
typename>
296 CONDITIONALLY_NOEXCEPT;
394 template <size_t IDX,
typename... Args>
396 explicit(
sizeof...(
Args) == 0)
401 constexpr variant(std::in_place_index_t<IDX> inplace, Args&&... args)
402 : detail::variant_impl<
void, T...>(inplace, std::forward<Args>(args)...) {
433 template <size_t IDX,
typename U,
typename... Args>
434 constexpr variant(std::in_place_index_t<IDX> inplace,
435 std::initializer_list<U> init,
437 : detail::variant_impl<
void, T...>(inplace, init, std::forward<Args>(args)...) {}
468 template <
typename U,
typename... Args>
471 explicit(
sizeof...(
Args) == 0)
477 : detail::variant_impl<
void, T...>(std::in_place_index<detail::index_of_v<U, T...>>,
478 std::forward<Args>(args)...) {
510 template <
typename U,
typename V,
typename... Args>
515 std::initializer_list<V> init,
517 : detail::variant_impl<
void, T...>(std::in_place_index<detail::index_of_v<U, T...>>,
519 std::forward<Args>(args)...) {
550 template <
typename U>
560 : variant(emplace_construct_t<0>{}, std::forward<U>(value)) {
592 template <
typename U>
599 constexpr variant(std::initializer_list<U> init)
600 : variant(emplace_construct_t<0>{}, init) {
615 CONDITIONALLY_NOEXCEPT;
651 requires(
true && ... &&
698 noexcept((
true && ... &&
702 requires(
true && ... &&
711 template <size_t IDX,
typename U>
712 constexpr void assign_value(U&& value) {
713 if constexpr (detail::traits<detail::select_t<IDX, T...>>::
template is_assignable<
716 if constexpr (!std::is_void_v<detail::select_t<IDX, T...>>) {
717 data_().
template get<IDX>() = std::forward<U>(value);
720 data_().
template emplace<IDX>(std::forward<U>(value));
723 assign_value<IDX + 1>(std::forward<U>(value));
755 template <
typename U>
761 assign_value<0>(std::forward<U>(rhs));
794 template <
typename U>
798 constexpr variant&
operator=(std::initializer_list<U> rhs) {
799 assign_value<0>(rhs);
825 [[nodiscard]]
constexpr size_t
index()
const noexcept {
return data_().index(); }
849 template <size_t I,
typename... Args>
852 typename detail::traits<detail::select_t<I, T...>>::
reference
857 data_().
template emplace<I>(std::forward<Args>(args)...);
858 return data_().
template get<I>();
884 template <size_t I,
typename U,
typename... Args>
887 typename detail::traits<detail::select_t<I, T...>>::
reference
891 emplace(std::initializer_list<U> ilist, Args&&... args) {
892 data_().
template emplace<I>(ilist, std::forward<Args>(args)...);
893 return data_().
template get<I>();
924 template <
typename U,
typename... Args>
935 data_().
template emplace<detail::index_of_v<U, T...>>(std::forward<Args>(args)...);
936 return data_().
template get<detail::index_of_v<U, T...>>();
968 template <
typename U,
typename V,
typename... Args>
978 emplace(std::initializer_list<V> ilist, Args&&... args) {
979 data_().
template emplace<detail::index_of_v<U, T...>>(ilist,
980 std::forward<Args>(args)...);
981 return data_().
template get<detail::index_of_v<U, T...>>();
1010 [[nodiscard]]
constexpr
1012 typename detail::traits<detail::select_t<I, T...>>::
reference
1017 return data_().
template get<I>();
1046 [[nodiscard]]
constexpr
1053 return data_().
template get<I>();
1082 [[nodiscard]]
constexpr
1089 return std::move(data_()).
template get<I>();
1118 [[nodiscard]]
constexpr
1125 return std::move(data_()).
template get<I>();
1158 template <
typename U>
1162 [[nodiscard]]
constexpr
1169 return this->operator[](sumty::index<detail::index_of_v<U, T...>>);
1202 template <
typename U>
1206 [[nodiscard]]
constexpr
1213 return this->operator[](sumty::index<detail::index_of_v<U, T...>>);
1246 template <
typename U>
1250 [[nodiscard]]
constexpr
1257 return std::move(*
this).operator[](sumty::index<detail::index_of_v<U, T...>>);
1290 template <
typename U>
1294 [[nodiscard]]
constexpr
1301 return std::move(*
this).operator[](sumty::index<detail::index_of_v<U, T...>>);
1328 [[nodiscard]]
constexpr
1330 typename detail::traits<detail::select_t<I, T...>>::
reference
1336 return data_().
template get<I>();
1363 [[nodiscard]]
constexpr
1371 return data_().
template get<I>();
1398 [[nodiscard]]
constexpr
1406 return std::move(data_()).
template get<I>();
1433 [[nodiscard]]
constexpr
1441 return std::move(data_()).
template get<I>();
1473 template <
typename U>
1477 [[nodiscard]]
constexpr
1484 return this->
template get<detail::index_of_v<U, T...>>();
1516 template <
typename U>
1520 [[nodiscard]]
constexpr
1527 return this->
template get<detail::index_of_v<U, T...>>();
1559 template <
typename U>
1563 [[nodiscard]]
constexpr
1570 return std::move(*
this).
template get<detail::index_of_v<U, T...>>();
1602 template <
typename U>
1606 [[nodiscard]]
constexpr
1613 return std::move(*
this).
template get<detail::index_of_v<U, T...>>();
1642 [[nodiscard]]
constexpr
1644 typename detail::traits<detail::select_t<I, T...>>::
pointer
1649 using ptr_t =
typename detail::traits<detail::select_t<I, T...>>::pointer;
1650 if constexpr (!std::is_void_v<ptr_t>) {
1653 ret = &data_().
template get<I>();
1689 [[nodiscard]]
constexpr
1691 typename detail::traits<detail::select_t<I, T...>>::
const_pointer
1696 using ptr_t =
typename detail::traits<detail::select_t<I, T...>>::const_pointer;
1697 if constexpr (!std::is_void_v<ptr_t>) {
1700 ret = &data_().
template get<I>();
1741 template <
typename U>
1745 [[nodiscard]]
constexpr
1747 typename detail::traits<U>::
pointer
1752 return get_if<detail::index_of_v<U, T...>>();
1786 template <
typename U>
1790 [[nodiscard]]
constexpr
1797 return get_if<detail::index_of_v<U, T...>>();
1818 template <
typename U>
1820 if constexpr (detail::is_unique_v<U, T...>) {
1821 return index() == detail::index_of_v<U, T...>;
1823 return holds_alt_impl<0, U>();
1857 template <
typename V>
1860 detail::invoke_result_t<
1862 typename detail::traits<detail::select_t<0, T...>>::
reference>
1867 return detail::visit_impl<V, variant&, T...>(std::forward<V>(visitor), *
this);
1900 template <
typename V>
1903 detail::invoke_result_t<
1910 return detail::visit_impl<V,
const variant&, T...>(std::forward<V>(visitor), *
this);
1943 template <
typename V>
1946 detail::invoke_result_t<
1953 return detail::visit_impl<V, variant&&, T...>(std::forward<V>(visitor),
1987 template <
typename V>
1990 detail::invoke_result_t<
1997 return detail::visit_impl<V,
const variant&&, T...>(std::forward<V>(visitor),
2051 template <
typename V>
2054 detail::invoke_result_t<
2056 typename detail::traits<detail::select_t<0, T...>>::
reference,
2057 detail::alternative_info<0, variant>>
2062 return detail::visit_informed_impl<V, variant&, T...>(std::forward<V>(visitor),
2116 template <
typename V>
2119 detail::invoke_result_t<
2122 detail::alternative_info<0, variant>>
2127 return detail::visit_informed_impl<V,
const variant&, T...>(
2128 std::forward<V>(visitor), *
this);
2181 template <
typename V>
2184 detail::invoke_result_t<
2187 detail::alternative_info<0, variant>>
2192 return detail::visit_informed_impl<V, variant&&, T...>(std::forward<V>(visitor),
2246 template <
typename V>
2249 detail::invoke_result_t<
2252 detail::alternative_info<0, variant>>
2257 return detail::visit_informed_impl<V,
const variant&&, T...>(
2258 std::forward<V>(visitor), std::move(*
this));
2287 constexpr void swap(variant& other)
2294 data_().swap(other.data_());
2318 template <
typename T,
typename... U>
2320 return v.
template holds_alternative<T>();
2349 template <size_t I,
typename... T>
2352 typename detail::traits<detail::select_t<I, T...>>::
reference
2357 return v.
template get<I>();
2386 template <size_t I,
typename... T>
2394 return v.
template get<I>();
2423 template <size_t I,
typename... T>
2431 return std::move(v).
template get<I>();
2460 template <size_t I,
typename... T>
2467 get(
const variant<T...>&& v) {
2468 return std::move(v).
template get<I>();
2503 template <
typename T,
typename... U>
2514 return v.
template get<T>();
2549 template <
typename T,
typename... U>
2560 return v.
template get<T>();
2595 template <
typename T,
typename... U>
2606 return std::move(v).
template get<T>();
2641 template <
typename T,
typename... U>
2651 get(
const variant<U...>&& v) {
2652 return std::move(v).
template get<T>();
2683 template <size_t I,
typename... T>
2686 typename detail::traits<detail::select_t<I, T...>>::
pointer
2691 return v.
template get_if<I>();
2722 template <size_t I,
typename... T>
2725 typename detail::traits<detail::select_t<I, T...>>::
const_pointer
2730 return v.
template get_if<I>();
2767 template <
typename T,
typename... U>
2773 typename detail::traits<T>::
pointer
2778 return v.
template get_if<T>();
2815 template <
typename T,
typename... U>
2826 return v.
template get_if<T>();
2868 template <
typename V>
2871 std::invoke_result_t<V&&>
2876 return std::invoke(std::forward<V>(visitor));
2922 template <
typename V,
typename T0,
typename... TN>
2925 detail::invoke_result_t<V&&,
2926 decltype(get<0>(std::declval<T0&&>())),
2927 decltype(get<0>(std::declval<TN&&>()))...>
2932 visit(V&& visitor, T0&& var0, TN&&... varn) {
2933 if constexpr (
sizeof...(TN) == 0) {
2934 return std::forward<T0>(var0).visit(std::forward<V>(visitor));
2936 return std::forward<T0>(var0).visit(
2937 [visitor = std::forward<V>(visitor),
2938 ... varn = std::forward<TN>(varn)](
auto&&... value)
mutable {
2940 [visitor = std::forward<V>(visitor),
2941 ... value = std::forward<
decltype(value)>(value)](
2942 auto&&... args)
mutable ->
decltype(
auto) {
2943 return std::invoke(std::forward<V>(visitor),
2944 std::forward<
decltype(value)>(value)...,
2945 std::forward<
decltype(args)>(args)...);
2947 std::forward<TN>(varn)...);
2980 template <
typename... T>
2981 constexpr void swap(variant<T...>& a, variant<T...>& b)
2983 noexcept(
noexcept(
a.
swap(
b)))
3005 template <
typename T>
3008 : detail::variant_size_helper<T> {
3027 template <
typename T>
3028 static inline constexpr size_t variant_size_v = variant_size<T>::value;
3049 template <size_t I,
typename T>
3050 struct variant_alternative
3052 : detail::variant_alternative_helper<I, T> {
3073 template <size_t I,
typename T>
3074 using variant_alternative_t =
typename variant_alternative<I, T>::type;
3077 template <
typename... T>
3078 requires((
true && ... && std::is_base_of_v<never, std::remove_cvref_t<T>>))
3079 class variant<T...> :
public never {};