1#ifndef MSTL_CORE_UTILITY_VARIANT_HPP__
2#define MSTL_CORE_UTILITY_VARIANT_HPP__
27template <
typename Variant,
typename T>
30#ifdef MSTL_STANDARD_14__
35template <
typename Variant,
typename T>
45template <
typename Variant,
size_t Idx>
52template <
typename Variant,
size_t Idx>
71template <
typename... Types>
73 static_assert(
sizeof...(Types) > 0,
"variant must have at least one type");
78 "if variant holds non, it should be at the first place");
92 using destruct_function = void(*)(
byte_t*);
100 static destruct_function* destructors_table()
noexcept {
101 static destruct_function function_ptrs[
sizeof...(Types)] = {
102 [](
byte_t* union_p)
noexcept {
103 reinterpret_cast<Types*
>(union_p)->~Types();
106 return function_ptrs;
109 using copy_construct_function = void(*)(
byte_t*,
byte_t const*);
117 static copy_construct_function* copy_constructors_table()
noexcept {
118 static copy_construct_function function_ptrs[
sizeof...(Types)] = {
119 [](
byte_t* union_dst,
byte_t const* union_src)
noexcept {
120 new (union_dst) Types(*
reinterpret_cast<Types const*
>(union_src));
123 return function_ptrs;
126 using copy_assignment_function = void(*)(
byte_t*,
byte_t const*);
134 static copy_assignment_function* copy_assigment_functions_table()
noexcept {
135 static copy_assignment_function function_ptrs[
sizeof...(Types)] = {
136 [](
byte_t* union_dst,
byte_t const* union_src)
noexcept {
137 *
reinterpret_cast<Types*
>(union_dst) = *
reinterpret_cast<Types const*
>(union_src);
140 return function_ptrs;
143 using move_construct_function = void(*)(
byte_t*,
const byte_t*);
151 static move_construct_function* move_constructors_table()
noexcept {
152 static move_construct_function function_ptrs[
sizeof...(Types)] = {
153 [](
byte_t* union_dst,
const byte_t* union_src)
noexcept {
154 new (union_dst) Types(
_MSTL move(*
reinterpret_cast<const Types*
>(union_src)));
157 return function_ptrs;
160 using move_assignment_function = void(*)(
byte_t*,
byte_t*);
168 static move_assignment_function* move_assigment_functions_table()
noexcept {
169 static move_assignment_function function_ptrs[
sizeof...(Types)] = {
171 *
reinterpret_cast<Types*
>(union_dst) =
_MSTL move(*
reinterpret_cast<Types*
>(union_src));
174 return function_ptrs;
177 template <
typename Lambda>
188 template <
typename Lambda>
189 static const_visitor_function<Lambda>* const_visitors_table()
noexcept {
190 static const_visitor_function<Lambda> function_ptrs[
sizeof...(Types)] = {
195 return function_ptrs;
198 template <
typename Lambda>
209 template <
typename Lambda>
210 static visitor_function<Lambda>* visitors_table()
noexcept {
211 static visitor_function<Lambda> function_ptrs[
sizeof...(Types)] = {
216 return function_ptrs;
220 is_constructible_v<variant_alternative_t<variant, I>, Args...>,
int> = 0>
221 constexpr bool try_construct_impl_aux_aux(Args&&... args) {
228 !is_constructible_v<variant_alternative_t<variant, I>, Args...>,
int> = 0>
229 constexpr bool try_construct_impl_aux_aux(Args&&... args) {
233 template <
size_t I,
typename... Args,
enable_if_t<(I <
sizeof...(Types)),
int> = 0>
234 constexpr bool try_construct_impl_aux(Args&&... args) {
238 template <
size_t I,
typename... Args,
enable_if_t<(I >=
sizeof...(Types)),
int> = 0>
239 constexpr bool try_construct_impl_aux(Args&&...) {
243 template <
size_t I,
typename... Args>
244 constexpr bool try_construct_impl(Args&&... args) {
248 template <
size_t I = 0,
typename... Args>
249 constexpr bool try_construct(Args&&... args) {
271 template <
typename T, enable_if_t<disjunction_v<is_same<T, Types>...>,
int> = 0>
273 noexcept(is_nothrow_move_constructible_v<T>)
274 : index_(variant_index_v<
variant, T>) {
275 T* p =
reinterpret_cast<T*
>(union_);
287 copy_constructors_table()[
index()](union_, x.union_);
300 copy_assigment_functions_table()[
index()](union_, x.union_);
311 move_constructors_table()[
index()](union_, x.union_);
324 move_assigment_functions_table()[
index()](union_, x.union_);
336 template <
size_t Idx,
typename... Args,
339 noexcept(is_nothrow_constructible_v<variant_alternative_t<variant, Idx>, Args...>)
354 template <
size_t Idx,
typename U,
typename... Args,
357 noexcept(is_nothrow_constructible_v<variant_alternative_t<variant, Idx>, std::initializer_list<U>&, Args...>)
383 destructors_table()[
index()](union_);
394 template <
typename Lambda, enable_if_t<conjunction_v<is_invocable<Lambda, Types&>...>,
int> = 0>
396 noexcept(conjunction_v<is_nothrow_invocable<Lambda, Types&>...>) {
408 template <
typename Lambda, enable_if_t<conjunction_v<is_invocable<Lambda, const Types&>...>,
int> = 0>
410 noexcept(conjunction_v<is_nothrow_invocable<Lambda, const Types&>...>) {
418 MSTL_NODISCARD MSTL_CONSTEXPR20
size_t index() const noexcept {
427 template <
typename T,
enable_if_t<is_any_of_v<T, Types...>,
int> = 0>
429 return variant_index_v<variant, T> == index_;
438 template <
size_t Idx,
enable_if_t<(Idx <
sizeof...(Types)),
int> = 0>
452 template <
typename T>
453 MSTL_CONSTEXPR20 T&
get() {
463 template <
size_t Idx,
enable_if_t<(Idx <
sizeof...(Types)),
int> = 0>
477 template <
typename T>
478 MSTL_CONSTEXPR20 T
const&
get()
const {
487 template <
size_t Idx,
enable_if_t<(Idx <
sizeof...(Types)),
int> = 0>
489 if (index_ != Idx)
return nullptr;
498 template <
typename T>
508 template <
size_t Idx,
enable_if_t<(Idx <
sizeof...(Types)),
int> = 0>
510 if (index_ != Idx)
return nullptr;
519 template <
typename T>
520 MSTL_CONSTEXPR20 T
const*
get_if() const noexcept {
532 template <
size_t Idx,
typename... Args,
535 noexcept(is_nothrow_constructible_v<variant_alternative_t<variant, Idx>, Args...>) {
536 destructors_table()[
index()](union_);
549 template <
typename T,
typename... Args,
enable_if_t<is_constructible_v<T, Args...>,
int> = 0>
551 noexcept(is_nothrow_constructible_v<T, Args...>) {
564 size_t this_index = index_;
565 const size_t other_index = x.index_;
567 move_constructors_table()[this_index](
reinterpret_cast<byte_t*
>(temp_union), union_);
568 destructors_table()[this_index](union_);
570 move_constructors_table()[other_index](union_, x.union_);
571 destructors_table()[other_index](x.union_);
572 move_constructors_table()[this_index](x.union_,
reinterpret_cast<byte_t*
>(temp_union));
573 destructors_table()[this_index](
reinterpret_cast<byte_t*
>(temp_union));
575 index_ = other_index;
576 x.index_ = this_index;
587 if (index_ != rhs.index_)
return false;
588 return this->
visit([&](
const auto& value) {
589 return rhs.
visit([&](
const auto& other_value) {
590 return value == other_value;
601 if (index_ != rhs.index_)
return false;
602 return this->
visit([&](
const auto& value) {
603 return rhs.
visit([&](
const auto& other_value) {
604 return value < other_value;
613 MSTL_NODISCARD MSTL_CONSTEXPR20
size_t to_hash()
const;
616#ifdef MSTL_SUPPORT_DEDUCTION_GUIDES__
617template <
typename... Args>
622template <
typename T,
typename ...Types>
626template <
typename T,
typename ...Types,
size_t Idx>
628 using type =
typename variant_alternative<variant<Types...>, Idx - 1>::type;
631template <
typename T,
typename ...Types>
633 static constexpr size_t value = 0;
635template <
typename T0,
typename T,
typename ...Types>
637 static constexpr size_t value = variant_index<variant<Types...>, T>::value + 1;
648template <
size_t Idx,
typename... Types>
651 using variant_type =
variant<Types...>;
652 return static_cast<T&
>(
static_cast<variant_type&
>(v).template
get<Idx>());
662template <
size_t Idx,
typename... Types>
665 using variant_type =
variant<Types...>;
666 return static_cast<const T&
>(
static_cast<const variant_type&
>(v).template
get<Idx>());
676template <
size_t Idx,
typename... Types>
679 using variant_type =
variant<Types...>;
680 return static_cast<T&&
>(
static_cast<variant_type&&
>(v).template
get<Idx>());
690template <
size_t Idx,
typename... Types>
693 using variant_type =
variant<Types...>;
694 return static_cast<const T&&
>(
static_cast<const variant_type&&
>(v).template
get<Idx>());
699struct __variant_elem_hasher {
700 template <
typename T>
701 constexpr size_t operator ()(
const T& value)
const {
702 return hash<decay_t<T>>{}(value);
708template <
typename... Types>
710 constexpr _INNER __variant_elem_hasher hasher{};
MSTL_NODISCARD constexpr T * addressof(T &x) noexcept
获取对象的地址
MSTL_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
字节类型,定义为无符号字符
MSTL_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的便捷别名
#define _MSTL
全局命名空间MSTL前缀
#define MSTL_END_INNER__
结束inner命名空间
#define _INNER
inner命名空间前缀
#define MSTL_END_NAMESPACE__
结束全局命名空间MSTL
#define MSTL_BEGIN_NAMESPACE__
开始全局命名空间MSTL
#define MSTL_BEGIN_INNER__
开始inner命名空间
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result)
移动范围元素
typename get_first_para< Types... >::type get_first_para_t
get_first_para的便捷别名
typename common_type< Types... >::type common_type_t
common_type的便捷别名
typename enable_if< Test, T >::type enable_if_t
enable_if的便捷别名
MSTL_CONSTEXPR20 variant_alternative_t< variant< Types... >, Idx > & get(variant< Types... > &v)
获取变体中指定索引位置的引用
MSTL_NODISCARD MSTL_CONSTEXPR20 size_t to_hash() const
计算变体的哈希值
typename variant_alternative< Variant, Idx >::type variant_alternative_t
variant_alternative的便捷别名,获取变体中指定索引位置的类型
MSTL_NODISCARD MSTL_CONSTEXPR20 bool holds_alternative() const noexcept
检查是否存储特定类型的值
variant(Args &&... args)
通用构造函数
MSTL_CONSTEXPR20 variant & operator=(const variant &x)
拷贝赋值运算符
MSTL_CONSTEXPR20 T * get_if() noexcept
如果存在,获取指定类型值的指针
MSTL_CONSTEXPR20 variant(inplace_construct_tag, Args &&... args) noexcept(is_nothrow_constructible_v< variant_alternative_t< variant, Idx >, Args... >)
参数列表原地构造函数
MSTL_CONSTEXPR20 variant(const variant &x)
拷贝构造函数
MSTL_CONSTEXPR20 ~variant() noexcept
析构函数
MSTL_CONSTEXPR20 common_type_t< invoke_result_t< Lambda, Types & >... > visit(Lambda &&lambda) noexcept(conjunction_v< is_nothrow_invocable< Lambda, Types & >... >)
访问变体值
MSTL_NODISCARD MSTL_CONSTEXPR20 bool operator==(const variant &rhs) const
相等比较运算符
MSTL_CONSTEXPR20 T const * get_if() const noexcept
如果存在,获取指定类型值的常量指针
MSTL_CONSTEXPR20 T const & get() const
获取指定类型值的常量引用
MSTL_CONSTEXPR20 variant() noexcept(is_nothrow_default_constructible_v< variant_alternative_t< variant, 0 > >)
默认构造函数
MSTL_NODISCARD MSTL_CONSTEXPR20 size_t index() const noexcept
获取当前存储类型的索引
MSTL_CONSTEXPR20 common_type_t< invoke_result_t< Lambda, const Types & >... > visit(Lambda &&lambda) const noexcept(conjunction_v< is_nothrow_invocable< Lambda, const Types & >... >)
常量访问变体值
MSTL_CONSTEXPR20 void emplace(Args &&... args) noexcept(is_nothrow_constructible_v< T, Args... >)
构造指定类型的新值
MSTL_CONSTEXPR20 T & get()
获取指定类型值的引用
MSTL_CONSTEXPR20 variant_alternative_t< variant, Idx > & get()
获取指定索引位置的引用
MSTL_CONSTEXPR20 void emplace(Args &&... args) noexcept(is_nothrow_constructible_v< variant_alternative_t< variant, Idx >, Args... >)
在指定位置构造新值
MSTL_CONSTEXPR20 variant_alternative_t< variant, Idx > const & get() const
获取指定索引位置的常量引用
MSTL_CONSTEXPR20 variant_alternative_t< variant, Idx > * get_if() noexcept
如果存在,获取指定索引位置的指针
MSTL_CONSTEXPR20 void swap(variant &x) noexcept
交换两个变体的内容
MSTL_CONSTEXPR20 variant_alternative_t< variant, Idx > const * get_if() const noexcept
如果存在,获取指定索引位置的常量指针
MSTL_CONSTEXPR20 variant(T &&value) noexcept(is_nothrow_move_constructible_v< T >)
从特定类型值构造
MSTL_CONSTEXPR20 variant(variant &&x) noexcept
移动构造函数
MSTL_NODISCARD MSTL_CONSTEXPR20 bool operator<(const variant &rhs) const
小于比较运算符
MSTL_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... >)
初始化列表原地构造函数