1#ifndef NEFORCE_CORE_UTILITY_VARIANT_HPP__
2#define NEFORCE_CORE_UTILITY_VARIANT_HPP__
16NEFORCE_BEGIN_NAMESPACE__
30template <
typename Variant,
typename T>
33#ifdef NEFORCE_STANDARD_14
38template <
typename Variant,
typename T>
48template <
typename Variant,
size_t Idx>
55template <
typename Variant,
size_t Idx>
67template <
typename... Types>
69 static_assert(
sizeof...(Types) > 0,
"variant must have at least one type");
73 "if variant holds none, it should be in the first place");
85 alignas(_NEFORCE
max({
alignof(Types)...}))
byte_t union_[_NEFORCE
max({
sizeof(Types)...})]{};
87 using destruct_function = void (*)(
byte_t*);
95 static destruct_function* destructors_table()
noexcept {
96 static destruct_function function_ptrs[
sizeof...(Types)] = {
97 [](
byte_t* union_p)
noexcept {
reinterpret_cast<Types*
>(union_p)->~Types(); }...};
101 using copy_construct_function = void (*)(
byte_t*,
byte_t const*);
109 static copy_construct_function* copy_constructors_table()
noexcept {
110 static copy_construct_function function_ptrs[
sizeof...(Types)] = {
111 [](
byte_t* union_dst,
byte_t const* union_src)
noexcept {
112 new (union_dst) Types(*
reinterpret_cast<Types const*
>(union_src));
114 return function_ptrs;
117 using copy_assignment_function = void (*)(
byte_t*,
byte_t const*);
125 static copy_assignment_function* copy_assigment_functions_table()
noexcept {
126 static copy_assignment_function function_ptrs[
sizeof...(Types)] = {
127 [](
byte_t* union_dst,
byte_t const* union_src)
noexcept {
128 *
reinterpret_cast<Types*
>(union_dst) = *
reinterpret_cast<Types const*
>(union_src);
130 return function_ptrs;
133 using move_construct_function = void (*)(
byte_t*,
const byte_t*);
141 static move_construct_function* move_constructors_table()
noexcept {
142 static move_construct_function function_ptrs[
sizeof...(Types)] = {
143 [](
byte_t* union_dst,
const byte_t* union_src)
noexcept {
144 new (union_dst) Types(_NEFORCE
move(*
reinterpret_cast<const Types*
>(union_src)));
146 return function_ptrs;
149 using move_assignment_function = void (*)(
byte_t*,
byte_t*);
157 static move_assignment_function* move_assigment_functions_table()
noexcept {
158 static move_assignment_function function_ptrs[
sizeof...(Types)] = {
160 *
reinterpret_cast<Types*
>(union_dst) = _NEFORCE
move(*
reinterpret_cast<Types*
>(union_src));
162 return function_ptrs;
165 template <
typename Lambda>
176 template <
typename Lambda>
177 static const_visitor_function<Lambda>* const_visitors_table()
noexcept {
178 static const_visitor_function<Lambda> function_ptrs[
sizeof...(Types)] = {
182 return function_ptrs;
185 template <
typename Lambda>
186 using visitor_function =
196 template <
typename Lambda>
197 static visitor_function<Lambda>* visitors_table()
noexcept {
198 static visitor_function<Lambda> function_ptrs[
sizeof...(Types)] = {
202 return function_ptrs;
205 template <
size_t I,
typename... Args,
207 constexpr bool try_construct_impl_aux_aux(Args&&... args) {
213 template <
size_t I,
typename... Args,
215 constexpr bool try_construct_impl_aux_aux(Args&&... args) {
216 return variant::try_construct_impl<I + 1>(_NEFORCE
forward<Args>(args)...);
219 template <
size_t I,
typename... Args,
enable_if_t<(I <
sizeof...(Types)),
int> = 0>
220 constexpr bool try_construct_impl_aux(Args&&... args) {
221 return variant::try_construct_impl_aux_aux<I>(_NEFORCE
forward<Args>(args)...);
224 template <
size_t I,
typename... Args,
enable_if_t<(I >=
sizeof...(Types)),
int> = 0>
225 constexpr bool try_construct_impl_aux(Args&&...) {
229 template <
size_t I,
typename... Args>
230 constexpr bool try_construct_impl(Args&&... args) {
231 return variant::try_construct_impl_aux<I>(_NEFORCE
forward<Args>(args)...);
234 template <
size_t I = 0,
typename... Args>
235 constexpr bool try_construct(Args&&... args) {
236 return variant::try_construct_impl<I>(_NEFORCE
forward<Args>(args)...);
256 template <
typename T, enable_if_t<disjunction_v<is_same<T, Types>...>,
int> = 0>
259 T* p =
reinterpret_cast<T*
>(union_);
270 index_(other.index_) {
271 copy_constructors_table()[
index()](union_, other.union_);
285 index_ = other.index_;
286 copy_assigment_functions_table()[
index()](union_, other.union_);
297 index_(other.index_) {
298 move_constructors_table()[
index()](union_, other.union_);
312 index_ = other.index_;
313 move_assigment_functions_table()[
index()](union_, other.union_);
325 template <
size_t Idx,
typename... Args,
343 template <
size_t Idx,
typename U,
typename... Args,
349 std::initializer_list<U>&, Args...>) :
363 if (!variant::try_construct(_NEFORCE
forward<Args>(args)...)) {
374 NEFORCE_CONSTEXPR20
~variant() noexcept { destructors_table()[
index()](union_); }
384 template <
typename Lambda, enable_if_t<conjunction_v<is_invocable<Lambda, Types&>...>,
int> = 0>
398 template <
typename Lambda, enable_if_t<conjunction_v<is_invocable<Lambda, const Types&>...>,
int> = 0>
408 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20
size_t index() const noexcept {
return index_; }
426 template <
size_t Idx,
enable_if_t<(Idx <
sizeof...(Types)),
int> = 0>
440 template <
typename T>
441 NEFORCE_CONSTEXPR20 T&
get() {
451 template <
size_t Idx,
enable_if_t<(Idx <
sizeof...(Types)),
int> = 0>
465 template <
typename T>
466 NEFORCE_CONSTEXPR20 T
const&
get()
const {
475 template <
size_t Idx,
enable_if_t<(Idx <
sizeof...(Types)),
int> = 0>
488 template <
typename T>
489 NEFORCE_CONSTEXPR20 T*
get_if() noexcept {
498 template <
size_t Idx,
enable_if_t<(Idx <
sizeof...(Types)),
int> = 0>
511 template <
typename T>
512 NEFORCE_CONSTEXPR20 T
const*
get_if() const noexcept {
524 template <
size_t Idx,
typename... Args,
527 NEFORCE_CONSTEXPR20
void
529 destructors_table()[
index()](union_);
558 size_t this_index = index_;
559 const size_t other_index = other.index_;
560 alignas(_NEFORCE
max({
alignof(Types)...}))
byte_t temp_union[_NEFORCE
max({
sizeof(Types)...})];
561 move_constructors_table()[this_index](
reinterpret_cast<byte_t*
>(temp_union), union_);
562 destructors_table()[this_index](union_);
564 move_constructors_table()[other_index](union_, other.union_);
565 destructors_table()[other_index](other.union_);
566 move_constructors_table()[this_index](other.union_,
reinterpret_cast<byte_t*
>(temp_union));
567 destructors_table()[this_index](
reinterpret_cast<byte_t*
>(temp_union));
569 index_ = other_index;
570 other.index_ = this_index;
581 if (index_ != rhs.index_) {
584 return this->
visit([&](
const auto& value) {
585 return rhs.
visit([&](
const auto& other_value) {
return value == other_value; });
595 if (index_ != rhs.index_) {
598 return this->
visit([&](
const auto& value) {
599 return rhs.
visit([&](
const auto& other_value) {
return value < other_value; });
607 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20
size_t to_hash()
const;
610#ifdef NEFORCE_STANDARD_17
611template <
typename... Args>
616template <
typename T,
typename... Types>
620template <
typename T,
typename... Types,
size_t Idx>
622 using type =
typename variant_alternative<variant<Types...>, Idx - 1>::type;
625template <
typename T,
typename... Types>
627 static constexpr size_t value = 0;
629template <
typename T0,
typename T,
typename... Types>
631 static constexpr size_t value = variant_index<variant<Types...>, T>::value + 1;
642template <
size_t Idx,
typename... Types>
645 using variant_type =
variant<Types...>;
646 return static_cast<T&
>(
static_cast<variant_type&
>(v).template
get<Idx>());
656template <
size_t Idx,
typename... Types>
659 using variant_type =
variant<Types...>;
660 return static_cast<const T&
>(
static_cast<const variant_type&
>(v).template
get<Idx>());
670template <
size_t Idx,
typename... Types>
673 using variant_type =
variant<Types...>;
674 return static_cast<T&&
>(
static_cast<variant_type&&
>(v).template
get<Idx>());
684template <
size_t Idx,
typename... Types>
687 using variant_type =
variant<Types...>;
688 return static_cast<const T&&
>(
static_cast<const variant_type&&
>(v).template
get<Idx>());
695struct __variant_elem_hasher {
696 template <
typename T>
697 constexpr size_t operator()(
const T& value)
const {
698 return hash<decay_t<T>>{}(value);
703template <
typename... Types>
705 constexpr inner::__variant_elem_hasher hasher{};
713NEFORCE_END_NAMESPACE__
NEFORCE_NODISCARD constexpr T * addressof(T &x) noexcept
获取对象的地址
NEFORCE_NODISCARD constexpr T && forward(remove_reference_t< T > &x) noexcept
完美转发左值
constexpr const T & max(const T &a, const T &b, Compare comp) noexcept(noexcept(comp(a, b)))
返回两个值中的较大者
unsigned char byte_t
字节类型,定义为无符号字符
NEFORCE_CONSTEXPR14 inner::__invoke_result_aux< Callable, Args... >::type invoke(Callable &&f, Args &&... args) noexcept(is_nothrow_invocable< Callable, Args... >::value)
统一调用接口
typename inner::__invoke_result_aux< F, Args... >::type invoke_result_t
invoke_result的便捷别名
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result) noexcept(noexcept(inner::__move_aux(first, last, result)))
移动范围元素
typename get_first_para< Types... >::type get_first_para_t
get_first_para的便捷别名
typename common_type< Types... >::type common_type_t
common_type的便捷别名
NEFORCE_INLINE17 constexpr bool is_nothrow_default_constructible_v
is_nothrow_default_constructible的便捷变量模板
NEFORCE_INLINE17 constexpr bool is_nothrow_constructible_v
is_nothrow_constructible的便捷变量模板
NEFORCE_INLINE17 constexpr bool is_constructible_v
is_constructible的便捷变量模板
NEFORCE_INLINE17 constexpr bool is_nothrow_move_constructible_v
is_nothrow_move_constructible的便捷变量模板
NEFORCE_INLINE17 constexpr bool disjunction_v
disjunction的便捷变量模板
NEFORCE_INLINE17 constexpr bool is_any_of_v
is_any_of的便捷变量模板
NEFORCE_INLINE17 constexpr bool conjunction_v
conjunction的便捷变量模板
typename enable_if< Test, T >::type enable_if_t
enable_if的便捷别名
NEFORCE_CONSTEXPR20 variant_alternative_t< variant< Types... >, Idx > & get(variant< Types... > &v)
获取变体中指定索引位置的引用
typename variant_alternative< Variant, Idx >::type variant_alternative_t
variant_alternative的便捷别名,获取变体中指定索引位置的类型
NEFORCE_INLINE17 constexpr size_t variant_index_v
variant_index的便捷别名,获取类型在变体中的索引值
variant(Args &&... args)
通用构造函数
NEFORCE_CONSTEXPR20 variant(inplace_construct_tag, Args &&... args) noexcept(is_nothrow_constructible_v< variant_alternative_t< variant, Idx >, Args... >)
参数列表原地构造函数
NEFORCE_CONSTEXPR20 variant & operator=(const variant &other)
拷贝赋值运算符
NEFORCE_CONSTEXPR20 variant_alternative_t< variant, Idx > const * get_if() const noexcept
如果存在,获取指定索引位置的常量指针
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_t index() const noexcept
获取当前存储类型的索引
NEFORCE_CONSTEXPR20 variant(inplace_construct_tag, std::initializer_list< U > ilist, Args &&... args) noexcept(is_nothrow_constructible_v< variant_alternative_t< variant, Idx >, std::initializer_list< U > &, Args... >)
初始化列表原地构造函数
NEFORCE_CONSTEXPR20 variant & operator=(variant &&other) noexcept
移动赋值运算符
NEFORCE_CONSTEXPR20 variant(T &&value) noexcept(is_nothrow_move_constructible_v< T >)
从特定类型值构造
NEFORCE_CONSTEXPR20 variant_alternative_t< variant, Idx > * get_if() noexcept
如果存在,获取指定索引位置的指针
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator==(const variant &rhs) const
相等比较运算符
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool holds_alternative() const noexcept
检查是否存储特定类型的值
NEFORCE_CONSTEXPR20 void emplace(Args &&... args) noexcept(is_nothrow_constructible_v< T, Args... >)
构造指定类型的新值
NEFORCE_CONSTEXPR20 variant(variant &&other) noexcept
移动构造函数
NEFORCE_CONSTEXPR20 T const & get() const
获取指定类型值的常量引用
NEFORCE_CONSTEXPR20 void emplace(Args &&... args) noexcept(is_nothrow_constructible_v< variant_alternative_t< variant, Idx >, Args... >)
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator<(const variant &rhs) const
小于比较运算符
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_t to_hash() const
计算变体的哈希值
NEFORCE_CONSTEXPR20 common_type_t< invoke_result_t< Lambda, Types & >... > visit(Lambda &&lambda) noexcept(conjunction_v< is_nothrow_invocable< Lambda, Types & >... >)
访问变体值
NEFORCE_CONSTEXPR20 void swap(variant &other) noexcept
交换两个变体的内容
NEFORCE_CONSTEXPR20 variant_alternative_t< variant, Idx > const & get() const
获取指定索引位置的常量引用
NEFORCE_CONSTEXPR20 ~variant() noexcept
析构函数
NEFORCE_CONSTEXPR20 T & get()
获取指定类型值的引用
NEFORCE_CONSTEXPR20 common_type_t< invoke_result_t< Lambda, const Types & >... > visit(Lambda &&lambda) const noexcept(conjunction_v< is_nothrow_invocable< Lambda, const Types & >... >)
常量访问变体值
NEFORCE_CONSTEXPR20 variant() noexcept(is_nothrow_default_constructible_v< variant_alternative_t< variant, 0 > >)
默认构造函数
NEFORCE_CONSTEXPR20 variant(const variant &other)
拷贝构造函数
NEFORCE_CONSTEXPR20 T * get_if() noexcept
如果存在,获取指定类型值的指针
NEFORCE_CONSTEXPR20 T const * get_if() const noexcept
如果存在,获取指定类型值的常量指针
NEFORCE_CONSTEXPR20 variant_alternative_t< variant, Idx > & get()
获取指定索引位置的引用