STL/stl/inc/variant

1769 строки
81 KiB
C++
Исходник Обычный вид История

2019-09-05 01:57:56 +03:00
// variant standard header
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#pragma once
#ifndef _VARIANT_
#define _VARIANT_
#include <yvals.h>
#if _STL_COMPILER_PREPROCESSOR
#if !_HAS_CXX17
#pragma message("The contents of <variant> are available only with C++17 or later.")
#else // ^^^ !_HAS_CXX17 / _HAS_CXX17 vvv
2019-09-05 01:57:56 +03:00
#include <exception>
#include <initializer_list>
#include <type_traits>
#include <utility>
#include <xmemory>
#include <xsmf_control.h>
#include <xstddef>
#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new
#ifdef __clang__
#define _STL_UNREACHABLE __builtin_unreachable()
#else // ^^^ clang ^^^ / vvv other vvv
#define _STL_UNREACHABLE __assume(false)
#endif // __clang__
_STD_BEGIN
// TYPE TRAITS
template <class...>
struct _All_same : true_type {};
template <class _First, class... _Rest>
struct _All_same<_First, _Rest...> : bool_constant<conjunction_v<is_same<_First, _Rest>...>> {}; // variadic is_same
template <class _To, class... _From>
struct _Convertible_from_all : bool_constant<conjunction_v<is_convertible<_From, _To>...>> {
// variadic is_convertible
};
2019-09-05 01:57:56 +03:00
// METAPROGRAMMING UTILITIES
template <class...>
struct _Meta_list {}; // a sequence of types
struct _Meta_nil {};
// ALIAS TEMPLATE _Meta_front
template <class _List>
struct _Meta_front_;
template <class _List>
using _Meta_front =
// extract the first type in a sequence (head of list)
typename _Meta_front_<_List>::type;
template <template <class...> class _List, class _First, class... _Rest>
struct _Meta_front_<_List<_First, _Rest...>> {
using type = _First;
};
// ALIAS TEMPLATE _Meta_pop_front
template <class _List>
struct _Meta_pop_front_;
template <class _List>
using _Meta_pop_front =
// subsequence including all but the first type (tail of list)
typename _Meta_pop_front_<_List>::type;
template <template <class...> class _List, class _First, class... _Rest>
struct _Meta_pop_front_<_List<_First, _Rest...>> {
using type = _List<_Rest...>;
};
// ALIAS TEMPLATE _Meta_push_front
template <class _List, class _Ty>
struct _Meta_push_front_;
template <class _List, class _Ty>
using _Meta_push_front =
// prepend a new type onto a sequence
typename _Meta_push_front_<_List, _Ty>::type;
template <template <class...> class _List, class... _Types, class _Ty>
struct _Meta_push_front_<_List<_Types...>, _Ty> {
using type = _List<_Ty, _Types...>;
};
// STRUCT TEMPLATE _Meta_quote
template <class _Void, template <class...> class _Fn, class... _Args>
struct _Meta_quote_helper_;
template <template <class...> class _Fn, class... _Args>
struct _Meta_quote_helper_<void_t<_Fn<_Args...>>, _Fn, _Args...> {
using type = _Fn<_Args...>;
};
template <template <class...> class _Fn>
struct _Meta_quote { // encapsulate a template into a meta-callable type
template <class... _Types>
using _Invoke = typename _Meta_quote_helper_<void, _Fn, _Types...>::type;
};
// ALIAS TEMPLATE _Meta_invoke
template <class _Fn, class... _Args>
using _Meta_invoke = // invoke meta-callable _Fn with _Args
typename _Fn::template _Invoke<_Args...>;
// STRUCT TEMPLATE _Meta_bind_back
template <class _Fn, class... _Args>
struct _Meta_bind_back { // construct a meta-callable that passes its arguments and _Args to _Fn
template <class... _Types>
using _Invoke = _Meta_invoke<_Fn, _Types..., _Args...>;
};
// ALIAS TEMPLATE _Meta_apply
template <class _Fn, class _List>
struct _Meta_apply_;
template <class _Fn, class _List>
using _Meta_apply =
// explode _List into the parameters of meta-callable _Fn
typename _Meta_apply_<_Fn, _List>::type;
template <class _Fn, template <class...> class _List, class... _Types>
struct _Meta_apply_<_Fn,
_List<_Types...>> { // invoke meta-callable _Fn with the parameters of a template specialization
using type = _Meta_invoke<_Fn, _Types...>;
};
template <class _Fn, class _Ty, _Ty... _Idxs>
struct _Meta_apply_<_Fn,
integer_sequence<_Ty, _Idxs...>> { // invoke meta-callable _Fn with the elements of an integer_sequence
using type = _Meta_invoke<_Fn, integral_constant<_Ty, _Idxs>...>;
};
// ALIAS TEMPLATE _Meta_transform
template <class _Fn, class _List>
struct _Meta_transform_;
template <class _Fn, class _List>
using _Meta_transform =
// transform sequence of _Types... into sequence of _Fn<_Types...>
typename _Meta_transform_<_Fn, _List>::type;
template <template <class...> class _List, class _Fn, class... _Types>
struct _Meta_transform_<_Fn, _List<_Types...>> {
using type = _List<_Meta_invoke<_Fn, _Types>...>;
};
// ALIAS TEMPLATE _Meta_repeat_n_c
template <class, class, template <class...> class>
struct _Meta_repeat_n_c_;
template <size_t _Count, class _Ty, template <class...> class _Continue>
using _Meta_repeat_n_c =
// construct a sequence consisting of repetitions of _Ty
typename _Meta_repeat_n_c_<_Ty, make_index_sequence<_Count>, _Continue>::type;
template <class _Ty, size_t>
using _Meta_repeat_first_helper = _Ty;
template <class _Ty, size_t... _Idxs, template <class...> class _Continue>
struct _Meta_repeat_n_c_<_Ty, index_sequence<_Idxs...>, _Continue> {
using type = _Continue<_Meta_repeat_first_helper<_Ty, _Idxs>...>;
};
// ALIAS TEMPLATE _Meta_at_c
template <class _List, size_t _Idx, class = void>
struct _Meta_at_;
template <class _List, size_t _Idx>
using _Meta_at_c =
// Extract the _Idx-th type from _List
typename _Meta_at_<_List, _Idx>::type;
#ifdef __clang__
template <template <class...> class _List, class... _Types, size_t _Idx>
struct _Meta_at_<_List<_Types...>, _Idx, void_t<__type_pack_element<_Idx, _Types...>>> {
using type = __type_pack_element<_Idx, _Types...>;
};
#else // ^^^ __clang__ / !__clang__ vvv
template <class... _VoidPtrs>
struct _Meta_at_impl {
template <class _Ty, class... _Types>
static _Ty _Eval(_VoidPtrs..., _Ty*, _Types*...); // undefined
};
template <class _Ty>
constexpr _Identity<_Ty>* _Type_as_pointer() {
return nullptr;
}
template <template <class...> class _List, class... _Types, size_t _Idx>
struct _Meta_at_<_List<_Types...>, _Idx, enable_if_t<(_Idx < sizeof...(_Types))>> {
using type =
typename decltype(_Meta_repeat_n_c<_Idx, void*, _Meta_at_impl>::_Eval(_Type_as_pointer<_Types>()...))::type;
};
#endif // __clang__
// ALIAS TEMPLATE _Meta_find_index
inline constexpr auto _Meta_npos = ~size_t{0};
template <class _List, class _Ty>
struct _Meta_find_index_ {
using type = integral_constant<size_t, _Meta_npos>;
};
template <class _List, class _Ty>
using _Meta_find_index =
// find the index of the first occurrence of _Ty in _List
typename _Meta_find_index_<_List, _Ty>::type;
constexpr size_t _Meta_find_index_i_(const bool* const _Ptr, const size_t _Count,
size_t _Idx = 0) { // return the index of the first true in the _Count bools at _Ptr, or _Meta_npos if all are false
for (; _Idx < _Count; ++_Idx) {
if (_Ptr[_Idx]) {
return _Idx;
}
}
return _Meta_npos;
}
template <template <class...> class _List, class _First, class... _Rest, class _Ty>
struct _Meta_find_index_<_List<_First, _Rest...>, _Ty> {
static constexpr bool _Bools[] = {is_same_v<_First, _Ty>, is_same_v<_Rest, _Ty>...};
using type = integral_constant<size_t, _Meta_find_index_i_(_Bools, 1 + sizeof...(_Rest))>;
};
// ALIAS TEMPLATE _Meta_find_unique_index
template <class _List, class _Ty>
struct _Meta_find_unique_index_ {
using type = integral_constant<size_t, _Meta_npos>;
};
template <class _List, class _Ty>
using _Meta_find_unique_index =
// The index of _Ty in _List if it occurs exactly once, otherwise _Meta_npos
typename _Meta_find_unique_index_<_List, _Ty>::type;
constexpr size_t _Meta_find_unique_index_i_2(const bool* const _Ptr, const size_t _Count,
const size_t
_First) { // return _First if there is no _First < j < _Count such that _Ptr[j] is true, otherwise _Meta_npos
return _First != _Meta_npos && _Meta_find_index_i_(_Ptr, _Count, _First + 1) == _Meta_npos ? _First : _Meta_npos;
}
constexpr size_t _Meta_find_unique_index_i_(const bool* const _Ptr,
const size_t _Count) { // Pass the smallest i such that _Ptr[i] is true to _Meta_find_unique_index_i_2
return _Meta_find_unique_index_i_2(_Ptr, _Count, _Meta_find_index_i_(_Ptr, _Count));
}
template <template <class...> class _List, class _First, class... _Rest, class _Ty>
struct _Meta_find_unique_index_<_List<_First, _Rest...>, _Ty> {
using type = integral_constant<size_t,
_Meta_find_unique_index_i_(_Meta_find_index_<_List<_First, _Rest...>, _Ty>::_Bools, 1 + sizeof...(_Rest))>;
};
// ALIAS TEMPLATE _Meta_as_list
template <class>
struct _Meta_as_list_;
template <class _Ty>
using _Meta_as_list =
// convert _Ty to a _Meta_list
typename _Meta_as_list_<_Ty>::type;
template <template <class...> class _List, class... _Types>
struct _Meta_as_list_<_List<_Types...>> { // convert the parameters of an arbitrary template specialization to a
// _Meta_list of types
using type = _Meta_list<_Types...>;
};
template <class _Ty, _Ty... _Idxs>
struct _Meta_as_list_<integer_sequence<_Ty, _Idxs...>> { // convert an integer_sequence to a _Meta_list of
// integral_constants
using type = _Meta_list<integral_constant<_Ty, _Idxs>...>;
};
// ALIAS TEMPLATE _Meta_as_integer_sequence
template <class _List>
struct _Meta_as_integer_sequence_;
template <class _List>
using _Meta_as_integer_sequence =
// convert a list of integral_constants to an integer_sequence
typename _Meta_as_integer_sequence_<_List>::type;
template <template <class...> class _List, class _Ty, _Ty... _Idxs>
struct _Meta_as_integer_sequence_<_List<integral_constant<_Ty, _Idxs>...>> {
using type = integer_sequence<_Ty, _Idxs...>;
};
// ALIAS TEMPLATE _Meta_concat
template <class...>
struct _Meta_concat_;
template <class... _Types>
using _Meta_concat =
// merge several lists into one
typename _Meta_concat_<_Types...>::type;
template <template <class...> class _List>
struct _Meta_concat_<_List<>> {
using type = _List<>;
};
template <template <class...> class _List, class... _Items1>
struct _Meta_concat_<_List<_Items1...>> {
using type = _List<_Items1...>;
};
template <template <class...> class _List, class... _Items1, class... _Items2>
struct _Meta_concat_<_List<_Items1...>, _List<_Items2...>> {
using type = _List<_Items1..., _Items2...>;
};
template <template <class...> class _List, class... _Items1, class... _Items2, class... _Items3>
struct _Meta_concat_<_List<_Items1...>, _List<_Items2...>, _List<_Items3...>> {
using type = _List<_Items1..., _Items2..., _Items3...>;
};
template <template <class...> class _List, class... _Items1, class... _Items2, class... _Items3, class... _Rest>
struct _Meta_concat_<_List<_Items1...>, _List<_Items2...>, _List<_Items3...>, _Rest...> {
using type = _Meta_concat<_List<_Items1..., _Items2..., _Items3...>, _Rest...>;
};
// ALIAS TEMPLATE _Meta_join
template <class _ListOfLists>
using _Meta_join =
// transform a list of lists of elements into a single list containing those elements
_Meta_apply<_Meta_quote<_Meta_concat>, _ListOfLists>;
// ALIAS TEMPLATE _Meta_cartesian_product
template <class>
struct _Meta_cartesian_product_;
template <class _ListOfLists>
using _Meta_cartesian_product =
// find the n-ary Cartesian Product of the lists in the input list
typename _Meta_cartesian_product_<_ListOfLists>::type;
template <template <class...> class _List>
struct _Meta_cartesian_product_<_List<>> {
using type = _List<>;
};
template <template <class...> class _List1, template <class...> class _List2, class... _Items>
struct _Meta_cartesian_product_<_List1<_List2<_Items...>>> {
using type = _List1<_List2<_Items>...>;
};
template <template <class...> class _List1, class... _Items, template <class...> class _List2, class... _Lists>
struct _Meta_cartesian_product_<_List1<_List2<_Items...>, _Lists...>> {
using type = _Meta_join<_List1<_Meta_transform<_Meta_bind_back<_Meta_quote<_Meta_push_front>, _Items>,
_Meta_cartesian_product<_List1<_Lists...>>>...>>;
};
#define _STL_STAMP4(n, x) \
x(n); \
x(n + 1); \
x(n + 2); \
x(n + 3)
#define _STL_STAMP16(n, x) \
_STL_STAMP4(n, x); \
_STL_STAMP4(n + 4, x); \
_STL_STAMP4(n + 8, x); \
_STL_STAMP4(n + 12, x)
#define _STL_STAMP64(n, x) \
_STL_STAMP16(n, x); \
_STL_STAMP16(n + 16, x); \
_STL_STAMP16(n + 32, x); \
_STL_STAMP16(n + 48, x)
#define _STL_STAMP256(n, x) \
_STL_STAMP64(n, x); \
_STL_STAMP64(n + 64, x); \
_STL_STAMP64(n + 128, x); \
_STL_STAMP64(n + 192, x)
#define _STL_STAMP(n, x) x(_STL_STAMP##n, n)
// VARIANT OF VALUE TYPES [variant.variant]
template <class... _Types>
class variant;
// VARIANT HELPER CLASSES [variant.helper]
template <class _Ty>
struct variant_size; // undefined
template <class _Ty>
struct variant_size<const _Ty> : variant_size<_Ty>::type {};
template <class _Ty>
struct _CXX20_DEPRECATE_VOLATILE variant_size<volatile _Ty> : variant_size<_Ty>::type {};
2019-09-05 01:57:56 +03:00
template <class _Ty>
struct _CXX20_DEPRECATE_VOLATILE variant_size<const volatile _Ty> : variant_size<_Ty>::type {};
2019-09-05 01:57:56 +03:00
template <class _Ty>
inline constexpr size_t variant_size_v = variant_size<_Ty>::value;
template <class... _Types>
struct variant_size<variant<_Types...>> : integral_constant<size_t, sizeof...(_Types)> {};
template <size_t _Idx, class _Ty>
struct variant_alternative; // undefined
template <size_t _Idx, class _Ty>
using variant_alternative_t = typename variant_alternative<_Idx, _Ty>::type;
template <size_t _Idx, class _Ty>
struct variant_alternative<_Idx, const _Ty> {
using type = add_const_t<variant_alternative_t<_Idx, _Ty>>;
};
template <size_t _Idx, class _Ty>
struct _CXX20_DEPRECATE_VOLATILE variant_alternative<_Idx, volatile _Ty> {
2019-09-05 01:57:56 +03:00
using type = add_volatile_t<variant_alternative_t<_Idx, _Ty>>;
};
template <size_t _Idx, class _Ty>
struct _CXX20_DEPRECATE_VOLATILE variant_alternative<_Idx, const volatile _Ty> {
2019-09-05 01:57:56 +03:00
using type = add_cv_t<variant_alternative_t<_Idx, _Ty>>;
};
template <size_t _Idx, class... _Types>
struct variant_alternative<_Idx, variant<_Types...>> {
static_assert(_Idx < sizeof...(_Types), "variant index out of bounds");
#ifdef __clang__
using type = __type_pack_element<_Idx, _Types...>;
#else // ^^^ __clang__ ^^^ / vvv !__clang__ vvv
using type = _Meta_at_c<variant<_Types...>, _Idx>;
#endif // __clang__
};
inline constexpr size_t variant_npos = _Meta_npos;
// CLASS bad_variant_access [variant.bad.access]
class bad_variant_access
: public exception { // exception for visit of a valueless variant or get<I> on a variant with index() != I
public:
bad_variant_access() noexcept = default;
_NODISCARD virtual const char* __CLR_OR_THIS_CALL what() const noexcept override {
return "bad variant access";
}
#if !_HAS_EXCEPTIONS
protected:
virtual void _Doraise() const override { // perform class-specific exception handling
2019-09-05 01:57:56 +03:00
_RAISE(*this);
}
#endif // !_HAS_EXCEPTIONS
};
[[noreturn]] inline void _Throw_bad_variant_access() {
_THROW(bad_variant_access{});
}
template <bool _TrivialDestruction, class... _Types>
class _Variant_storage_ { // empty storage (empty "_Types" case)
};
// ALIAS TEMPLATE _Variant_storage
template <class... _Types>
using _Variant_storage = _Variant_storage_<conjunction_v<is_trivially_destructible<_Types>...>, _Types...>;
template <class _First, class... _Rest>
class _Variant_storage_<true, _First, _Rest...> { // Storage for variant alternatives (trivially destructible case)
public:
static constexpr size_t _Size = 1 + sizeof...(_Rest);
union {
remove_const_t<_First> _Head;
_Variant_storage<_Rest...> _Tail;
};
_Variant_storage_() noexcept { // no initialization (no active member)
}
template <class... _Types>
constexpr explicit _Variant_storage_(integral_constant<size_t, 0>, _Types&&... _Args) noexcept(
is_nothrow_constructible_v<_First, _Types...>)
: _Head(static_cast<_Types&&>(_Args)...) { // initialize _Head with _Args...
}
template <size_t _Idx, class... _Types, enable_if_t<(_Idx > 0), int> = 0>
constexpr explicit _Variant_storage_(integral_constant<size_t, _Idx>, _Types&&... _Args) noexcept(
is_nothrow_constructible_v<_Variant_storage<_Rest...>, integral_constant<size_t, _Idx - 1>, _Types...>)
: _Tail(integral_constant<size_t, _Idx - 1>{}, static_cast<_Types&&>(_Args)...) { // initialize _Tail (recurse)
}
_NODISCARD constexpr _First& _Get() & noexcept {
return _Head;
}
_NODISCARD constexpr const _First& _Get() const& noexcept {
return _Head;
}
_NODISCARD constexpr _First&& _Get() && noexcept {
return _STD move(_Head);
}
_NODISCARD constexpr const _First&& _Get() const&& noexcept {
return _STD move(_Head);
}
};
template <class _First, class... _Rest>
class _Variant_storage_<false, _First, _Rest...> { // Storage for variant alternatives (non-trivially destructible case)
public:
static constexpr size_t _Size = 1 + sizeof...(_Rest);
union {
remove_const_t<_First> _Head;
_Variant_storage<_Rest...> _Tail;
};
~_Variant_storage_() noexcept { // explicitly non-trivial destructor (which would otherwise be defined as deleted
// since the class has a variant member with a non-trivial destructor)
}
_Variant_storage_() noexcept { // no initialization (no active member)
}
template <class... _Types>
constexpr explicit _Variant_storage_(integral_constant<size_t, 0>, _Types&&... _Args) noexcept(
is_nothrow_constructible_v<_First, _Types...>)
: _Head(static_cast<_Types&&>(_Args)...) { // initialize _Head with _Args...
}
template <size_t _Idx, class... _Types, enable_if_t<(_Idx > 0), int> = 0>
constexpr explicit _Variant_storage_(integral_constant<size_t, _Idx>, _Types&&... _Args) noexcept(
is_nothrow_constructible_v<_Variant_storage<_Rest...>, integral_constant<size_t, _Idx - 1>, _Types...>)
: _Tail(integral_constant<size_t, _Idx - 1>{}, static_cast<_Types&&>(_Args)...) { // initialize _Tail (recurse)
}
_Variant_storage_(_Variant_storage_&&) = default;
_Variant_storage_(const _Variant_storage_&) = default;
_Variant_storage_& operator=(_Variant_storage_&&) = default;
_Variant_storage_& operator=(const _Variant_storage_&) = default;
_NODISCARD constexpr _First& _Get() & noexcept {
return _Head;
}
_NODISCARD constexpr const _First& _Get() const& noexcept {
return _Head;
}
_NODISCARD constexpr _First&& _Get() && noexcept {
return _STD move(_Head);
}
_NODISCARD constexpr const _First&& _Get() const&& noexcept {
return _STD move(_Head);
}
};
#ifdef __cplusplus_winrt // TRANSITION, VSO-586813
2019-09-05 01:57:56 +03:00
// C++/CX is unable to store hats in unions. We instead store them inside a
// wrapper to enable minimal hats-in-variants support.
template <class _Ty>
struct _Variant_item {
remove_const_t<_Ty> _Item;
template <class... _Types>
constexpr _Variant_item(_Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>)
: _Item(static_cast<_Types&&>(_Args)...) {}
};
template <class _First, class... _Rest>
class _Variant_storage_<false, _First ^, _Rest...> { // Storage for variant alternatives (^ case)
public:
static constexpr size_t _Size = 1 + sizeof...(_Rest);
union {
_Variant_item<_First ^> _Head;
_Variant_storage<_Rest...> _Tail;
};
~_Variant_storage_() noexcept { // explicitly non-trivial destructor (which would otherwise be defined as deleted
// since the class has a variant member with a non-trivial destructor)
}
_Variant_storage_() noexcept { // no initialization (no active member)
}
template <class... _Types>
constexpr explicit _Variant_storage_(integral_constant<size_t, 0>, _Types&&... _Args) noexcept(
is_nothrow_constructible_v<_First ^, _Types...>)
: _Head(static_cast<_Types&&>(_Args)...) { // initialize _Head with _Args...
}
template <size_t _Idx, class... _Types, enable_if_t<(_Idx > 0), int> = 0>
constexpr explicit _Variant_storage_(integral_constant<size_t, _Idx>, _Types&&... _Args) noexcept(
is_nothrow_constructible_v<_Variant_storage<_Rest...>, integral_constant<size_t, _Idx - 1>, _Types...>)
: _Tail(integral_constant<size_t, _Idx - 1>{}, static_cast<_Types&&>(_Args)...) { // initialize _Tail (recurse)
}
_Variant_storage_(_Variant_storage_&&) = default;
_Variant_storage_(const _Variant_storage_&) = default;
_Variant_storage_& operator=(_Variant_storage_&&) = default;
_Variant_storage_& operator=(const _Variant_storage_&) = default;
_NODISCARD constexpr _First ^ &_Get() & noexcept {
return _Head._Item;
}
_NODISCARD constexpr _First ^ const& _Get() const& noexcept {
return _Head._Item;
}
_NODISCARD constexpr _First ^ &&_Get() && noexcept {
return _STD move(_Head)._Item;
}
_NODISCARD constexpr _First ^ const&& _Get() const&& noexcept {
return _STD move(_Head)._Item;
}
};
#endif // __cplusplus_winrt
// _Variant_storage VISITATION AND ACCESS
template <size_t _Idx, class _Storage>
_NODISCARD constexpr decltype(auto) _Variant_raw_get(
_Storage&& _Obj) noexcept { // access the _Idx-th element of a _Variant_storage
if constexpr (_Idx == 0) {
return static_cast<_Storage&&>(_Obj)._Get();
} else if constexpr (_Idx == 1) {
return static_cast<_Storage&&>(_Obj)._Tail._Get();
} else if constexpr (_Idx == 2) {
return static_cast<_Storage&&>(_Obj)._Tail._Tail._Get();
} else if constexpr (_Idx == 3) {
return static_cast<_Storage&&>(_Obj)._Tail._Tail._Tail._Get();
} else if constexpr (_Idx == 4) {
return static_cast<_Storage&&>(_Obj)._Tail._Tail._Tail._Tail._Get();
} else if constexpr (_Idx == 5) {
return static_cast<_Storage&&>(_Obj)._Tail._Tail._Tail._Tail._Tail._Get();
} else if constexpr (_Idx == 6) {
return static_cast<_Storage&&>(_Obj)._Tail._Tail._Tail._Tail._Tail._Tail._Get();
} else if constexpr (_Idx == 7) {
return static_cast<_Storage&&>(_Obj)._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Get();
} else if constexpr (_Idx < 16) {
return _Variant_raw_get<_Idx - 8>(
static_cast<_Storage&&>(_Obj)._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail);
} else if constexpr (_Idx < 32) {
return _Variant_raw_get<_Idx - 16>(
static_cast<_Storage&&>(_Obj)
._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail);
} else if constexpr (_Idx < 64) {
return _Variant_raw_get<_Idx - 32>(
static_cast<_Storage&&>(_Obj)
._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail
._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail);
} else { // _Idx >= 64
return _Variant_raw_get<_Idx - 64>(
static_cast<_Storage&&>(_Obj)
._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail
._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail
._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail
._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail);
}
}
template <class _Ty, size_t _Tag>
struct _Tagged { // aggregate a runtime value and a compile-time tag value
static constexpr size_t _Idx = _Tag;
_Ty _Val;
};
template <class _Storage, size_t _Idx>
using _Variant_tagged_ref_t = _Tagged<decltype(_Variant_raw_get<_Idx>(_STD declval<_Storage>()))&&, _Idx>;
template <class _Fn, class _Storage>
using _Variant_raw_visit_t = decltype(_STD declval<_Fn>()(_STD declval<_Variant_tagged_ref_t<_Storage, 0>>()));
template <size_t _Idx, class _Fn, class _Storage>
_NODISCARD constexpr _Variant_raw_visit_t<_Fn, _Storage> _Variant_raw_visit_dispatch(
_Fn&& _Func, _Storage&& _Var) noexcept(is_nothrow_invocable_v<_Fn, _Variant_tagged_ref_t<_Storage, _Idx>>) {
// call _Func with the _Idx-th element in _Storage (tagged with _Idx)
return static_cast<_Fn&&>(_Func)(
_Variant_tagged_ref_t<_Storage, _Idx>{_Variant_raw_get<_Idx>(static_cast<_Storage&&>(_Var))});
}
template <class _Fn, class _Storage>
_NODISCARD constexpr _Variant_raw_visit_t<_Fn, _Storage> _Variant_raw_visit_valueless(
_Fn&& _Func, _Storage&& _Obj) noexcept(is_nothrow_invocable_v<_Fn, _Tagged<_Storage&&, variant_npos>>) {
// call _Func with _Storage (tagged with variant_npos)
return static_cast<_Fn&&>(_Func)(_Tagged<_Storage&&, variant_npos>{static_cast<_Storage&&>(_Obj)});
}
template <class _Fn, class _Storage, class _Indices = make_index_sequence<remove_reference_t<_Storage>::_Size>>
inline constexpr bool _Variant_raw_visit_noexcept = false;
template <class _Fn, class _Storage, size_t... _Idxs>
inline constexpr bool _Variant_raw_visit_noexcept<_Fn, _Storage, index_sequence<_Idxs...>> =
conjunction_v<is_nothrow_invocable<_Fn, _Tagged<_Storage&&, variant_npos>>,
is_nothrow_invocable<_Fn, _Variant_tagged_ref_t<_Storage, _Idxs>>...>;
template <class _Fn, class _Storage,
class _Indices = make_index_sequence<remove_reference_t<_Storage>::_Size>>
struct _Variant_raw_dispatch_table1; // undefined
template <class _Fn, class _Storage, size_t... _Idxs>
struct _Variant_raw_dispatch_table1<_Fn, _Storage,
index_sequence<_Idxs...>> { // map from canonical index to visitation target
using _Dispatch_t = _Variant_raw_visit_t<_Fn, _Storage> (*)(_Fn&&, _Storage&&) noexcept(
_Variant_raw_visit_noexcept<_Fn, _Storage>);
static constexpr _Dispatch_t _Array[] = {
&_Variant_raw_visit_valueless<_Fn, _Storage>, &_Variant_raw_visit_dispatch<_Idxs, _Fn, _Storage>...};
};
template <int _Strategy>
struct _Variant_raw_visit1;
template <>
struct _Variant_raw_visit1<-1> { // Fallback case for variants too large for any of the following "switch" strategies
template <class _Fn, class _Storage>
_NODISCARD static constexpr _Variant_raw_visit_t<_Fn, _Storage> _Visit(
size_t _Idx, _Fn&& _Func, _Storage&& _Obj) noexcept(_Variant_raw_visit_noexcept<_Fn, _Storage>) {
// dispatch a visitor for a _Variant_storage with many states
constexpr size_t _Size = remove_reference_t<_Storage>::_Size;
static_assert(_Size > 256);
constexpr auto& _Array = _Variant_raw_dispatch_table1<_Fn, _Storage>::_Array;
return _Array[_Idx](static_cast<_Fn&&>(_Func), static_cast<_Storage&&>(_Obj));
}
};
#define _STL_CASE(n) \
case (n) + 1: \
if constexpr ((n) < _Size) { \
return static_cast<_Fn&&>(_Func)( \
_Variant_tagged_ref_t<_Storage, (n)>{_Variant_raw_get<(n)>(static_cast<_Storage&&>(_Obj))}); \
} \
_STL_UNREACHABLE
#define _STL_VISIT_STAMP(stamper, n) \
constexpr size_t _Size = remove_reference_t<_Storage>::_Size; \
static_assert(((n) == 4 || _Size > (n) / 4) && _Size <= (n)); \
switch (_Idx) { \
case 0: \
return static_cast<_Fn&&>(_Func)(_Tagged<_Storage&&, variant_npos>{static_cast<_Storage&&>(_Obj)}); \
\
stamper(0, _STL_CASE); \
default: \
_STL_UNREACHABLE; \
}
template <>
struct _Variant_raw_visit1<1> {
template <class _Fn, class _Storage>
_NODISCARD static constexpr _Variant_raw_visit_t<_Fn, _Storage> _Visit(
size_t _Idx, _Fn&& _Func, _Storage&& _Obj) noexcept(_Variant_raw_visit_noexcept<_Fn, _Storage>) {
// dispatch a visitor for a _Variant_storage with at most 4^1 states
_STL_STAMP(4, _STL_VISIT_STAMP);
}
};
template <>
struct _Variant_raw_visit1<2> {
template <class _Fn, class _Storage>
_NODISCARD static constexpr _Variant_raw_visit_t<_Fn, _Storage> _Visit(
size_t _Idx, _Fn&& _Func, _Storage&& _Obj) noexcept(_Variant_raw_visit_noexcept<_Fn, _Storage>) {
// dispatch a visitor for a _Variant_storage with at most 4^2 states
_STL_STAMP(16, _STL_VISIT_STAMP);
}
};
template <>
struct _Variant_raw_visit1<3> {
template <class _Fn, class _Storage>
_NODISCARD static constexpr _Variant_raw_visit_t<_Fn, _Storage> _Visit(
size_t _Idx, _Fn&& _Func, _Storage&& _Obj) noexcept(_Variant_raw_visit_noexcept<_Fn, _Storage>) {
// dispatch a visitor for a _Variant_storage with at most 4^3 states
_STL_STAMP(64, _STL_VISIT_STAMP);
}
};
template <>
struct _Variant_raw_visit1<4> {
template <class _Fn, class _Storage>
_NODISCARD static constexpr _Variant_raw_visit_t<_Fn, _Storage> _Visit(
size_t _Idx, _Fn&& _Func, _Storage&& _Obj) noexcept(_Variant_raw_visit_noexcept<_Fn, _Storage>) {
// dispatch a visitor for a _Variant_storage with at most 4^4 states
_STL_STAMP(256, _STL_VISIT_STAMP);
}
};
#undef _STL_VISIT_STAMP
#undef _STL_CASE
template <class _Storage, class _Fn>
_NODISCARD constexpr _Variant_raw_visit_t<_Fn, _Storage> _Variant_raw_visit(
size_t _Idx, _Storage&& _Obj, _Fn&& _Func) noexcept(_Variant_raw_visit_noexcept<_Fn, _Storage>) {
// Call _Func with _Storage if _Idx is variant_npos, and otherwise the _Idx-th element in _Storage.
// pre: _Idx + 1 <= remove_reference_t<_Storage>::_Size
constexpr size_t _Size = remove_reference_t<_Storage>::_Size;
constexpr int _Strategy = _Size <= 4 ? 1 : _Size <= 16 ? 2 : _Size <= 64 ? 3 : _Size <= 256 ? 4 : -1;
++_Idx; // bias index by +1 to map {variant_npos} U [0, _Size) to the contiguous range [0, _Size]
return _Variant_raw_visit1<_Strategy>::_Visit(_Idx, static_cast<_Fn&&>(_Func), static_cast<_Storage&&>(_Obj));
}
// STRUCT TEMPLATE _Variant_base
template <class...>
class _Variant_base;
template <size_t _Count>
using _Variant_index_t = // signed so that conversion of -1 to size_t can cheaply sign extend
conditional_t<(_Count < static_cast<size_t>((numeric_limits<signed char>::max)())), signed char,
conditional_t<(_Count < static_cast<size_t>((numeric_limits<short>::max)())), short, int>>;
template <class... _Types>
struct _Variant_construct_visitor { // visitor that constructs the same alternative in a target _Variant_base as is
// currently active in a source _Variant_base from the source's contained value
_Variant_base<_Types...>& _Self;
template <class _Ty, size_t _Idx>
void operator()(_Tagged<_Ty, _Idx> _Source) const noexcept(disjunction_v<bool_constant<_Idx == variant_npos>,
is_nothrow_constructible<remove_reference_t<_Ty>, _Ty>>) { // initialize _Idx-th item in _Self from _Source
// pre: _Self.valueless_by_exception()
(void) _Source; // TRANSITION, DevCom-1004719
2019-09-05 01:57:56 +03:00
if constexpr (_Idx != variant_npos) {
auto& _Target = _Variant_raw_get<_Idx>(_Self._Storage());
_Construct_in_place(_Target, static_cast<_Ty&&>(_Source._Val));
_Self._Set_index(_Idx);
}
}
};
template <class _Target, class... _Types>
inline constexpr bool _Variant_should_directly_construct_v =
disjunction_v<is_nothrow_constructible<_Target, _Types...>, negation<is_nothrow_move_constructible<_Target>>>;
template <class... _Types>
struct _Variant_assign_visitor { // visitor that implements assignment for variants with non-trivial alternatives
_Variant_base<_Types...>& _Self;
template <class _Ty, size_t _Idx>
void operator()(_Tagged<_Ty, _Idx> _Source) const noexcept(disjunction_v<bool_constant<_Idx == variant_npos>,
conjunction<is_nothrow_assignable<_Remove_cvref_t<_Ty>&, _Ty>,
is_nothrow_constructible<_Remove_cvref_t<_Ty>, _Ty>>>) {
// assign the _Idx-th alternative of _Self from _Source
if constexpr (_Idx == variant_npos) { // assign from valueless _Source
(void) _Source; // TRANSITION, DevCom-1004719
2019-09-05 01:57:56 +03:00
_Self._Reset();
} else {
auto& _Target = _Variant_raw_get<_Idx>(_Self._Storage());
if (_Self._Which == _Idx) { // same alternative: assign directly
_Target = static_cast<_Ty&&>(_Source._Val);
} else { // different alternative
if constexpr (is_lvalue_reference_v<_Ty>) { // RHS is an lvalue: copy
if constexpr (_Variant_should_directly_construct_v<_Remove_cvref_t<_Ty>,
_Ty>) { // copy is nothrow or move throws; construct in place
_Self._Reset();
_Construct_in_place(_Target, _Source._Val);
} else { // copy throws and move does not; move from a temporary copy
auto _Temp = _Source._Val;
_Self._Reset();
_Construct_in_place(_Target, _STD move(_Temp));
}
} else { // RHS is an rvalue: move
_Self._Reset();
_Construct_in_place(_Target, static_cast<_Ty&&>(_Source._Val));
}
_Self._Set_index(_Idx);
}
}
}
};
template <class... _Types>
class _Variant_base
: private _Variant_storage<_Types...> { // Associate an integral discriminator with a _Variant_storage
public:
using _Index_t = _Variant_index_t<sizeof...(_Types)>;
static constexpr auto _Invalid_index = static_cast<_Index_t>(-1);
_Index_t _Which;
using _Storage_t = _Variant_storage<_Types...>;
_NODISCARD constexpr _Storage_t& _Storage() & noexcept { // access this variant's storage
return *this;
}
_NODISCARD constexpr const _Storage_t& _Storage() const& noexcept { // access this variant's storage
return *this;
}
_NODISCARD constexpr _Storage_t&& _Storage() && noexcept { // access this variant's storage
return _STD move(*this);
}
_NODISCARD constexpr const _Storage_t&& _Storage() const&& noexcept { // access this variant's storage
return _STD move(*this);
}
_Variant_base() noexcept : _Storage_t{}, _Which{_Invalid_index} { // initialize to the value-less state
}
template <size_t _Idx, class... _UTypes,
enable_if_t<is_constructible_v<_Meta_at_c<variant<_Types...>, _Idx>, _UTypes...>, int> = 0>
constexpr explicit _Variant_base(in_place_index_t<_Idx>, _UTypes&&... _Args) noexcept(
is_nothrow_constructible_v<_Meta_at_c<variant<_Types...>, _Idx>, _UTypes...>)
: _Storage_t(integral_constant<size_t, _Idx>{}, static_cast<_UTypes&&>(_Args)...),
_Which{static_cast<_Index_t>(_Idx)} { // initialize alternative _Idx from _Args...
}
_NODISCARD constexpr bool valueless_by_exception() const noexcept { // does this variant NOT hold a value?
return _Which < 0;
}
_NODISCARD constexpr size_t index() const noexcept {
// index of the contained alternative or variant_npos if valueless_by_exception
2019-09-05 01:57:56 +03:00
return static_cast<size_t>(_Which);
}
void _Set_index(const size_t _Idx) noexcept {
// record _Idx as the active alternative
// pre: the active alternative of *this is _Idx
2019-09-05 01:57:56 +03:00
_Which = static_cast<_Index_t>(_Idx);
}
template <size_t _Idx>
void _Destroy() noexcept {
// destroy the contained value
// pre: _Idx == index()
2019-09-05 01:57:56 +03:00
if constexpr (_Idx != variant_npos && !is_trivially_destructible_v<_Meta_at_c<variant<_Types...>, _Idx>>) {
_Destroy_in_place(_Variant_raw_get<_Idx>(_Storage()));
}
}
void _Destroy() noexcept { // destroy the contained value, if any
if constexpr (!conjunction_v<is_trivially_destructible<_Types>...>) {
_Variant_raw_visit(index(), _Storage(), [](auto _Ref) noexcept {
if constexpr (decltype(_Ref)::_Idx != variant_npos) {
_Destroy_in_place(_Ref._Val);
}
});
2019-09-05 01:57:56 +03:00
}
}
void _Reset() noexcept { // transition to the valueless_by_exception state
_Destroy();
_Set_index(variant_npos);
}
template <size_t _Idx>
void _Reset() noexcept {
// transition to the valueless_by_exception state
// pre: _Idx == index()
2019-09-05 01:57:56 +03:00
if constexpr (_Idx != variant_npos) {
_Destroy<_Idx>();
_Set_index(variant_npos);
}
}
void _Construct_from(const _Variant_base& _That) noexcept(conjunction_v<is_nothrow_copy_constructible<_Types>...>) {
// copy _That's contained value into *this
// pre: valueless_by_exception()
_Variant_raw_visit(_That.index(), _That._Storage(), _Variant_construct_visitor<_Types...>{*this});
}
void _Construct_from(_Variant_base&& _That) noexcept(conjunction_v<is_nothrow_move_constructible<_Types>...>) {
// move _That's contained value into *this
// pre: valueless_by_exception()
_Variant_raw_visit(_That.index(), _STD move(_That)._Storage(), _Variant_construct_visitor<_Types...>{*this});
}
void _Assign_from(const _Variant_base& _That) noexcept(
conjunction_v<is_nothrow_copy_constructible<_Types>..., is_nothrow_copy_assignable<_Types>...>) {
// copy assign _That's contained value (if any) into *this
_Variant_raw_visit(_That.index(), _That._Storage(), _Variant_assign_visitor<_Types...>{*this});
}
void _Assign_from(_Variant_base&& _That) noexcept(
conjunction_v<is_nothrow_move_constructible<_Types>..., is_nothrow_move_assignable<_Types>...>) {
// move assign _That's contained value (if any) into *this
_Variant_raw_visit(_That.index(), _STD move(_That)._Storage(), _Variant_assign_visitor<_Types...>{*this});
}
};
template <class... _Types>
struct _Variant_destroy_layer_ : _Variant_base<_Types...> { // destruction behavior facade (non-trivial case)
using _Variant_base<_Types...>::_Variant_base;
~_Variant_destroy_layer_() noexcept { // Destroy contained value, if any
this->_Destroy();
}
_Variant_destroy_layer_() = default;
_Variant_destroy_layer_(const _Variant_destroy_layer_&) = default;
_Variant_destroy_layer_(_Variant_destroy_layer_&&) = default;
_Variant_destroy_layer_& operator=(const _Variant_destroy_layer_&) = default;
_Variant_destroy_layer_& operator=(_Variant_destroy_layer_&&) = default;
};
template <class... _Types>
using _Variant_destroy_layer = conditional_t<conjunction_v<is_trivially_destructible<_Types>...>,
_Variant_base<_Types...>, _Variant_destroy_layer_<_Types...>>;
// CLASS TEMPLATE variant
Changes to support the compiler portion of P1152R4 "deprecating volatile" (#674) * Updates for MSVC implementation of P1152R4 "deprecating volatile" * Enable volatile deprecation warnings in STL's std and libcxx test suites * `<any>`: `any_cast<T>` now returns `remove_cv_t<T>` because it's silly to have a cv-qualified return type (LWG issue submitted) * `<optional>`: `optional<T>::value_or` now returns `remove_cv_t<T>` because it's silly to have a cv-qualified return type (LWG issue submitted). * `<type_traits>`: suppress deprecation warnings around `_Implicitly_convert_to` so `_Implicitly_convert_to<volatile meow>(woof)` doesn't warn * `<variant>`: Suppress deprecation warnings when forming the "imaginary" overload set `FUN` for the `variant(T&&)` constructor. * Add the new warning C5215 "'%s' a function parameter with volatile qualified type is deprecated in C++20" to libc++'s "suppress deprecation warnings" macro and update llvm submodule reference. * Skip libc++ test `containers/sequences/deque/deque.modifiers/insert_iter_iter.pass.cpp` after seeing one timeout too many in Contest logs. * Suppress C5215 in `tr1/include/tfuns.h` which uses volatile function parameters, and in `tr1/functional4` altogether. * Update skips for two libc++ tests that changed suffixes from `.sh.cpp` to `.pass.cpp`. * Add a throwaway `addCompileFlags` function to `LibcxxTestFormat` to enable libc++ to continue working after upstream changes to pass configuration to the filesystem tests which we do not run.
2020-04-04 04:20:24 +03:00
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-volatile"
#else // ^^^ Clang / not Clang vvv
#pragma warning(push)
#pragma warning(disable : 5215) // '%s' a function parameter with volatile qualified type is deprecated in C++20
#endif // __clang__
2019-09-05 01:57:56 +03:00
template <size_t _Idx, class _Ty>
struct _Variant_init_single_overload {
using _FTy = _Meta_list<integral_constant<size_t, _Idx>, _Ty> (*)(_Ty);
operator _FTy();
};
Changes to support the compiler portion of P1152R4 "deprecating volatile" (#674) * Updates for MSVC implementation of P1152R4 "deprecating volatile" * Enable volatile deprecation warnings in STL's std and libcxx test suites * `<any>`: `any_cast<T>` now returns `remove_cv_t<T>` because it's silly to have a cv-qualified return type (LWG issue submitted) * `<optional>`: `optional<T>::value_or` now returns `remove_cv_t<T>` because it's silly to have a cv-qualified return type (LWG issue submitted). * `<type_traits>`: suppress deprecation warnings around `_Implicitly_convert_to` so `_Implicitly_convert_to<volatile meow>(woof)` doesn't warn * `<variant>`: Suppress deprecation warnings when forming the "imaginary" overload set `FUN` for the `variant(T&&)` constructor. * Add the new warning C5215 "'%s' a function parameter with volatile qualified type is deprecated in C++20" to libc++'s "suppress deprecation warnings" macro and update llvm submodule reference. * Skip libc++ test `containers/sequences/deque/deque.modifiers/insert_iter_iter.pass.cpp` after seeing one timeout too many in Contest logs. * Suppress C5215 in `tr1/include/tfuns.h` which uses volatile function parameters, and in `tr1/functional4` altogether. * Update skips for two libc++ tests that changed suffixes from `.sh.cpp` to `.pass.cpp`. * Add a throwaway `addCompileFlags` function to `LibcxxTestFormat` to enable libc++ to continue working after upstream changes to pass configuration to the filesystem tests which we do not run.
2020-04-04 04:20:24 +03:00
#ifdef __clang__
#pragma clang diagnostic pop
#else // ^^^ Clang / not Clang vvv
#pragma warning(pop)
#endif // __clang__
2019-09-05 01:57:56 +03:00
template <class _Indices, class... _Types>
struct _Variant_init_overload_set_;
template <size_t... _Indices, class... _Types>
struct _Variant_init_overload_set_<index_sequence<_Indices...>, _Types...>
: _Variant_init_single_overload<_Indices, _Types>... {};
template <class... _Types>
using _Variant_init_overload_set = _Variant_init_overload_set_<index_sequence_for<_Types...>, _Types...>;
template <class Enable, class _Ty, class... _Types>
struct _Variant_init_helper { // failure case (has no member "type")
};
template <class _Ty, class... _Types>
struct _Variant_init_helper<void_t<decltype(_Variant_init_overload_set<_Types...>{}(_STD declval<_Ty>()))>, _Ty,
_Types...> {
// perform overload resolution to determine the unique alternative that should be initialized in
// variant<_Types...> from an argument expression with type and value category _Ty
2019-09-05 01:57:56 +03:00
using type = decltype(_Variant_init_overload_set<_Types...>{}(_STD declval<_Ty>()));
};
template <class _Ty, class... _Types> // extract the type from _Variant_init_helper
using _Variant_init_type = _Meta_front<_Meta_pop_front<typename _Variant_init_helper<void, _Ty, _Types...>::type>>;
template <class _Ty, class... _Types> // extract the index from _Variant_init_helper
using _Variant_init_index = _Meta_front<typename _Variant_init_helper<void, _Ty, _Types...>::type>;
template <class>
struct _Is_in_place_index_specialization : false_type {};
template <size_t _Idx>
struct _Is_in_place_index_specialization<in_place_index_t<_Idx>> : true_type {};
template <class... _Types>
class variant : private _SMF_control<_Variant_destroy_layer<_Types...>, _Types...> { // discriminated union
public:
static_assert(conjunction_v<is_object<_Types>..., negation<is_array<_Types>>..., is_destructible<_Types>...>,
"variant<Types...> requires all of the Types to meet the Cpp17Destructible requirements "
"N4828 [variant.variant]/2.");
static_assert(sizeof...(_Types) > 0,
"variant<> (with no template arguments) may not be instantiated (N4835 [variant.variant]/3).");
2019-09-05 01:57:56 +03:00
using _Mybase = _SMF_control<_Variant_destroy_layer<_Types...>, _Types...>;
// constructors [variant.ctor]
template <class _First = _Meta_front<variant>, enable_if_t<is_default_constructible_v<_First>, int> = 0>
constexpr variant() noexcept(is_nothrow_default_constructible_v<_First>)
: _Mybase(in_place_index<0>) { // value-initialize alternative 0
}
template <class _Ty,
enable_if_t<sizeof...(_Types) != 0 //
&& !is_same_v<_Remove_cvref_t<_Ty>, variant> //
&& !_Is_specialization_v<_Remove_cvref_t<_Ty>, in_place_type_t> //
&& !_Is_in_place_index_specialization<_Remove_cvref_t<_Ty>>::value //
&& is_constructible_v<_Variant_init_type<_Ty, _Types...>, _Ty>, //
int> = 0>
constexpr variant(_Ty&& _Obj) noexcept(is_nothrow_constructible_v<_Variant_init_type<_Ty, _Types...>, _Ty>)
: _Mybase(in_place_index<_Variant_init_index<_Ty, _Types...>::value>, static_cast<_Ty&&>(_Obj)) {
// initialize to the type selected by passing _Obj to the overload set f(Types)...
}
template <class _Ty, class... _UTypes, class _Idx = _Meta_find_unique_index<variant, _Ty>,
enable_if_t<_Idx::value != _Meta_npos && is_constructible_v<_Ty, _UTypes...>, int> = 0>
constexpr explicit variant(in_place_type_t<_Ty>, _UTypes&&... _Args) noexcept(
is_nothrow_constructible_v<_Ty, _UTypes...>) // strengthened
: _Mybase(in_place_index<_Idx::value>, static_cast<_UTypes&&>(_Args)...) {
// initialize alternative _Ty from _Args...
}
template <class _Ty, class _Elem, class... _UTypes, class _Idx = _Meta_find_unique_index<variant, _Ty>,
enable_if_t<_Idx::value != _Meta_npos && is_constructible_v<_Ty, initializer_list<_Elem>&, _UTypes...>, int> =
0>
constexpr explicit variant(in_place_type_t<_Ty>, initializer_list<_Elem> _Ilist, _UTypes&&... _Args) noexcept(
is_nothrow_constructible_v<_Ty, initializer_list<_Elem>&, _UTypes...>) // strengthened
: _Mybase(in_place_index<_Idx::value>, _Ilist, static_cast<_UTypes&&>(_Args)...) {
// initialize alternative _Ty from _Ilist and _Args...
}
template <size_t _Idx, class... _UTypes,
enable_if_t<is_constructible_v<_Meta_at_c<variant, _Idx>, _UTypes...>, int> = 0>
constexpr explicit variant(in_place_index_t<_Idx>, _UTypes&&... _Args) noexcept(
is_nothrow_constructible_v<_Meta_at_c<variant, _Idx>, _UTypes...>) // strengthened
: _Mybase(in_place_index<_Idx>, static_cast<_UTypes&&>(_Args)...) { // initialize alternative _Idx from _Args...
}
template <size_t _Idx, class _Elem, class... _UTypes,
enable_if_t<is_constructible_v<_Meta_at_c<variant, _Idx>, initializer_list<_Elem>&, _UTypes...>, int> = 0>
constexpr explicit variant(in_place_index_t<_Idx>, initializer_list<_Elem> _Ilist, _UTypes&&... _Args) noexcept(
is_constructible_v<_Meta_at_c<variant, _Idx>, initializer_list<_Elem>&, _UTypes...>) // strengthened
: _Mybase(in_place_index<_Idx>, _Ilist, static_cast<_UTypes&&>(_Args)...) {
// initialize alternative _Idx from _Ilist and _Args...
}
// assignment [variant.assign]
template <class _Ty, enable_if_t<!is_same_v<_Remove_cvref_t<_Ty>, variant> //
&& is_constructible_v<_Variant_init_type<_Ty, _Types...>, _Ty> //
&& is_assignable_v<_Variant_init_type<_Ty, _Types...>&, _Ty>, //
int> = 0>
variant& operator=(_Ty&& _Obj) noexcept(is_nothrow_assignable_v<_Variant_init_type<_Ty, _Types...>&, _Ty>&&
is_nothrow_constructible_v<_Variant_init_type<_Ty, _Types...>, _Ty>) {
// assign/emplace the alternative chosen by overload resolution of _Obj with f(_Types)...
constexpr size_t _TargetIdx = _Variant_init_index<_Ty, _Types...>::value;
if (index() == _TargetIdx) {
auto& _Target = _Variant_raw_get<_TargetIdx>(_Storage());
_Target = static_cast<_Ty&&>(_Obj);
} else {
using _TargetTy = _Variant_init_type<_Ty, _Types...>;
if constexpr (_Variant_should_directly_construct_v<_TargetTy, _Ty>) {
this->_Reset();
_Emplace_valueless<_TargetIdx>(static_cast<_Ty&&>(_Obj));
} else {
_TargetTy _Temp(static_cast<_Ty&&>(_Obj));
this->_Reset();
_Emplace_valueless<_TargetIdx>(_STD move(_Temp));
}
}
return *this;
}
// modifiers [variant.mod]
using _Mybase::_Storage;
template <class _Ty, class... _ArgTypes, size_t _Idx = _Meta_find_unique_index<variant, _Ty>::value,
enable_if_t<_Idx != _Meta_npos && is_constructible_v<_Ty, _ArgTypes...>, int> = 0>
_Ty& emplace(_ArgTypes&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _ArgTypes...>) /* strengthened */ {
// emplace alternative _Ty from _Args...
this->_Reset();
return _Emplace_valueless<_Idx>(static_cast<_ArgTypes&&>(_Args)...);
}
template <class _Ty, class _Elem, class... _ArgTypes, size_t _Idx = _Meta_find_unique_index<variant, _Ty>::value,
enable_if_t<_Idx != _Meta_npos && is_constructible_v<_Ty, initializer_list<_Elem>&, _ArgTypes...>, int> = 0>
_Ty& emplace(initializer_list<_Elem> _Ilist, _ArgTypes&&... _Args) noexcept(
is_nothrow_constructible_v<_Ty, initializer_list<_Elem>&, _ArgTypes...>) /* strengthened */ {
// emplace alternative _Ty from _Ilist and _Args...
this->_Reset();
return _Emplace_valueless<_Idx>(_Ilist, static_cast<_ArgTypes&&>(_Args)...);
}
template <size_t _Idx, class... _ArgTypes,
enable_if_t<is_constructible_v<_Meta_at_c<variant, _Idx>, _ArgTypes...>, int> = 0>
_Meta_at_c<variant, _Idx>& emplace(_ArgTypes&&... _Args) noexcept(
is_nothrow_constructible_v<_Meta_at_c<variant, _Idx>, _ArgTypes...>) /* strengthened */ {
// emplace alternative _Idx from _Args...
this->_Reset();
return _Emplace_valueless<_Idx>(static_cast<_ArgTypes&&>(_Args)...);
}
template <size_t _Idx, class _Elem, class... _ArgTypes,
enable_if_t<is_constructible_v<_Meta_at_c<variant, _Idx>, initializer_list<_Elem>&, _ArgTypes...>, int> = 0>
_Meta_at_c<variant, _Idx>& emplace(initializer_list<_Elem> _Ilist, _ArgTypes&&... _Args) noexcept(
is_nothrow_constructible_v<_Meta_at_c<variant, _Idx>, initializer_list<_Elem>&,
_ArgTypes...>) /* strengthened */ {
// emplace alternative _Idx from _Ilist and _Args...
this->_Reset();
return _Emplace_valueless<_Idx>(_Ilist, static_cast<_ArgTypes&&>(_Args)...);
}
// value status [variant.status]
using _Mybase::index;
using _Mybase::valueless_by_exception;
// swap [variant.swap]
void swap(variant& _That) noexcept(
conjunction_v<is_nothrow_move_constructible<_Types>..., is_nothrow_swappable<_Types>...>) {
// exchange the contained values if *this and _That hold the same alternative, otherwise exchange the values of
// the variants themselves
static_assert(conjunction_v<is_move_constructible<_Types>...>,
"variant<Types...>::swap requires all of the Types... to be move constructible. (N4835 [variant.swap]/1)");
2019-09-05 01:57:56 +03:00
static_assert(disjunction_v<negation<is_move_constructible<_Types>>..., conjunction<is_swappable<_Types>...>>,
"variant<Types...>::swap requires all of the Types... to be swappable. (N4835 [variant.swap]/1)");
2019-09-05 01:57:56 +03:00
if constexpr (conjunction_v<_Is_trivially_swappable<_Types>...>) {
using _BaseTy = _Variant_base<_Types...>;
_STD swap(static_cast<_BaseTy&>(*this), static_cast<_BaseTy&>(_That));
} else if constexpr (sizeof...(_Types) < 32) {
// Limit the size of variants that use this quadratic code size implementation of swap.
_Variant_raw_visit(index(), _Storage(),
[this, &_That](auto _My_ref)
#ifndef __EDG__ // TRANSITION, VSO-897887
2019-09-05 01:57:56 +03:00
noexcept(conjunction_v<is_nothrow_move_constructible<_Types>..., is_nothrow_swappable<_Types>...>)
#endif // TRANSITION, VSO-897887
2019-09-05 01:57:56 +03:00
{
_Variant_raw_visit(_That.index(), _That._Storage(),
[this, &_That, _My_ref](auto _That_ref)
#ifndef __EDG__ // TRANSITION, VSO-897887
2019-09-05 01:57:56 +03:00
noexcept(conjunction_v<is_nothrow_move_constructible<_Types>...,
is_nothrow_swappable<_Types>...>)
#endif // TRANSITION, VSO-897887
2019-09-05 01:57:56 +03:00
{
constexpr size_t _That_idx = decltype(_That_ref)::_Idx;
#ifdef __EDG__ // TRANSITION, VSO-657455
constexpr size_t _My_idx = decltype(_My_ref)::_Idx + 0 * _That_idx;
2019-09-05 01:57:56 +03:00
#else // ^^^ workaround ^^^ / vvv no workaround vvv
constexpr size_t _My_idx = decltype(_My_ref)::_Idx;
#endif // TRANSITION, VSO-657455
2019-09-05 01:57:56 +03:00
if constexpr (_My_idx == _That_idx) { // Same alternatives...
if constexpr (_My_idx != variant_npos) { // ...and not valueless, swap directly
_Swap_adl(_My_ref._Val, _That_ref._Val);
}
} else if constexpr (_My_idx == variant_npos) { // *this is valueless, _That is not
this->_Emplace_valueless<_That_idx>(_STD move(_That_ref._Val));
_That.template _Reset<_That_idx>();
} else if constexpr (_That_idx == variant_npos) { // _That is valueless, *this is not
_That._Emplace_valueless<_My_idx>(_STD move(_My_ref._Val));
this->template _Reset<_My_idx>();
} else { // different non-valueless alternatives
#ifdef __EDG__ // TRANSITION, VSO-657455
2019-09-05 01:57:56 +03:00
using _Workaround = enable_if_t<_That_idx != variant_npos, decltype(_My_ref._Val)>;
auto _Tmp = _STD move(static_cast<_Workaround>(_My_ref._Val));
#else // ^^^ workaround ^^^ / vvv no workaround vvv
auto _Tmp = _STD move(_My_ref._Val);
#endif // TRANSITION, VSO-657455
2019-09-05 01:57:56 +03:00
this->template _Reset<_My_idx>();
this->_Emplace_valueless<_That_idx>(_STD move(_That_ref._Val));
_That.template _Reset<_That_idx>();
_That._Emplace_valueless<_My_idx>(_STD move(_Tmp));
}
});
});
} else {
if (this->_Which == _That._Which) {
_Variant_raw_visit(static_cast<size_t>(this->_Which), _That._Storage(),
[this](auto _Ref)
#ifndef __EDG__ // TRANSITION, VSO-897887
2019-09-05 01:57:56 +03:00
noexcept(conjunction_v<is_nothrow_swappable<_Types>...>)
#endif // TRANSITION, VSO-897887
2019-09-05 01:57:56 +03:00
{
constexpr size_t _Idx = decltype(_Ref)::_Idx;
if constexpr (_Idx != variant_npos) {
_Swap_adl(_Variant_raw_get<_Idx>(this->_Storage()), _Ref._Val);
}
});
} else {
variant _Tmp = _STD move(*this);
this->_Emplace_from(_STD move(_That));
_That._Emplace_from(_STD move(_Tmp));
}
}
}
private:
template <size_t _Idx, class... _ArgTypes>
_Meta_at_c<variant, _Idx>& _Emplace_valueless(_ArgTypes&&... _Args) noexcept(
is_nothrow_constructible_v<_Meta_at_c<variant, _Idx>, _ArgTypes...>) {
// initialize alternative _Idx from _Args...
// pre: valueless_by_exception()
auto& _Obj = _Variant_raw_get<_Idx>(_Storage());
_Construct_in_place(_Obj, static_cast<_ArgTypes&&>(_Args)...);
this->_Set_index(_Idx);
return _Obj;
}
void _Emplace_from(variant&& _That) noexcept(conjunction_v<is_nothrow_move_constructible<_Types>...>) {
// steal the contained value from _That
this->_Reset();
_Variant_raw_visit(_That.index(), _That._Storage(),
[this](auto _Ref)
#ifndef __EDG__ // TRANSITION, VSO-897887
2019-09-05 01:57:56 +03:00
noexcept(conjunction_v<is_nothrow_move_constructible<_Types>...>)
#endif // TRANSITION, VSO-897887
2019-09-05 01:57:56 +03:00
{
constexpr size_t _Idx = decltype(_Ref)::_Idx;
if constexpr (_Idx != variant_npos) {
this->_Emplace_valueless<_Idx>(_STD move(_Ref._Val));
}
});
}
};
// VALUE ACCESS [variant.get]
template <class _Ty, class... _Types>
_NODISCARD constexpr bool holds_alternative(
const variant<_Types...>& _Var) noexcept { // true iff _Var holds alternative _Ty
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
static_assert(_Idx != _Meta_npos, "holds_alternative<T>(const variant<Types...>&) requires T to occur exactly "
"once in Types. (N4835 [variant.get]/1)");
2019-09-05 01:57:56 +03:00
return _Var.index() == _Idx;
}
template <size_t _Idx, class... _Types>
_NODISCARD constexpr decltype(auto) get(
variant<_Types...>& _Var) { // access the contained value of _Var if its _Idx-th alternative is active
static_assert(_Idx < sizeof...(_Types), "variant index out of bounds");
if (_Var.index() == _Idx) {
return _Variant_raw_get<_Idx>(_Var._Storage());
}
_Throw_bad_variant_access();
}
template <size_t _Idx, class... _Types>
_NODISCARD constexpr decltype(auto) get(
variant<_Types...>&& _Var) { // access the contained value of _Var if its _Idx-th alternative is active
static_assert(_Idx < sizeof...(_Types), "variant index out of bounds");
if (_Var.index() == _Idx) {
return _Variant_raw_get<_Idx>(_STD move(_Var)._Storage());
}
_Throw_bad_variant_access();
}
template <size_t _Idx, class... _Types>
_NODISCARD constexpr decltype(auto) get(
const variant<_Types...>& _Var) { // access the contained value of _Var if its _Idx-th alternative is active
static_assert(_Idx < sizeof...(_Types), "variant index out of bounds");
if (_Var.index() == _Idx) {
return _Variant_raw_get<_Idx>(_Var._Storage());
}
_Throw_bad_variant_access();
}
template <size_t _Idx, class... _Types>
_NODISCARD constexpr decltype(auto) get(
const variant<_Types...>&& _Var) { // access the contained value of _Var if its _Idx-th alternative is active
static_assert(_Idx < sizeof...(_Types), "variant index out of bounds");
if (_Var.index() == _Idx) {
return _Variant_raw_get<_Idx>(_STD move(_Var)._Storage());
}
_Throw_bad_variant_access();
}
template <class _Ty, class... _Types>
_NODISCARD constexpr decltype(auto) get(
variant<_Types...>& _Var) { // access the contained value of _Var if its alternative _Ty is active
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
static_assert(_Idx < sizeof...(_Types),
"get<T>(variant<Types...>&) requires T to occur exactly once in Types. (N4835 [variant.get]/5)");
2019-09-05 01:57:56 +03:00
return _STD get<_Idx>(_Var);
}
template <class _Ty, class... _Types>
_NODISCARD constexpr decltype(auto) get(
variant<_Types...>&& _Var) { // access the contained value of _Var if its alternative _Ty is active
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
static_assert(_Idx < sizeof...(_Types),
"get<T>(variant<Types...>&&) requires T to occur exactly once in Types. (N4835 [variant.get]/5)");
2019-09-05 01:57:56 +03:00
return _STD get<_Idx>(_STD move(_Var));
}
template <class _Ty, class... _Types>
_NODISCARD constexpr decltype(auto) get(
const variant<_Types...>& _Var) { // access the contained value of _Var if its alternative _Ty is active
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
static_assert(_Idx < sizeof...(_Types),
"get<T>(const variant<Types...>&) requires T to occur exactly once in Types. (N4835 [variant.get]/5)");
2019-09-05 01:57:56 +03:00
return _STD get<_Idx>(_Var);
}
template <class _Ty, class... _Types>
_NODISCARD constexpr decltype(auto) get(
const variant<_Types...>&& _Var) { // access the contained value of _Var if its alternative _Ty is active
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
static_assert(_Idx < sizeof...(_Types),
"get<T>(const variant<Types...>&&) requires T to occur exactly once in Types. (N4835 [variant.get]/5)");
2019-09-05 01:57:56 +03:00
return _STD get<_Idx>(_STD move(_Var));
}
template <size_t _Idx, class... _Types>
_NODISCARD constexpr auto get_if(
variant<_Types...>* _Ptr) noexcept { // get the address of *_Ptr's contained value if it holds alternative _Idx
static_assert(_Idx < sizeof...(_Types), "variant index out of bounds");
return _Ptr && _Ptr->index() == _Idx ? _STD addressof(_Variant_raw_get<_Idx>(_Ptr->_Storage())) : nullptr;
}
template <size_t _Idx, class... _Types>
_NODISCARD constexpr auto get_if(const variant<_Types...>*
_Ptr) noexcept { // get the address of *_Ptr's contained value if it holds alternative _Idx
static_assert(_Idx < sizeof...(_Types), "variant index out of bounds");
return _Ptr && _Ptr->index() == _Idx ? _STD addressof(_Variant_raw_get<_Idx>(_Ptr->_Storage())) : nullptr;
}
template <class _Ty, class... _Types>
_NODISCARD constexpr add_pointer_t<_Ty> get_if(
variant<_Types...>* _Ptr) noexcept { // get the address of *_Ptr's contained value if it holds alternative _Ty
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
static_assert(_Idx != _Meta_npos,
"get_if<T>(variant<Types...> *) requires T to occur exactly once in Types. (N4835 [variant.get]/9)");
2019-09-05 01:57:56 +03:00
return _STD get_if<_Idx>(_Ptr);
}
template <class _Ty, class... _Types>
_NODISCARD constexpr add_pointer_t<const _Ty> get_if(
const variant<_Types...>* _Ptr) noexcept { // get the address of *_Ptr's contained value if it holds alternative _Ty
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
static_assert(_Idx != _Meta_npos,
"get_if<T>(const variant<Types...> *) requires T to occur exactly once in Types. (N4835 [variant.get]/9)");
2019-09-05 01:57:56 +03:00
return _STD get_if<_Idx>(_Ptr);
}
// RELATIONAL OPERATORS [variant.relops]
template <class _Op, class... _Types>
struct _Variant_relop_visitor { // evaluate _Op with the contained value of two variants that hold the same alternative
const _Variant_storage<_Types...>& _Left;
template <class _Ty, size_t _Idx>
_NODISCARD constexpr bool operator()(_Tagged<const _Ty&, _Idx> _Right) const noexcept(
disjunction_v<bool_constant<_Idx == variant_npos>, is_nothrow_invocable_r<bool, _Op, const _Ty&, const _Ty&>>) {
// determine the relationship between the stored values of _Left and _Right
// pre: _Left.index() == _Idx && _Right.index() == _Idx
if constexpr (_Idx != variant_npos) {
return _Op{}(_Variant_raw_get<_Idx>(_Left), _Right._Val);
} else { // return whatever _Op returns for equal values
(void) _Right; // TRANSITION, DevCom-1004719
2019-09-05 01:57:56 +03:00
return _Op{}(0, 0);
}
}
};
template <class... _Types>
_NODISCARD constexpr bool operator==(const variant<_Types...>& _Left, const variant<_Types...>& _Right) noexcept(
conjunction_v<is_nothrow_invocable_r<bool, equal_to<>, const _Types&, const _Types&>...>) /* strengthened */ {
// determine if the arguments are both valueless or contain equal values
using _Visitor = _Variant_relop_visitor<equal_to<>, _Types...>;
const size_t _Right_index = _Right.index();
return _Left.index() == _Right_index
&& _Variant_raw_visit(_Right_index, _Right._Storage(), _Visitor{_Left._Storage()});
}
template <class... _Types>
_NODISCARD constexpr bool operator!=(const variant<_Types...>& _Left, const variant<_Types...>& _Right) noexcept(
conjunction_v<is_nothrow_invocable_r<bool, not_equal_to<>, const _Types&, const _Types&>...>) /* strengthened */ {
// determine if the arguments have different active alternatives or contain unequal values
using _Visitor = _Variant_relop_visitor<not_equal_to<>, _Types...>;
const size_t _Right_index = _Right.index();
return _Left.index() != _Right_index
|| _Variant_raw_visit(_Right_index, _Right._Storage(), _Visitor{_Left._Storage()});
}
template <class... _Types>
_NODISCARD constexpr bool operator<(const variant<_Types...>& _Left, const variant<_Types...>& _Right) noexcept(
conjunction_v<is_nothrow_invocable_r<bool, less<>, const _Types&, const _Types&>...>) /* strengthened */ {
// determine if _Left has a lesser index(), or equal index() and lesser
// contained value than _Right
using _Visitor = _Variant_relop_visitor<less<>, _Types...>;
const size_t _Left_offset = _Left.index() + 1;
const size_t _Right_offset = _Right.index() + 1;
return _Left_offset < _Right_offset
|| (_Left_offset == _Right_offset
&& _Variant_raw_visit(_Right_offset - 1, _Right._Storage(), _Visitor{_Left._Storage()}));
}
template <class... _Types>
_NODISCARD constexpr bool operator>(const variant<_Types...>& _Left, const variant<_Types...>& _Right) noexcept(
conjunction_v<is_nothrow_invocable_r<bool, greater<>, const _Types&, const _Types&>...>) /* strengthened */ {
// determine if _Left has a greater index(), or equal index() and
// greater contained value than _Right
using _Visitor = _Variant_relop_visitor<greater<>, _Types...>;
const size_t _Left_offset = _Left.index() + 1;
const size_t _Right_offset = _Right.index() + 1;
return _Left_offset > _Right_offset
|| (_Left_offset == _Right_offset
&& _Variant_raw_visit(_Right_offset - 1, _Right._Storage(), _Visitor{_Left._Storage()}));
}
template <class... _Types>
_NODISCARD constexpr bool operator<=(const variant<_Types...>& _Left, const variant<_Types...>& _Right) noexcept(
conjunction_v<is_nothrow_invocable_r<bool, less_equal<>, const _Types&, const _Types&>...>) /* strengthened */ {
// determine if _Left's index() is less than _Right's, or equal and
// _Left contains a value less than or equal to _Right
using _Visitor = _Variant_relop_visitor<less_equal<>, _Types...>;
const size_t _Left_offset = _Left.index() + 1;
const size_t _Right_offset = _Right.index() + 1;
return _Left_offset < _Right_offset
|| (_Left_offset == _Right_offset
&& _Variant_raw_visit(_Right_offset - 1, _Right._Storage(), _Visitor{_Left._Storage()}));
}
template <class... _Types>
_NODISCARD constexpr bool operator>=(const variant<_Types...>& _Left, const variant<_Types...>& _Right) noexcept(
conjunction_v<is_nothrow_invocable_r<bool, greater_equal<>, const _Types&, const _Types&>...>) /* strengthened */ {
// determine if _Left's index() is greater than _Right's, or equal and
// _Left contains a value greater than or equal to _Right
using _Visitor = _Variant_relop_visitor<greater_equal<>, _Types...>;
const size_t _Left_offset = _Left.index() + 1;
const size_t _Right_offset = _Right.index() + 1;
return _Left_offset > _Right_offset
|| (_Left_offset == _Right_offset
&& _Variant_raw_visit(_Right_offset - 1, _Right._Storage(), _Visitor{_Left._Storage()}));
}
// VISITATION [variant.visit]
template <class... _Variants>
inline constexpr size_t _Variant_total_states =
(size_t{1} * ... * (variant_size_v<_Variants> + 1)); // +1 to account for the valueless state
_NODISCARD constexpr size_t _Variant_visit_index1(const size_t _Acc) noexcept {
return _Acc;
}
template <class _FirstTy, class... _RestTys>
_NODISCARD constexpr size_t _Variant_visit_index1(size_t _Acc, const _FirstTy& _First,
const _RestTys&... _Rest) noexcept { // calculate a canonical index from the biased indices of the variants _First
// and _Rest...
_Acc += (_First.index() + 1) * _Variant_total_states<_RestTys...>;
return _Variant_visit_index1(_Acc, _Rest...);
}
template <class _Callable, class... _Types>
using _Variant_visit_result_t =
<functional> Avoid layers of forwards in invoke (#585) This change removes the last "nonessential" stack frame that would be encountered for threads, and makes the debugging experience for several standard components, like `std::function`, nicer by not needing so many step into / step out of sequences. ![image](https://user-images.githubusercontent.com/1544943/75860992-92b2b000-5db1-11ea-90f1-d7ec3adde21b.png) 1. CRT's thread entry point 2. std::thread's entry point that staples the parameters on 3. invoke 4. already user code yay! Hopefully this makes debug codegen better too, particularly now that ranges hammers invoke even harder than we used to. I didn't change any of the metaprogramming for deciding which strategy to use -- I like that we don't use SFINAE to make that decision, and don't really consider myself competent enough a metaprogrammer to confidently make changes there. I just make `_Invoker_xyz` also supply a strategy value that is fed into `if constexpr`. @CaseyCarter suggested some larger changes which might have sped up metaprogramming I tried, but ran into issues because one can't deduce the calling convention of pointers-to-member-function. I've also made a one time exception to our usual policy of using `std::forward` rather than `static_cast`, with the rationale that `invoke` is hammered *everywhere*, and also by traits, and we want the debugging experience of that to be as nice as possible. (Also drive-by removed unnecessary compilation of iostreams from the `Dev10_729003_bind_reference_wrapper` I noticed debugging a test case failure) Co-authored-by: Casey Carter <cartec69@gmail.com>
2020-03-06 02:36:26 +03:00
decltype(_STD invoke(_STD declval<_Callable>(), _Variant_raw_get<0>(_STD declval<_Types>()._Storage())...));
2019-09-05 01:57:56 +03:00
template <class>
struct _Variant_dispatcher;
template <size_t... _Is>
struct _Variant_dispatcher<index_sequence<_Is...>> {
template <class _Ret, class _Callable, class... _Types, bool _Any_valueless = ((_Is == 0) || ...)>
_NODISCARD static constexpr _Ret _Dispatch2(_Callable&& _Obj, _Types&&... _Args) {
2019-09-05 01:57:56 +03:00
if constexpr (_Any_valueless) {
(void) _Obj; // TRANSITION, DevCom-1004719
((void) _Args, ...); // TRANSITION, DevCom-1004719
2019-09-05 01:57:56 +03:00
_Throw_bad_variant_access();
}
#if _HAS_CXX20
else if constexpr (is_void_v<_Ret>) {
<functional> Avoid layers of forwards in invoke (#585) This change removes the last "nonessential" stack frame that would be encountered for threads, and makes the debugging experience for several standard components, like `std::function`, nicer by not needing so many step into / step out of sequences. ![image](https://user-images.githubusercontent.com/1544943/75860992-92b2b000-5db1-11ea-90f1-d7ec3adde21b.png) 1. CRT's thread entry point 2. std::thread's entry point that staples the parameters on 3. invoke 4. already user code yay! Hopefully this makes debug codegen better too, particularly now that ranges hammers invoke even harder than we used to. I didn't change any of the metaprogramming for deciding which strategy to use -- I like that we don't use SFINAE to make that decision, and don't really consider myself competent enough a metaprogrammer to confidently make changes there. I just make `_Invoker_xyz` also supply a strategy value that is fed into `if constexpr`. @CaseyCarter suggested some larger changes which might have sped up metaprogramming I tried, but ran into issues because one can't deduce the calling convention of pointers-to-member-function. I've also made a one time exception to our usual policy of using `std::forward` rather than `static_cast`, with the rationale that `invoke` is hammered *everywhere*, and also by traits, and we want the debugging experience of that to be as nice as possible. (Also drive-by removed unnecessary compilation of iostreams from the `Dev10_729003_bind_reference_wrapper` I noticed debugging a test case failure) Co-authored-by: Casey Carter <cartec69@gmail.com>
2020-03-06 02:36:26 +03:00
static_cast<void>(_STD invoke(
static_cast<_Callable&&>(_Obj), _Variant_raw_get<_Is - 1>(static_cast<_Types&&>(_Args)._Storage())...));
}
#endif // _HAS_CXX20
else {
<functional> Avoid layers of forwards in invoke (#585) This change removes the last "nonessential" stack frame that would be encountered for threads, and makes the debugging experience for several standard components, like `std::function`, nicer by not needing so many step into / step out of sequences. ![image](https://user-images.githubusercontent.com/1544943/75860992-92b2b000-5db1-11ea-90f1-d7ec3adde21b.png) 1. CRT's thread entry point 2. std::thread's entry point that staples the parameters on 3. invoke 4. already user code yay! Hopefully this makes debug codegen better too, particularly now that ranges hammers invoke even harder than we used to. I didn't change any of the metaprogramming for deciding which strategy to use -- I like that we don't use SFINAE to make that decision, and don't really consider myself competent enough a metaprogrammer to confidently make changes there. I just make `_Invoker_xyz` also supply a strategy value that is fed into `if constexpr`. @CaseyCarter suggested some larger changes which might have sped up metaprogramming I tried, but ran into issues because one can't deduce the calling convention of pointers-to-member-function. I've also made a one time exception to our usual policy of using `std::forward` rather than `static_cast`, with the rationale that `invoke` is hammered *everywhere*, and also by traits, and we want the debugging experience of that to be as nice as possible. (Also drive-by removed unnecessary compilation of iostreams from the `Dev10_729003_bind_reference_wrapper` I noticed debugging a test case failure) Co-authored-by: Casey Carter <cartec69@gmail.com>
2020-03-06 02:36:26 +03:00
return _STD invoke(
2019-09-05 01:57:56 +03:00
static_cast<_Callable&&>(_Obj), _Variant_raw_get<_Is - 1>(static_cast<_Types&&>(_Args)._Storage())...);
}
}
};
template <class _Ret, class _Ordinals, class _Callable, class _Variants>
2019-09-05 01:57:56 +03:00
struct _Variant_dispatch_table; // undefined
template <class _Ret, class... _Ordinals, class _Callable, class... _Variants>
struct _Variant_dispatch_table<_Ret, _Meta_list<_Ordinals...>, _Callable,
2019-09-05 01:57:56 +03:00
_Meta_list<_Variants...>> { // map from canonical index to visitation target
using _Dispatch_t = _Ret (*)(_Callable&&, _Variants&&...);
2019-09-05 01:57:56 +03:00
static constexpr _Dispatch_t _Array[] = {
&_Variant_dispatcher<_Ordinals>::template _Dispatch2<_Ret, _Callable, _Variants...>...};
2019-09-05 01:57:56 +03:00
};
template <class _Callable, class _IndexSequence, class... _Variants>
struct _Variant_single_visit_result; // undefined
template <class _Callable, size_t... _Idxs, class... _Variants>
struct _Variant_single_visit_result<_Callable, index_sequence<_Idxs...>,
_Variants...> { // result type/category from invoking _Callable with the elements of
// _Variants... at (_Idxs - 1)...
<functional> Avoid layers of forwards in invoke (#585) This change removes the last "nonessential" stack frame that would be encountered for threads, and makes the debugging experience for several standard components, like `std::function`, nicer by not needing so many step into / step out of sequences. ![image](https://user-images.githubusercontent.com/1544943/75860992-92b2b000-5db1-11ea-90f1-d7ec3adde21b.png) 1. CRT's thread entry point 2. std::thread's entry point that staples the parameters on 3. invoke 4. already user code yay! Hopefully this makes debug codegen better too, particularly now that ranges hammers invoke even harder than we used to. I didn't change any of the metaprogramming for deciding which strategy to use -- I like that we don't use SFINAE to make that decision, and don't really consider myself competent enough a metaprogrammer to confidently make changes there. I just make `_Invoker_xyz` also supply a strategy value that is fed into `if constexpr`. @CaseyCarter suggested some larger changes which might have sped up metaprogramming I tried, but ran into issues because one can't deduce the calling convention of pointers-to-member-function. I've also made a one time exception to our usual policy of using `std::forward` rather than `static_cast`, with the rationale that `invoke` is hammered *everywhere*, and also by traits, and we want the debugging experience of that to be as nice as possible. (Also drive-by removed unnecessary compilation of iostreams from the `Dev10_729003_bind_reference_wrapper` I noticed debugging a test case failure) Co-authored-by: Casey Carter <cartec69@gmail.com>
2020-03-06 02:36:26 +03:00
using type = decltype(_STD invoke(_STD declval<_Callable>(),
2019-09-05 01:57:56 +03:00
_Variant_raw_get<_Idxs == 0 ? 0 : _Idxs - 1>(_STD declval<_Variants>()._Storage())...));
};
template <class _Callable, class _ListOfIndexVectors, class... _Variants>
struct _Variant_all_visit_results_same; // undefined
template <class _Callable, class... _IndexVectors, class... _Variants>
struct _Variant_all_visit_results_same<_Callable, _Meta_list<_IndexVectors...>, _Variants...>
: _All_same<typename _Variant_single_visit_result<_Callable, _IndexVectors,
_Variants...>::type...>::type { // true_type iff invocation of _Callable on the elements of _Variants with all
// sequences of indices in _IndexVectors has the same type and value category.
};
template <class _To, class _Callable, class _ListOfIndexVectors, class... _Variants>
struct _Variant_all_visit_results_implicitly_convertible; // undefined
template <class _To, class _Callable, class... _IndexVectors, class... _Variants>
struct _Variant_all_visit_results_implicitly_convertible<_To, _Callable, _Meta_list<_IndexVectors...>, _Variants...>
: _Convertible_from_all<_To,
typename _Variant_single_visit_result<_Callable, _IndexVectors, _Variants...>::type...>::type {
// true_type if invocation of _Callable on the elements of _Variants with all sequences of indices in _IndexVectors
// is implicitly convertible to _To.
};
2019-09-05 01:57:56 +03:00
template <int _Strategy>
struct _Visit_strategy;
template <>
struct _Visit_strategy<-1> { // Fallback strategy for visitations with too many total states for the
// following "switch" strategies.
template <class _Ret, class _ListOfIndexVectors, class _Callable, class... _Variants>
static constexpr _Ret _Visit2(
2019-09-05 01:57:56 +03:00
size_t _Idx, _Callable&& _Obj, _Variants&&... _Args) { // dispatch a visitation with many potential states
constexpr size_t _Size = _Variant_total_states<_Remove_cvref_t<_Variants>...>;
static_assert(_Size > 256);
constexpr auto& _Array =
_Variant_dispatch_table<_Ret, _ListOfIndexVectors, _Callable, _Meta_list<_Variants...>>::_Array;
2019-09-05 01:57:56 +03:00
return _Array[_Idx](static_cast<_Callable&&>(_Obj), static_cast<_Variants&&>(_Args)...);
}
};
template <>
struct _Visit_strategy<0> {
template <class _Ret, class, class _Callable>
static constexpr _Ret _Visit2(size_t, _Callable&& _Obj) { // dispatch a visitation with 4^0 potential states
if constexpr (is_void_v<_Ret>) {
return static_cast<void>(static_cast<_Callable&&>(_Obj)());
} else {
return static_cast<_Callable&&>(_Obj)();
}
2019-09-05 01:57:56 +03:00
}
};
#define _STL_CASE(n) \
case (n): \
if constexpr ((n) < _Size) { \
using _Indices = _Meta_at_c<_ListOfIndexVectors, (n)>; \
return _Variant_dispatcher<_Indices>::template _Dispatch2<_Ret, _Callable, _Variants...>( \
static_cast<_Callable&&>(_Obj), static_cast<_Variants&&>(_Args)...); \
} \
2019-09-05 01:57:56 +03:00
_STL_UNREACHABLE
#define _STL_VISIT_STAMP(stamper, n) \
constexpr size_t _Size = _Variant_total_states<_Remove_cvref_t<_Variants>...>; \
static_assert(_Size > (n) / 4 && _Size <= (n)); \
switch (_Idx) { \
stamper(0, _STL_CASE); \
default: \
_STL_UNREACHABLE; \
}
template <>
struct _Visit_strategy<1> {
template <class _Ret, class _ListOfIndexVectors, class _Callable, class... _Variants>
static constexpr _Ret _Visit2(
2019-09-05 01:57:56 +03:00
size_t _Idx, _Callable&& _Obj, _Variants&&... _Args) { // dispatch a visitation with 4^1 potential states
_STL_STAMP(4, _STL_VISIT_STAMP);
}
};
template <>
struct _Visit_strategy<2> {
template <class _Ret, class _ListOfIndexVectors, class _Callable, class... _Variants>
static constexpr _Ret _Visit2(
2019-09-05 01:57:56 +03:00
size_t _Idx, _Callable&& _Obj, _Variants&&... _Args) { // dispatch a visitation with 4^2 potential states
_STL_STAMP(16, _STL_VISIT_STAMP);
}
};
template <>
struct _Visit_strategy<3> {
template <class _Ret, class _ListOfIndexVectors, class _Callable, class... _Variants>
static constexpr _Ret _Visit2(
2019-09-05 01:57:56 +03:00
size_t _Idx, _Callable&& _Obj, _Variants&&... _Args) { // dispatch a visitation with 4^3 potential states
_STL_STAMP(64, _STL_VISIT_STAMP);
}
};
template <>
struct _Visit_strategy<4> {
template <class _Ret, class _ListOfIndexVectors, class _Callable, class... _Variants>
static constexpr _Ret _Visit2(
2019-09-05 01:57:56 +03:00
size_t _Idx, _Callable&& _Obj, _Variants&&... _Args) { // dispatch a visitation with 4^4 potential states
_STL_STAMP(256, _STL_VISIT_STAMP);
}
};
#undef _STL_VISIT_STAMP
#undef _STL_CASE
template <class... _Types>
variant<_Types...>& _As_variant_(variant<_Types...>&);
template <class... _Types>
const variant<_Types...>& _As_variant_(const variant<_Types...>&);
template <class... _Types>
variant<_Types...>&& _As_variant_(variant<_Types...>&&);
template <class... _Types>
const variant<_Types...>&& _As_variant_(const variant<_Types...>&&);
template <class _Ty>
using _As_variant = // Deduce variant specialization from a derived type
decltype(_As_variant_(_STD declval<_Ty>()));
template <size_t _Size, class _Ret, class _ListOfIndexVectors, class _Callable, class... _Variants>
constexpr _Ret _Visit_impl(_Callable&& _Obj, _Variants&&... _Args) {
constexpr int _Strategy =
_Size == 1 ? 0 : _Size <= 4 ? 1 : _Size <= 16 ? 2 : _Size <= 64 ? 3 : _Size <= 256 ? 4 : -1;
return _Visit_strategy<_Strategy>::template _Visit2<_Ret, _ListOfIndexVectors>(
_Variant_visit_index1(0, static_cast<_As_variant<_Variants>&>(_Args)...), static_cast<_Callable&&>(_Obj),
static_cast<_As_variant<_Variants>&&>(_Args)...);
}
2019-09-05 01:57:56 +03:00
template <class _Callable, class... _Variants, class = void_t<_As_variant<_Variants>...>>
constexpr _Variant_visit_result_t<_Callable, _As_variant<_Variants>...> visit(_Callable&& _Obj, _Variants&&... _Args) {
// Invoke _Obj with the contained values of _Args...
constexpr auto _Size = _Variant_total_states<_Remove_cvref_t<_As_variant<_Variants>>...>;
using _ListOfIndexLists =
_Meta_list<_Meta_as_list<make_index_sequence<1 + variant_size_v<_Remove_cvref_t<_As_variant<_Variants>>>>>...>;
using _ListOfIndexVectors =
_Meta_transform<_Meta_quote<_Meta_as_integer_sequence>, _Meta_cartesian_product<_ListOfIndexLists>>;
using _Ret = _Variant_visit_result_t<_Callable, _As_variant<_Variants>...>;
2019-09-05 01:57:56 +03:00
static_assert(_Variant_all_visit_results_same<_Callable, _ListOfIndexVectors, _As_variant<_Variants>...>::value,
"visit() requires the result of all potential invocations to have the same type and value category "
"(N4835 [variant.visit]/2).");
2019-09-05 01:57:56 +03:00
return _Visit_impl<_Size, _Ret, _ListOfIndexVectors>(
static_cast<_Callable&&>(_Obj), static_cast<_Variants&&>(_Args)...);
}
#if _HAS_CXX20
template <class _Ret, class _Callable, class... _Variants, class = void_t<_As_variant<_Variants>...>>
constexpr _Ret visit(_Callable&& _Obj, _Variants&&... _Args) {
constexpr auto _Size = _Variant_total_states<_Remove_cvref_t<_As_variant<_Variants>>...>;
using _ListOfIndexLists =
_Meta_list<_Meta_as_list<make_index_sequence<1 + variant_size_v<_Remove_cvref_t<_As_variant<_Variants>>>>>...>;
using _ListOfIndexVectors =
_Meta_transform<_Meta_quote<_Meta_as_integer_sequence>, _Meta_cartesian_product<_ListOfIndexLists>>;
if constexpr (!is_void_v<_Ret>) {
static_assert(_Variant_all_visit_results_implicitly_convertible<_Ret, _Callable, _ListOfIndexVectors,
_As_variant<_Variants>...>::value,
"visit<R>() requires the result of all potential invocations to be implicitly convertible to R "
"(N4835 [variant.visit]/2).");
}
return _Visit_impl<_Size, _Ret, _ListOfIndexVectors>(
static_cast<_Callable&&>(_Obj), static_cast<_Variants&&>(_Args)...);
2019-09-05 01:57:56 +03:00
}
#endif // _HAS_CXX20
2019-09-05 01:57:56 +03:00
// CLASS monostate [variant.monostate]
struct monostate {};
// monostate RELATIONAL OPERATORS [variant.monostate.relops]
_NODISCARD constexpr bool operator==(monostate, monostate) noexcept {
return true;
}
_NODISCARD constexpr bool operator!=(monostate, monostate) noexcept {
return false;
}
_NODISCARD constexpr bool operator<(monostate, monostate) noexcept {
return false;
}
_NODISCARD constexpr bool operator>(monostate, monostate) noexcept {
return false;
}
_NODISCARD constexpr bool operator<=(monostate, monostate) noexcept {
return true;
}
_NODISCARD constexpr bool operator>=(monostate, monostate) noexcept {
return true;
}
// SPECIALIZED ALGORITHMS [variant.specalg]
template <class... _Types,
enable_if_t<conjunction_v<is_move_constructible<_Types>..., is_swappable<_Types>...>, int> = 0>
void swap(variant<_Types...>& _Left, variant<_Types...>& _Right) noexcept(noexcept(_Left.swap(_Right))) {
_Left.swap(_Right);
}
// HASH SUPPORT [variant.hash]
struct _Variant_hash_visitor { // visitation function for hashing variants
template <class _Ty, size_t _Idx>
_NODISCARD size_t operator()(_Tagged<const _Ty&, _Idx> _Obj) const
noexcept(disjunction_v<bool_constant<_Idx == variant_npos>,
is_nothrow_invocable<hash<_Ty>, const _Ty&>>) { // hash contained value _Obj
if constexpr (_Idx == variant_npos) { // hash a valueless variant
return 0;
} else { // hash the contained value
return hash<_Ty>{}(_Obj._Val);
}
}
};
template <class... _Types>
struct hash<variant<_Types...>> : _Conditionally_enabled_hash<variant<_Types...>,
conjunction_v<is_default_constructible<hash<remove_const_t<_Types>>>...>> {
_NODISCARD static size_t _Do_hash(const variant<_Types...>& _Var) noexcept(
conjunction_v<_Is_nothrow_hashable<remove_const_t<_Types>>...>) {
// called from the CRTP base to hash _Var iff the hash is enabled
return _Variant_raw_visit(_Var.index(), _Var._Storage(), _Variant_hash_visitor{});
}
};
template <>
struct hash<monostate> {
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef monostate _ARGUMENT_TYPE_NAME;
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef size_t _RESULT_TYPE_NAME;
2019-09-05 01:57:56 +03:00
_NODISCARD size_t operator()(monostate) const noexcept {
return 1729; // Arbitrary value
}
};
_STD_END
#undef _STL_STAMP
#undef _STL_STAMP256
#undef _STL_STAMP64
#undef _STL_STAMP16
#undef _STL_STAMP4
#undef _STL_UNREACHABLE
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // _HAS_CXX17
#endif // _STL_COMPILER_PREPROCESSOR
#endif // _VARIANT_