5#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_VARIANT_VARIANT_HPP_
6#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_VARIANT_VARIANT_HPP_
15#include "arene/base/array/array.hpp"
16#include "arene/base/byte/byte.hpp"
17#include "arene/base/compare/operators.hpp"
18#include "arene/base/compiler_support/diagnostics.hpp"
19#include "arene/base/compiler_support/platform_queries.hpp"
20#include "arene/base/compiler_support/preprocessor.hpp"
21#include "arene/base/constraints/constraints.hpp"
22#include "arene/base/detail/exceptions.hpp"
23#include "arene/base/memory/construct_at.hpp"
24#include "arene/base/memory/destroy_at.hpp"
25#include "arene/base/stdlib_choice/add_pointer.hpp"
26#include "arene/base/stdlib_choice/addressof.hpp"
27#include "arene/base/stdlib_choice/cstddef.hpp"
28#include "arene/base/stdlib_choice/decay.hpp"
29#include "arene/base/stdlib_choice/declval.hpp"
30#include "arene/base/stdlib_choice/enable_if.hpp"
31#include "arene/base/stdlib_choice/equal_to.hpp"
32#include "arene/base/stdlib_choice/forward.hpp"
33#include "arene/base/stdlib_choice/ignore.hpp"
34#include "arene/base/stdlib_choice/initializer_list.hpp"
35#include "arene/base/stdlib_choice/integral_constant.hpp"
36#include "arene/base/stdlib_choice/is_constructible.hpp"
37#include "arene/base/stdlib_choice/is_copy_assignable.hpp"
38#include "arene/base/stdlib_choice/is_copy_constructible.hpp"
39#include "arene/base/stdlib_choice/is_default_constructible.hpp"
40#include "arene/base/stdlib_choice/is_move_assignable.hpp"
41#include "arene/base/stdlib_choice/is_move_constructible.hpp"
42#include "arene/base/stdlib_choice/is_reference.hpp"
43#include "arene/base/stdlib_choice/is_same.hpp"
44#include "arene/base/stdlib_choice/is_void.hpp"
45#include "arene/base/stdlib_choice/less.hpp"
46#include "arene/base/stdlib_choice/max_initializer_list_overload.hpp"
47#include "arene/base/type_traits/conditional.hpp"
49#include "arene/base/stdlib_choice/move.hpp"
50#include "arene/base/stdlib_choice/remove_reference.hpp"
51#include "arene/base/type_list/at.hpp"
52#include "arene/base/type_list/type_list.hpp"
53#include "arene/base/type_manipulation/non_constructible_dummy.hpp"
54#include "arene/base/type_traits/all_of.hpp"
55#include "arene/base/type_traits/index_of.hpp"
56#include "arene/base/type_traits/void_t.hpp"
57#include "arene/base/utility/forward_like.hpp"
58#include "arene/base/variant/traits.hpp"
60#if ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED)
61#include "arene/base/variant/detail/bad_variant_access_exceptions_enabled.hpp"
63#include "arene/base/variant/detail/bad_variant_access_exceptions_disabled.hpp"
83template <
typename... Ts>
86namespace variant_detail {
93template <
typename... Ts>
94class variant_util_impl;
103inline constexpr void copy_construct_object(
bool selected,
void const* source,
void* dest)
noexcept(
104 std::is_copy_constructible<T>::value
106 static_assert(std::is_copy_constructible<T>::value,
"Type must be copyable");
108 construct_at(
static_cast<T*>(dest), *
static_cast<T
const*>(source));
120inline constexpr void copy_assign_object(
bool selected,
void const* source,
void* dest)
noexcept(
121 std::is_nothrow_copy_assignable<T>::value
123 static_assert(std::is_copy_assignable<T>::value,
"Type must be copy-assignable");
125 *
static_cast<T*>(dest) = *
static_cast<T
const*>(source);
137inline constexpr void move_construct_object(
bool selected,
void* source,
void* dest)
noexcept(
138 std::is_move_constructible<T>::value
140 static_assert(std::is_move_constructible<T>::value,
"Type must be movable");
142 construct_at(
static_cast<T*>(dest),
static_cast<std::remove_reference_t<T>&&>(*
static_cast<T*>(source)));
154inline constexpr void move_assign_object(
bool selected,
void* source,
void* dest)
noexcept(
155 std::is_move_assignable<T>::value
157 static_assert(std::is_move_assignable<T>::value,
"Type must be copy-assignable");
159 *
static_cast<T*>(dest) =
static_cast<std::remove_reference_t<T>&&>(*
static_cast<T*>(source));
170inline constexpr void destroy_object(
bool selected,
void* data)
noexcept {
172 destroy_at(
static_cast<T*>(data));
185inline constexpr auto check_object_equality(
bool selected,
void const* lhs,
void const* rhs)
noexcept ->
bool {
190 return std::equal_to<T>{}(*
static_cast<T
const*>(lhs), *
static_cast<T
const*>(rhs));
202inline constexpr auto check_object_less_than(
bool selected,
void const* lhs,
void const* rhs)
noexcept ->
bool {
207 return std::less<T>{}(*
static_cast<T
const*>(lhs), *
static_cast<T
const*>(rhs));
214template <
typename T,
typename... Ts>
215class variant_util_impl<T, Ts...> {
223 static constexpr void
224 copy(std::size_t current_idx, std::size_t requested_idx,
void const* source,
void* dest)
noexcept(
225 (std::is_nothrow_copy_constructible<T>::value) &&
226 (base::all_of_v<(std::is_nothrow_copy_constructible<Ts>::value)...>)
228 copy_construct_object<T>(current_idx == requested_idx, source, dest);
229 variant_util_impl<Ts...>::copy(current_idx + 1U, requested_idx, source, dest);
237 static constexpr void
238 copy_assign(std::size_t current_idx, std::size_t requested_idx,
void const* source,
void* dest)
noexcept(
239 (std::is_nothrow_copy_assignable<T>::value) && (base::all_of_v<(std::is_nothrow_copy_assignable<Ts>::value)...>)
241 copy_assign_object<T>(current_idx == requested_idx, source, dest);
242 variant_util_impl<Ts...>::copy_assign(current_idx + 1U, requested_idx, source, dest);
251 static constexpr void move(std::size_t current_idx, std::size_t requested_idx,
void* source,
void* dest)
noexcept(
252 (std::is_nothrow_move_constructible<T>::value) &&
253 (base::all_of_v<(std::is_nothrow_move_constructible<Ts>::value)...>)
255 move_construct_object<T>(current_idx == requested_idx, source, dest);
256 variant_util_impl<Ts...>::move(current_idx + 1U, requested_idx, source, dest);
264 static constexpr void
265 move_assign(std::size_t current_idx, std::size_t requested_idx,
void* source,
void* dest)
noexcept(
266 (std::is_nothrow_move_assignable<T>::value) && (base::all_of_v<(std::is_nothrow_move_assignable<Ts>::value)...>)
268 move_assign_object<T>(current_idx == requested_idx, source, dest);
269 variant_util_impl<Ts...>::move_assign(current_idx + 1U, requested_idx, source, dest);
276 static constexpr void destroy(std::size_t current_idx, std::size_t requested_idx,
void* data)
noexcept {
277 destroy_object<T>(current_idx == requested_idx, data);
278 variant_util_impl<Ts...>::destroy(current_idx + 1U, requested_idx, data);
287 static constexpr auto
288 check_equality(std::size_t current_idx, std::size_t requested_idx,
void const* lhs,
void const* rhs)
noexcept
290 return check_object_equality<T>(current_idx == requested_idx, lhs, rhs) ||
291 variant_util_impl<Ts...>::check_equality(current_idx + 1U, requested_idx, lhs, rhs);
301 static constexpr auto
302 check_less_than(std::size_t current_idx, std::size_t requested_idx,
void const* lhs,
void const* rhs)
noexcept
304 return check_object_less_than<T>(current_idx == requested_idx, lhs, rhs) ||
305 variant_util_impl<Ts...>::check_less_than(current_idx + 1U, requested_idx, lhs, rhs);
311class variant_util_impl<> {
319 static constexpr void
320 copy(std::size_t , std::size_t ,
void const* ,
void* )
noexcept {}
326 static constexpr void
327 copy_assign(std::size_t , std::size_t ,
void const* ,
void* )
noexcept {}
332 static constexpr void move(std::size_t , std::size_t ,
void* ,
void* )
noexcept {}
338 static constexpr void
339 move_assign(std::size_t , std::size_t ,
void* ,
void* )
noexcept {}
345 static constexpr void destroy(std::size_t , std::size_t ,
void* )
noexcept {}
355 static constexpr auto check_equality(
356 std::size_t
const current_idx,
357 std::size_t
const requested_idx,
358 void const*
const lhs,
359 void const*
const rhs
361 std::ignore = current_idx;
365 return requested_idx == variant_npos;
373 static constexpr auto check_less_than(
374 std::size_t
const current_idx,
375 std::size_t
const requested_idx,
376 void const*
const lhs,
377 void const*
const rhs
379 std::ignore = current_idx;
380 std::ignore = requested_idx;
393template <
typename... Ts>
401 inline static void copy(
405 )
noexcept(base::all_of_v<std::is_nothrow_copy_constructible<Ts>::value...>) {
406 variant_util_impl<Ts...>::copy(0U, idx, source, dest);
413 inline static void copy_assign(
417 )
noexcept(base::all_of_v<std::is_nothrow_copy_assignable<Ts>::value...>) {
418 variant_util_impl<Ts...>::copy_assign(0U, idx, source, dest);
426 inline static void move(
430 )
noexcept(base::all_of_v<std::is_nothrow_move_constructible<Ts>::value...>) {
431 variant_util_impl<Ts...>::move(0U, idx, source, dest);
438 inline static void move_assign(
442 )
noexcept(base::all_of_v<std::is_nothrow_move_assignable<Ts>::value...>) {
443 variant_util_impl<Ts...>::move_assign(0U, idx, source, dest);
449 inline static void destroy(std::size_t idx,
void* data)
noexcept { variant_util_impl<Ts...>::destroy(0U, idx, data); }
457 inline static auto check_equality(std::size_t idx,
void const* lhs,
void const* rhs)
noexcept ->
bool {
458 return variant_util_impl<Ts...>::check_equality(0U, idx, lhs, rhs);
467 inline static auto check_less_than(std::size_t idx,
void const* lhs,
void const* rhs)
noexcept ->
bool {
468 return variant_util_impl<Ts...>::check_less_than(0U, idx, lhs, rhs);
475template <
class Variant, std::size_t I = 0>
476class convertible_checker;
480template <std::size_t I>
481class convertible_checker<
variant<>, I> {
487 static void run() =
delete;
499template <
class H,
class... Ts, std::size_t I>
500class convertible_checker<
variant<H, Ts...>, I> : convertible_checker<
variant<Ts...>, I + 1> {
502 using convertible_checker<
variant<Ts...>, I + 1>::run;
507 static auto run(H
const&, std::integral_constant<std::size_t, I>) -> std::integral_constant<std::size_t, I>;
513 static auto run(H&&, std::integral_constant<std::size_t, I>) -> std::integral_constant<std::size_t, I>;
520template <
class Variant,
class T,
class =
void>
521class accepted_index {};
526template <
class Variant,
class T>
527class accepted_index<Variant, T, void_t<
decltype(convertible_checker<Variant>::run(std::declval<T>(), {}))>>
528 :
public decltype(convertible_checker<Variant>::run(std::declval<T>(), {})) {};
536template <
typename... Ts>
542 using util_type = variant_detail::variant_util<Ts...>;
552 static_assert(
sizeof...(Ts) > 0,
"Empty variant is not allowed");
557 static constexpr std::size_t num_types{
sizeof...(Ts)};
562 static constexpr std::size_t max_size{
std::
max({
sizeof(
Ts)...})};
567 static constexpr std::size_t max_align{
std::
max({
alignof(
Ts)...})};
695 util_type::move(other.idx_, other.data_.data(), data_.data());
707 variant(dummy_move_ctor_source&& other) =
delete;
780 if (index() != rhs.index()) {
782 util_type::move(rhs.idx_, rhs.data_.data(), data_.data());
785 util_type::move_assign(rhs.idx_, rhs.data_.data(), data_.data());
815 if (lhs.index() != rhs.index()) {
820 return util_type::check_equality(
822 static_cast<
void const*>(lhs.data_.data()),
823 static_cast<
void const*>(rhs.data_.data())
839 if (lhs.index() != rhs.index()) {
840 return (lhs.index() + 1U) < (rhs.index() + 1U);
844 return util_type::check_less_than(
846 static_cast<
void const*>(lhs.data_.data()),
847 static_cast<
void const*>(rhs.data_.data())
868 template <std::size_t I,
typename... Args>
871 using selected_type = nth_type<I>;
875 construct_at(
reinterpret_cast<selected_type*>(data_.data()), std::forward<Args>(args)...);
891 template <std::size_t I,
typename U,
typename... Args>
892 auto emplace(std::initializer_list<U> init, Args&&... args)
noexcept(
896 using selected_type = nth_type<I>;
900 construct_at(
reinterpret_cast<selected_type*>(data_.data()), init, std::forward<Args>(args)...);
913 template <
typename T,
typename... Args>
919 construct_at(
reinterpret_cast<T*>(data_.data()), std::forward<Args>(args)...);
920 idx_ = base::index_of_v<T, Ts...>;
933 template <
typename T,
typename U,
typename... Args>
934 auto emplace(std::initializer_list<U> init, Args&&... args)
noexcept(
941 construct_at(
reinterpret_cast<T*>(data_.data()), init, std::forward<Args>(args)...);
942 idx_ = base::index_of_v<T, Ts...>;
953 template <
typename T>
955 return get<base::index_of_v<T, Ts...>>();
964 template <
typename T>
966 return get<base::index_of_v<T, Ts...>>();
976 template <
typename T>
978 return std::move(get<base::index_of_v<T, Ts...>>());
987 template <
typename T>
990 return std::move(get<base::index_of_v<T, Ts...>>());
1001 template <std::size_t Index>
1003 return get_impl<Index, nth_type<Index>&>(*
this);
1013 template <std::size_t Index>
1015 return get_impl<Index, nth_type<Index>
const&>(*
this);
1025 template <std::size_t Index>
1027 return get_impl<Index, nth_type<Index>&&>(std::move(*
this));
1037 template <std::size_t Index>
1040 return get_impl<Index, nth_type<Index>
const&&>(std::move(*
this));
1066 template <std::size_t Index,
typename AlternativeRefT,
typename Self>
1067 static auto get_impl(Self&& self)
noexcept(!detail::are_exceptions_enabled_v) -> AlternativeRefT {
1068 variant_detail::variant_must_have_value(Index, self.idx_);
1069 ARENE_IGNORE_START();
1071 "-Wstrict-aliasing",
1072 "It's safe to use reinterpret_cast here since the check above ensures that the type of the object "
1073 "currently held by the variant is the same as the type requested."
1075 return ::arene::base::forward_like<Self>(
1077 *
reinterpret_cast<std::remove_reference_t<AlternativeRefT>*>(std::forward<Self>(self).data_.data())
1084 void destroy()
noexcept {
1086 util_type::destroy(idx_, data_.data());
1087 idx_ = variant_npos;
1093 alignas(
max_align) array<byte, max_size> data_{};
1106template <
typename T,
typename... Ts>
1108 static_assert(!std::is_void<T>::value,
"T should not be void");
1109 return var.
template get<T>();
1120template <
typename T,
typename... Ts>
1122 static_assert(!std::is_void<T>::value,
"T should not be void");
1123 return var.
template get<T>();
1134template <
typename T,
typename... Ts>
1136 static_assert(!std::is_void<T>::value,
"T should not be void");
1137 return std::move(var).
template get<T>();
1148template <
typename T,
typename... Ts>
1150 static_assert(!std::is_void<T>::value,
"T should not be void");
1152 return std::move(var).
template get<T>();
1165template <std::size_t I,
typename... Ts>
1166constexpr auto get(
variant<Ts...>& var)
noexcept(!detail::are_exceptions_enabled_v)
1167 -> variant_alternative_t<I, variant<Ts...>>& {
1168 static_assert(I <
sizeof...(Ts),
"The index should be in [0, number of alternatives)");
1169 return var.
template get<I>();
1181template <std::size_t I,
typename... Ts>
1182constexpr auto get(
variant<Ts...>
const& var)
noexcept(!detail::are_exceptions_enabled_v)
1183 -> variant_alternative_t<I, variant<Ts...>>
const& {
1184 static_assert(I <
sizeof...(Ts),
"The index should be in [0, number of alternatives)");
1185 return var.
template get<I>();
1198template <std::size_t I,
typename... Ts>
1199constexpr auto get(
variant<Ts...>&& var)
noexcept(!detail::are_exceptions_enabled_v)
1200 -> variant_alternative_t<I, variant<Ts...>>&& {
1201 static_assert(I <
sizeof...(Ts),
"The index should be in [0, number of alternatives)");
1202 return std::move(var).
template get<I>();
1214template <std::size_t I,
typename... Ts>
1215constexpr auto get(
variant<Ts...>
const&& var)
noexcept(!detail::are_exceptions_enabled_v)
1216 -> variant_alternative_t<I, variant<Ts...>>
const&& {
1217 static_assert(I <
sizeof...(Ts),
"The index should be in [0, number of alternatives)");
1219 return std::move(var).
template get<I>();
1232template <
class T,
class... Ts>
1234 return var.index() == base::index_of_v<T, Ts...>;
1243template <std::size_t I,
typename... Ts>
1246 using type = variant_alternative_t<I, variant<Ts...>>;
1247 static_assert(I <
sizeof...(Ts),
"The index should be in [0, number of alternatives)");
1248 static_assert(!std::is_void<type>::value,
"T should not be void");
1249 if ((ptr !=
nullptr) && (ptr->index() == I)) {
1250 return std::addressof(ptr->
template get<I>());
1260template <std::size_t I,
typename... Ts>
1263 using type = variant_alternative_t<I, variant<Ts...>>;
1264 static_assert(I <
sizeof...(Ts),
"The index should be in [0, number of alternatives)");
1265 static_assert(!std::is_void<type>::value,
"T should not be void");
1266 if ((ptr !=
nullptr) && (ptr->index() == I)) {
1267 return std::addressof(ptr->
template get<I>());
1277template <
typename T,
typename... Ts>
1278inline constexpr auto get_if(
variant<Ts...>* ptr)
noexcept -> std::add_pointer_t<T> {
1279 static_assert(!std::is_void<T>::value,
"T should not be void");
1280 return get_if<base::index_of_v<T, Ts...>>(ptr);
1287template <
typename T,
typename... Ts>
1288inline constexpr auto get_if(
variant<Ts...>
const* ptr)
noexcept -> std::add_pointer_t<T
const> {
1289 static_assert(!std::is_void<T>::value,
"T should not be void");
1290 return get_if<base::index_of_v<T, Ts...>>(ptr);
~variant()
Calls the destructor of the alternative type.
Definition variant.hpp:1052
auto get() const &&noexcept(!detail::are_exceptions_enabled_v) -> T const &&
Get by type.
Definition variant.hpp:988
constexpr auto valueless_by_exception() const noexcept -> bool
Check if the variant is valueless.
Definition variant.hpp:1049
auto get() &&noexcept(!detail::are_exceptions_enabled_v) -> nth_type< Index > &&
Get the object stored in this variant by the index.
Definition variant.hpp:1026
variant() noexcept(std::is_nothrow_default_constructible< T0 >::value)
Default constructor, which initializes the variant to a default constructed instance of its 0'th alte...
Definition variant.hpp:650
auto emplace(Args &&... args) noexcept(std::is_nothrow_constructible< nth_type< I >, Args... >::value) -> nth_type< I > &
Emplaces a value into the variant by index.
Definition variant.hpp:869
auto get() const &&noexcept(!detail::are_exceptions_enabled_v) -> nth_type< Index > const &&
Get the object stored in this variant by the index.
Definition variant.hpp:1038
variant(move_ctor_arg &&other) noexcept(base::all_of_v< std::is_nothrow_move_constructible< Ts >::value... >)
Move Constructor from another variant.
Definition variant.hpp:691
auto get() &&noexcept(!detail::are_exceptions_enabled_v) -> T &&
Get by type.
Definition variant.hpp:977
auto emplace(std::initializer_list< U > init, Args &&... args) noexcept(std::is_nothrow_constructible< T, std::initializer_list< U >, Args... >::value) -> T &
Emplaces a value into the variant by type.
Definition variant.hpp:934
auto get() &noexcept(!detail::are_exceptions_enabled_v) -> T &
Get by type.
Definition variant.hpp:954
auto emplace(Args &&... args) noexcept(std::is_nothrow_constructible< T, Args... >::value) -> T &
Emplaces a value into the variant by type.
Definition variant.hpp:914
friend auto operator<(variant const &lhs, variant const &rhs) noexcept -> bool
Less-than comparison.
Definition variant.hpp:838
auto emplace(std::initializer_list< U > init, Args &&... args) noexcept(std::is_nothrow_constructible< nth_type< I >, std::initializer_list< U >, Args... >::value) -> nth_type< I > &
Emplaces a value into the variant by index.
Definition variant.hpp:892
friend auto operator==(variant const &lhs, variant const &rhs) noexcept -> bool
Equality comparison.
Definition variant.hpp:814
auto get() &noexcept(!detail::are_exceptions_enabled_v) -> nth_type< Index > &
Get the object stored in this variant by the index.
Definition variant.hpp:1002
auto get() const &noexcept(!detail::are_exceptions_enabled_v) -> nth_type< Index > const &
Get the object stored in this variant by the index.
Definition variant.hpp:1014
auto operator=(move_assignment_arg &&rhs) noexcept(base::all_of_v< std::is_nothrow_move_constructible< Ts >::value... > &&base::all_of_v< std::is_nothrow_move_assignable< Ts >::value... >) -> variant &
Move Assignment operator from another variant of the same alternative types.
Definition variant.hpp:776
auto get() const &noexcept(!detail::are_exceptions_enabled_v) -> T const &
Get by type.
Definition variant.hpp:965
auto index() const noexcept -> std::size_t
Get the index of the alternative type that this variant currently holds.
Definition variant.hpp:856
Definition array_exceptions_disabled.cpp:11
constexpr auto get(variant< Ts... > const &&var) noexcept(!detail::are_exceptions_enabled_v) -> T const &&
Get value held by a variant by type.
Definition variant.hpp:1149
constexpr auto get(variant< Ts... > &&var) noexcept(!detail::are_exceptions_enabled_v) -> T &&
Get value held by a variant by type.
Definition variant.hpp:1135
constexpr auto get(variant< Ts... > &var) noexcept(!detail::are_exceptions_enabled_v) -> T &
Get value held by a variant by type.
Definition variant.hpp:1107
constexpr auto get(variant< Ts... > const &var) noexcept(!detail::are_exceptions_enabled_v) -> T const &
Get value held by a variant by type.
Definition variant.hpp:1121
constexpr auto holds_alternative(variant< Ts... > const &var) noexcept -> bool
Check if the variant holds a value of a given alternative type.
Definition variant.hpp:1233
constexpr auto get_if(variant< Ts... > *ptr) noexcept -> std::add_pointer_t< variant_alternative_t< I, variant< Ts... > > >
Attempt to get a pointer to the object held by the variant by index.
Definition variant.hpp:1244
constexpr auto get_if(variant< Ts... > const *ptr) noexcept -> std::add_pointer_t< variant_alternative_t< I, variant< Ts... > > const >
Attempt to get a pointer to the object held by the variant by index.
Definition variant.hpp:1261
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10