// MPark.Variant // // Copyright Michael Park, 2015-2017 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.md or copy at // http://boost.org/LICENSE_1_0.txt) // // From https://github.com/mpark/variant // // C10 // - Move to `c10` namespace. // - Rename namespace `detail` to `detail_`, to not conflict with existing // c10 implementations in `detail` namespace. // - In two functions, the template name reference `I` is changed to // `detail_::best_match::value` to work around gcc 7.3.1 bug. // However, this workaround also limits the use cases of `c10::variant`. // Please see NOTE [gcc 7.3.1 bug workaround] for details. // - The following code is moved to `c10/util/in_place.h`: // ``` // struct in_place_t { explicit in_place_t() = default; }; // // template // struct in_place_index_t { explicit in_place_index_t() = default; }; // // template // struct in_place_type_t { explicit in_place_type_t() = default; }; // // constexpr in_place_t in_place{}; // ``` // so that they can also be used in `c10/util/Optional.h`. #ifndef C10_UTIL_VARIANT_H_ #define C10_UTIL_VARIANT_H_ /* variant synopsis namespace std { // 20.7.2, class template variant template class variant { public: // 20.7.2.1, constructors constexpr variant() noexcept(see below); variant(const variant&); variant(variant&&) noexcept(see below); template constexpr variant(T&&) noexcept(see below); template constexpr explicit variant(in_place_type_t, Args&&...); template constexpr explicit variant( in_place_type_t, initializer_list, Args&&...); template constexpr explicit variant(in_place_index_t, Args&&...); template constexpr explicit variant( in_place_index_t, initializer_list, Args&&...); // 20.7.2.2, destructor ~variant(); // 20.7.2.3, assignment variant& operator=(const variant&); variant& operator=(variant&&) noexcept(see below); template variant& operator=(T&&) noexcept(see below); // 20.7.2.4, modifiers template T& emplace(Args&&...); template T& emplace(initializer_list, Args&&...); template variant_alternative& emplace(Args&&...); template variant_alternative& emplace(initializer_list, Args&&...); // 20.7.2.5, value status constexpr bool valueless_by_exception() const noexcept; constexpr size_t index() const noexcept; // 20.7.2.6, swap void swap(variant&) noexcept(see below); }; // 20.7.3, variant helper classes template struct variant_size; // undefined template constexpr size_t variant_size_v = variant_size::value; template struct variant_size; template struct variant_size; template struct variant_size; template struct variant_size>; template struct variant_alternative; // undefined template using variant_alternative_t = typename variant_alternative::type; template struct variant_alternative; template struct variant_alternative; template struct variant_alternative; template struct variant_alternative>; constexpr size_t variant_npos = -1; // 20.7.4, value access template constexpr bool holds_alternative(const variant&) noexcept; template constexpr variant_alternative_t>& get(variant&); template constexpr variant_alternative_t>&& get(variant&&); template constexpr variant_alternative_t> const& get(const variant&); template constexpr variant_alternative_t> const&& get(const variant&&); template constexpr T& get(variant&); template constexpr T&& get(variant&&); template constexpr const T& get(const variant&); template constexpr const T&& get(const variant&&); template constexpr add_pointer_t>> get_if(variant*) noexcept; template constexpr add_pointer_t>> get_if(const variant*) noexcept; template constexpr add_pointer_t get_if(variant*) noexcept; template constexpr add_pointer_t get_if(const variant*) noexcept; // 20.7.5, relational operators template constexpr bool operator==(const variant&, const variant&); template constexpr bool operator!=(const variant&, const variant&); template constexpr bool operator<(const variant&, const variant&); template constexpr bool operator>(const variant&, const variant&); template constexpr bool operator<=(const variant&, const variant&); template constexpr bool operator>=(const variant&, const variant&); // 20.7.6, visitation template constexpr see below visit(Visitor&&, Variants&&...); // 20.7.7, class monostate struct monostate; // 20.7.8, monostate relational operators constexpr bool operator<(monostate, monostate) noexcept; constexpr bool operator>(monostate, monostate) noexcept; constexpr bool operator<=(monostate, monostate) noexcept; constexpr bool operator>=(monostate, monostate) noexcept; constexpr bool operator==(monostate, monostate) noexcept; constexpr bool operator!=(monostate, monostate) noexcept; // 20.7.9, specialized algorithms template void swap(variant&, variant&) noexcept(see below); // 20.7.10, class bad_variant_access class bad_variant_access; // 20.7.11, hash support template struct hash; template struct hash>; template <> struct hash; } // namespace std */ #include #include #include #include #include #include #include // MPark.Variant // // Copyright Michael Park, 2015-2017 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.md or copy at // http://boost.org/LICENSE_1_0.txt) #ifndef C10_MPARK_CONFIG_HPP #define C10_MPARK_CONFIG_HPP // MSVC 2015 Update 3. #if __cplusplus < 201103L && (!defined(_MSC_VER) || _MSC_FULL_VER < 190024210) #error "MPark.Variant requires C++11 support." #endif #ifndef __has_attribute #define __has_attribute(x) 0 #endif #ifndef __has_builtin #define __has_builtin(x) 0 #endif #ifndef __has_include #define __has_include(x) 0 #endif #ifndef __has_feature #define __has_feature(x) 0 #endif #if __has_attribute(always_inline) || defined(__GNUC__) #define C10_MPARK_ALWAYS_INLINE __attribute__((__always_inline__)) inline #elif defined(_MSC_VER) #define C10_MPARK_ALWAYS_INLINE __forceinline #else #define C10_MPARK_ALWAYS_INLINE inline #endif #if __has_builtin(__builtin_addressof) || \ (defined(__GNUC__) && __GNUC__ >= 7) || defined(_MSC_VER) #define C10_MPARK_BUILTIN_ADDRESSOF #endif #if __has_builtin(__builtin_unreachable) || defined(__GNUC__) #define C10_MPARK_BUILTIN_UNREACHABLE __builtin_unreachable() #elif defined(_MSC_VER) #define C10_MPARK_BUILTIN_UNREACHABLE __assume(false) #else #define C10_MPARK_BUILTIN_UNREACHABLE #endif #if __has_builtin(__type_pack_element) #define C10_MPARK_TYPE_PACK_ELEMENT #endif #if defined(__cpp_constexpr) && __cpp_constexpr >= 200704 && \ !(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 9) #define C10_MPARK_CPP11_CONSTEXPR #endif #if defined(__cpp_constexpr) && __cpp_constexpr >= 201304 #define C10_MPARK_CPP14_CONSTEXPR #endif #if __has_feature(cxx_exceptions) || defined(__cpp_exceptions) || \ (defined(_MSC_VER) && defined(_CPPUNWIND)) #define C10_MPARK_EXCEPTIONS #endif #if defined(__cpp_generic_lambdas) || defined(_MSC_VER) #define C10_MPARK_GENERIC_LAMBDAS #endif #if defined(__cpp_lib_integer_sequence) #define C10_MPARK_INTEGER_SEQUENCE #endif #if defined(__cpp_return_type_deduction) || defined(_MSC_VER) #define C10_MPARK_RETURN_TYPE_DEDUCTION #endif #if defined(__cpp_lib_transparent_operators) || defined(_MSC_VER) #define C10_MPARK_TRANSPARENT_OPERATORS #endif #if defined(__cpp_variable_templates) || defined(_MSC_VER) #define C10_MPARK_VARIABLE_TEMPLATES #endif #if !defined(__GLIBCXX__) || __has_include() // >= libstdc++-5 #define C10_MPARK_TRIVIALITY_TYPE_TRAITS #define C10_MPARK_INCOMPLETE_TYPE_TRAITS #endif #endif // C10_MPARK_CONFIG_HPP // MPark.Variant // // Copyright Michael Park, 2015-2017 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.md or copy at // http://boost.org/LICENSE_1_0.txt) #ifndef C10_MPARK_IN_PLACE_HPP #define C10_MPARK_IN_PLACE_HPP #include #include namespace c10 { #ifdef C10_MPARK_VARIABLE_TEMPLATES template constexpr in_place_index_t in_place_index{}; template constexpr in_place_type_t in_place_type{}; #endif } // namespace c10 #endif // C10_MPARK_IN_PLACE_HPP // MPark.Variant // // Copyright Michael Park, 2015-2017 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.md or copy at // http://boost.org/LICENSE_1_0.txt) #ifndef C10_MPARK_LIB_HPP #define C10_MPARK_LIB_HPP #include #include #include #include #define C10_MPARK_RETURN(...) \ noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) { \ return __VA_ARGS__; \ } namespace c10 { namespace lib { template struct identity { using type = T; }; inline namespace cpp14 { template struct array { constexpr const T& operator[](std::size_t index) const { return data[index]; } T data[N == 0 ? 1 : N]; }; template using add_pointer_t = typename std::add_pointer::type; template using common_type_t = typename std::common_type::type; template using decay_t = typename std::decay::type; template using enable_if_t = typename std::enable_if::type; template using remove_const_t = typename std::remove_const::type; template using remove_reference_t = typename std::remove_reference::type; template inline constexpr T&& forward(remove_reference_t& t) noexcept { return static_cast(t); } template inline constexpr T&& forward(remove_reference_t&& t) noexcept { static_assert( !std::is_lvalue_reference::value, "can not forward an rvalue as an lvalue"); return static_cast(t); } template inline constexpr remove_reference_t&& move(T&& t) noexcept { return static_cast&&>(t); } #ifdef C10_MPARK_INTEGER_SEQUENCE using std::index_sequence; using std::index_sequence_for; using std::integer_sequence; using std::make_index_sequence; #else template struct integer_sequence { using value_type = T; static constexpr std::size_t size() noexcept { return sizeof...(Is); } }; template using index_sequence = integer_sequence; template struct make_index_sequence_concat; template struct make_index_sequence_concat< index_sequence, index_sequence> : identity> {}; template struct make_index_sequence_impl; template using make_index_sequence = typename make_index_sequence_impl::type; template struct make_index_sequence_impl : make_index_sequence_concat< make_index_sequence, make_index_sequence> {}; template <> struct make_index_sequence_impl<0> : identity> {}; template <> struct make_index_sequence_impl<1> : identity> {}; template using index_sequence_for = make_index_sequence; #endif // #ifdef C10_MPARK_TRANSPARENT_OPERATORS using equal_to = std::equal_to<>; #else struct equal_to { template inline constexpr auto operator()(Lhs&& lhs, Rhs&& rhs) const C10_MPARK_RETURN(lib::forward(lhs) == lib::forward(rhs)) }; #endif #ifdef C10_MPARK_TRANSPARENT_OPERATORS using not_equal_to = std::not_equal_to<>; #else struct not_equal_to { template inline constexpr auto operator()(Lhs&& lhs, Rhs&& rhs) const C10_MPARK_RETURN(lib::forward(lhs) != lib::forward(rhs)) }; #endif #ifdef C10_MPARK_TRANSPARENT_OPERATORS using less = std::less<>; #else struct less { template inline constexpr auto operator()(Lhs&& lhs, Rhs&& rhs) const C10_MPARK_RETURN(lib::forward(lhs) < lib::forward(rhs)) }; #endif #ifdef C10_MPARK_TRANSPARENT_OPERATORS using greater = std::greater<>; #else struct greater { template inline constexpr auto operator()(Lhs&& lhs, Rhs&& rhs) const C10_MPARK_RETURN(lib::forward(lhs) > lib::forward(rhs)) }; #endif #ifdef C10_MPARK_TRANSPARENT_OPERATORS using less_equal = std::less_equal<>; #else struct less_equal { template inline constexpr auto operator()(Lhs&& lhs, Rhs&& rhs) const C10_MPARK_RETURN(lib::forward(lhs) <= lib::forward(rhs)) }; #endif #ifdef C10_MPARK_TRANSPARENT_OPERATORS using greater_equal = std::greater_equal<>; #else struct greater_equal { template inline constexpr auto operator()(Lhs&& lhs, Rhs&& rhs) const C10_MPARK_RETURN(lib::forward(lhs) >= lib::forward(rhs)) }; #endif } // namespace cpp14 inline namespace cpp17 { // template using bool_constant = std::integral_constant; template struct voider : identity {}; template using void_t = typename voider::type; namespace detail_ { namespace swappable { using std::swap; template struct is_swappable { private: template < typename U, typename = decltype(swap(std::declval(), std::declval()))> inline static std::true_type test(int); template inline static std::false_type test(...); public: static constexpr bool value = decltype(test(0))::value; }; template struct is_nothrow_swappable { static constexpr bool value = noexcept(swap(std::declval(), std::declval())); }; template struct is_nothrow_swappable : std::false_type {}; } // namespace swappable } // namespace detail_ using detail_::swappable::is_swappable; template using is_nothrow_swappable = detail_::swappable::is_nothrow_swappable::value, T>; // namespace detail_ { template struct is_reference_wrapper : std::false_type {}; template struct is_reference_wrapper> : std::true_type {}; template struct Invoke; template <> struct Invoke { template inline static constexpr auto invoke(R T::*pmf, Arg&& arg, Args&&... args) C10_MPARK_RETURN( (lib::forward(arg).*pmf)(lib::forward(args)...)) }; template <> struct Invoke { template inline static constexpr auto invoke(R T::*pmf, Arg&& arg, Args&&... args) C10_MPARK_RETURN( (lib::forward(arg).get().*pmf)(lib::forward(args)...)) }; template <> struct Invoke { template inline static constexpr auto invoke(R T::*pmf, Arg&& arg, Args&&... args) C10_MPARK_RETURN( ((*lib::forward(arg)).*pmf)(lib::forward(args)...)) }; template <> struct Invoke { template inline static constexpr auto invoke(R T::*pmo, Arg&& arg) C10_MPARK_RETURN(lib::forward(arg).*pmo) }; template <> struct Invoke { template inline static constexpr auto invoke(R T::*pmo, Arg&& arg) C10_MPARK_RETURN(lib::forward(arg).get().*pmo) }; template <> struct Invoke { template inline static constexpr auto invoke(R T::*pmo, Arg&& arg) C10_MPARK_RETURN((*lib::forward(arg)).*pmo) }; template inline constexpr auto invoke(R T::*f, Arg&& arg, Args&&... args) C10_MPARK_RETURN( Invoke< std::is_function::value, (std::is_base_of>::value ? 0 : is_reference_wrapper>::value ? 1 : 2)>:: invoke(f, lib::forward(arg), lib::forward(args)...)) #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4100) #endif template inline constexpr auto invoke(F&& f, Args&&... args) C10_MPARK_RETURN(lib::forward(f)(lib::forward(args)...)) #ifdef _MSC_VER #pragma warning(pop) #endif } // namespace detail_ template inline constexpr auto invoke(F&& f, Args&&... args) C10_MPARK_RETURN( detail_::invoke(lib::forward(f), lib::forward(args)...)) namespace detail_ { template struct invoke_result {}; template struct invoke_result< void_t(), std::declval()...))>, F, Args...> : identity(), std::declval()...))> {}; } // namespace detail_ template using invoke_result = detail_::invoke_result; template using invoke_result_t = typename invoke_result::type; namespace detail_ { template struct is_invocable : std::false_type {}; template struct is_invocable>, F, Args...> : std::true_type {}; template struct is_invocable_r : std::false_type {}; template struct is_invocable_r>, R, F, Args...> : std::is_convertible, R> {}; } // namespace detail_ template using is_invocable = detail_::is_invocable; template using is_invocable_r = detail_::is_invocable_r; namespace detail_ { template struct is_nothrow_invocable { static constexpr bool value = noexcept(lib::invoke(std::declval(), std::declval()...)); }; template struct is_nothrow_invocable : std::false_type {}; template struct is_nothrow_invocable_r { private: inline static R impl() { return lib::invoke(std::declval(), std::declval()...); } public: static constexpr bool value = noexcept(impl()); }; template struct is_nothrow_invocable_r : std::false_type {}; } // namespace detail_ template using is_nothrow_invocable = detail_::is_nothrow_invocable::value, F, Args...>; template using is_nothrow_invocable_r = detail_:: is_nothrow_invocable_r::value, R, F, Args...>; // #ifdef C10_MPARK_BUILTIN_ADDRESSOF template inline constexpr T* addressof(T& arg) noexcept { return __builtin_addressof(arg); } #else namespace detail_ { namespace has_addressof_impl { struct fail; template inline fail operator&(T&&); template inline static constexpr bool impl() { return (std::is_class::value || std::is_union::value) && !std::is_same()), fail>::value; } } // namespace has_addressof_impl template using has_addressof = bool_constant()>; template inline constexpr T* addressof(T& arg, std::true_type) noexcept { return std::addressof(arg); } template inline constexpr T* addressof(T& arg, std::false_type) noexcept { return &arg; } } // namespace detail_ template inline constexpr T* addressof(T& arg) noexcept { return detail_::addressof(arg, detail_::has_addressof{}); } #endif template inline constexpr T* addressof(const T&&) = delete; } // namespace cpp17 template struct remove_all_extents : identity {}; template struct remove_all_extents> : remove_all_extents {}; template using remove_all_extents_t = typename remove_all_extents::type; template using size_constant = std::integral_constant; template struct indexed_type : size_constant { using type = T; }; template using all = std::is_same< integer_sequence, integer_sequence>; #ifdef C10_MPARK_TYPE_PACK_ELEMENT template using type_pack_element_t = __type_pack_element; #else template struct type_pack_element_impl { private: template struct set; template struct set> : indexed_type... {}; template inline static std::enable_if impl(indexed_type); inline static std::enable_if impl(...); public: using type = decltype(impl(set>{})); }; template using type_pack_element = typename type_pack_element_impl::type; template using type_pack_element_t = typename type_pack_element::type; #endif #ifdef C10_MPARK_TRIVIALITY_TYPE_TRAITS using std::is_trivially_copy_assignable; using std::is_trivially_copy_constructible; using std::is_trivially_move_assignable; using std::is_trivially_move_constructible; #else template struct is_trivially_copy_constructible : bool_constant::value&& __has_trivial_copy( T)> {}; template struct is_trivially_move_constructible : bool_constant<__is_trivial(T)> {}; template struct is_trivially_copy_assignable : bool_constant::value&& __has_trivial_assign( T)> {}; template struct is_trivially_move_assignable : bool_constant<__is_trivial(T)> {}; #endif template struct dependent_type : T {}; template struct push_back; template using push_back_t = typename push_back::type; template struct push_back, J> { using type = index_sequence; }; } // namespace lib } // namespace c10 #undef C10_MPARK_RETURN #endif // C10_MPARK_LIB_HPP namespace c10 { #ifdef C10_MPARK_RETURN_TYPE_DEDUCTION #define AUTO auto #define AUTO_RETURN(...) \ { return __VA_ARGS__; } #define AUTO_REFREF auto&& #define AUTO_REFREF_RETURN(...) \ { return __VA_ARGS__; } #define DECLTYPE_AUTO decltype(auto) #define DECLTYPE_AUTO_RETURN(...) \ { return __VA_ARGS__; } #else #define AUTO auto #define AUTO_RETURN(...) \ ->lib::decay_t { \ return __VA_ARGS__; \ } #define AUTO_REFREF auto #define AUTO_REFREF_RETURN(...) \ ->decltype((__VA_ARGS__)) { \ static_assert(std::is_reference::value, ""); \ return __VA_ARGS__; \ } #define DECLTYPE_AUTO auto #define DECLTYPE_AUTO_RETURN(...) \ ->decltype(__VA_ARGS__) { \ return __VA_ARGS__; \ } #endif class bad_variant_access : public std::exception { public: const char* what() const noexcept override { return "bad_variant_access"; } }; [[noreturn]] inline void throw_bad_variant_access() { #ifdef C10_MPARK_EXCEPTIONS throw bad_variant_access{}; #else std::terminate(); C10_MPARK_BUILTIN_UNREACHABLE; #endif } template class variant; template struct variant_size; #ifdef C10_MPARK_VARIABLE_TEMPLATES template constexpr std::size_t variant_size_v = variant_size::value; #endif template struct variant_size : variant_size {}; template struct variant_size : variant_size {}; template struct variant_size : variant_size {}; template struct variant_size> : lib::size_constant {}; template struct variant_alternative; template using variant_alternative_t = typename variant_alternative::type; template struct variant_alternative : std::add_const> {}; template struct variant_alternative : std::add_volatile> {}; template struct variant_alternative : std::add_cv> {}; template struct variant_alternative> { static_assert( I < sizeof...(Ts), "index out of bounds in `std::variant_alternative<>`"); using type = lib::type_pack_element_t; }; constexpr std::size_t variant_npos = static_cast(-1); namespace detail_ { constexpr std::size_t not_found = static_cast(-1); constexpr std::size_t ambiguous = static_cast(-2); #ifdef C10_MPARK_CPP14_CONSTEXPR template inline constexpr std::size_t find_index() { constexpr lib::array matches = { {std::is_same::value...}}; std::size_t result = not_found; for (std::size_t i = 0; i < sizeof...(Ts); ++i) { if (matches[i]) { if (result != not_found) { return ambiguous; } result = i; } } return result; } #else inline constexpr std::size_t find_index_impl(std::size_t result, std::size_t) { return result; } template inline constexpr std::size_t find_index_impl( std::size_t result, std::size_t idx, bool b, Bs... bs) { return b ? (result != not_found ? ambiguous : find_index_impl(idx, idx + 1, bs...)) : find_index_impl(result, idx + 1, bs...); } template inline constexpr std::size_t find_index() { return find_index_impl(not_found, 0, std::is_same::value...); } #endif template using find_index_sfinae_impl = lib::enable_if_t>; template using find_index_sfinae = find_index_sfinae_impl()>; template struct find_index_checked_impl : lib::size_constant { static_assert(I != not_found, "the specified type is not found."); static_assert(I != ambiguous, "the specified type is ambiguous."); }; template using find_index_checked = find_index_checked_impl()>; struct valueless_t {}; enum class Trait { TriviallyAvailable, Available, Unavailable }; template < typename T, template class IsTriviallyAvailable, template class IsAvailable> inline constexpr Trait trait() { return IsTriviallyAvailable::value ? Trait::TriviallyAvailable : IsAvailable::value ? Trait::Available : Trait::Unavailable; } #ifdef C10_MPARK_CPP14_CONSTEXPR template inline constexpr Trait common_trait(Traits... traits_) { Trait result = Trait::TriviallyAvailable; lib::array traits = {{traits_...}}; for (std::size_t i = 0; i < sizeof...(Traits); ++i) { Trait t = traits[i]; if (static_cast(t) > static_cast(result)) { result = t; } } return result; } #else inline constexpr Trait common_trait_impl(Trait result) { return result; } template inline constexpr Trait common_trait_impl(Trait result, Trait t, Traits... ts) { return static_cast(t) > static_cast(result) ? common_trait_impl(t, ts...) : common_trait_impl(result, ts...); } template inline constexpr Trait common_trait(Traits... ts) { return common_trait_impl(Trait::TriviallyAvailable, ts...); } #endif template struct traits { static constexpr Trait copy_constructible_trait = common_trait(trait< Ts, lib::is_trivially_copy_constructible, std::is_copy_constructible>()...); static constexpr Trait move_constructible_trait = common_trait(trait< Ts, lib::is_trivially_move_constructible, std::is_move_constructible>()...); static constexpr Trait copy_assignable_trait = common_trait( copy_constructible_trait, trait< Ts, lib::is_trivially_copy_assignable, std::is_copy_assignable>()...); static constexpr Trait move_assignable_trait = common_trait( move_constructible_trait, trait< Ts, lib::is_trivially_move_assignable, std::is_move_assignable>()...); static constexpr Trait destructible_trait = common_trait( trait()...); }; namespace access { struct recursive_union { #ifdef C10_MPARK_RETURN_TYPE_DEDUCTION template inline static constexpr auto&& get_alt(V&& v, in_place_index_t<0>) { return lib::forward(v).head_; } template inline static constexpr auto&& get_alt(V&& v, in_place_index_t) { return get_alt(lib::forward(v).tail_, in_place_index_t{}); } #else template struct get_alt_impl { template inline constexpr AUTO_REFREF operator()(V&& v) const AUTO_REFREF_RETURN(get_alt_impl{}(lib::forward(v).tail_)) }; template struct get_alt_impl<0, Dummy> { template inline constexpr AUTO_REFREF operator()(V&& v) const AUTO_REFREF_RETURN(lib::forward(v).head_) }; template inline static constexpr AUTO_REFREF get_alt(V&& v, in_place_index_t) AUTO_REFREF_RETURN(get_alt_impl{}(lib::forward(v))) #endif }; struct base { template inline static constexpr AUTO_REFREF get_alt(V&& v) #ifdef _MSC_VER AUTO_REFREF_RETURN(recursive_union::get_alt( lib::forward(v).data_, in_place_index_t{})) #else AUTO_REFREF_RETURN(recursive_union::get_alt( data(lib::forward(v)), in_place_index_t{})) #endif }; struct variant { template inline static constexpr AUTO_REFREF get_alt(V&& v) AUTO_REFREF_RETURN(base::get_alt(lib::forward(v).impl_)) }; } // namespace access namespace visitation { #if defined(C10_MPARK_CPP14_CONSTEXPR) && !defined(_MSC_VER) #define C10_MPARK_VARIANT_SWITCH_VISIT #endif struct base { template using dispatch_result_t = decltype(lib::invoke( std::declval(), access::base::get_alt<0>(std::declval())...)); template struct expected { template inline static constexpr bool but_got() { return std::is_same::value; } }; template struct visit_return_type_check { static_assert( expected::template but_got(), "`visit` requires the visitor to have a single return type"); template inline static constexpr DECLTYPE_AUTO invoke( Visitor&& visitor, Alts&&... alts) DECLTYPE_AUTO_RETURN(lib::invoke( lib::forward(visitor), lib::forward(alts)...)) }; #ifdef C10_MPARK_VARIANT_SWITCH_VISIT template struct dispatcher; template struct dispatcher { template C10_MPARK_ALWAYS_INLINE static constexpr R dispatch( F&&, typename ITs::type&&..., Vs&&...) { C10_MPARK_BUILTIN_UNREACHABLE; } template C10_MPARK_ALWAYS_INLINE static constexpr R dispatch_case(F&&, Vs&&...) { C10_MPARK_BUILTIN_UNREACHABLE; } template C10_MPARK_ALWAYS_INLINE static constexpr R dispatch_at( std::size_t, F&&, Vs&&...) { C10_MPARK_BUILTIN_UNREACHABLE; } }; template struct dispatcher { template C10_MPARK_ALWAYS_INLINE static constexpr R dispatch( F&& f, typename ITs::type&&... visited_vs) { using Expected = R; using Actual = decltype(lib::invoke( lib::forward(f), access::base::get_alt( lib::forward(visited_vs))...)); return visit_return_type_check::invoke( lib::forward(f), access::base::get_alt( lib::forward(visited_vs))...); } template C10_MPARK_ALWAYS_INLINE static constexpr R dispatch( F&& f, typename ITs::type&&... visited_vs, V&& v, Vs&&... vs) { #define C10_MPARK_DISPATCH(I) \ dispatcher< \ (I < lib::decay_t::size()), \ R, \ ITs..., \ lib::indexed_type>:: \ template dispatch<0>( \ lib::forward(f), \ lib::forward(visited_vs)..., \ lib::forward(v), \ lib::forward(vs)...) #define C10_MPARK_DEFAULT(I) \ dispatcher<(I < lib::decay_t::size()), R, ITs...>::template dispatch( \ lib::forward(f), \ lib::forward(visited_vs)..., \ lib::forward(v), \ lib::forward(vs)...) switch (v.index()) { case B + 0: return C10_MPARK_DISPATCH(B + 0); case B + 1: return C10_MPARK_DISPATCH(B + 1); case B + 2: return C10_MPARK_DISPATCH(B + 2); case B + 3: return C10_MPARK_DISPATCH(B + 3); case B + 4: return C10_MPARK_DISPATCH(B + 4); case B + 5: return C10_MPARK_DISPATCH(B + 5); case B + 6: return C10_MPARK_DISPATCH(B + 6); case B + 7: return C10_MPARK_DISPATCH(B + 7); case B + 8: return C10_MPARK_DISPATCH(B + 8); case B + 9: return C10_MPARK_DISPATCH(B + 9); case B + 10: return C10_MPARK_DISPATCH(B + 10); case B + 11: return C10_MPARK_DISPATCH(B + 11); case B + 12: return C10_MPARK_DISPATCH(B + 12); case B + 13: return C10_MPARK_DISPATCH(B + 13); case B + 14: return C10_MPARK_DISPATCH(B + 14); case B + 15: return C10_MPARK_DISPATCH(B + 15); case B + 16: return C10_MPARK_DISPATCH(B + 16); case B + 17: return C10_MPARK_DISPATCH(B + 17); case B + 18: return C10_MPARK_DISPATCH(B + 18); case B + 19: return C10_MPARK_DISPATCH(B + 19); case B + 20: return C10_MPARK_DISPATCH(B + 20); case B + 21: return C10_MPARK_DISPATCH(B + 21); case B + 22: return C10_MPARK_DISPATCH(B + 22); case B + 23: return C10_MPARK_DISPATCH(B + 23); case B + 24: return C10_MPARK_DISPATCH(B + 24); case B + 25: return C10_MPARK_DISPATCH(B + 25); case B + 26: return C10_MPARK_DISPATCH(B + 26); case B + 27: return C10_MPARK_DISPATCH(B + 27); case B + 28: return C10_MPARK_DISPATCH(B + 28); case B + 29: return C10_MPARK_DISPATCH(B + 29); case B + 30: return C10_MPARK_DISPATCH(B + 30); case B + 31: return C10_MPARK_DISPATCH(B + 31); default: return C10_MPARK_DEFAULT(B + 32); } #undef C10_MPARK_DEFAULT #undef C10_MPARK_DISPATCH } template C10_MPARK_ALWAYS_INLINE static constexpr R dispatch_case( F&& f, Vs&&... vs) { using Expected = R; using Actual = decltype(lib::invoke( lib::forward(f), access::base::get_alt(lib::forward(vs))...)); return visit_return_type_check::invoke( lib::forward(f), access::base::get_alt(lib::forward(vs))...); } template C10_MPARK_ALWAYS_INLINE static constexpr R dispatch_at( std::size_t index, F&& f, V&& v, Vs&&... vs) { static_assert( lib::all<( lib::decay_t::size() == lib::decay_t::size())...>::value, "all of the variants must be the same size."); #define C10_MPARK_DISPATCH_AT(I) \ dispatcher<(I < lib::decay_t::size()), R>::template dispatch_case( \ lib::forward(f), lib::forward(v), lib::forward(vs)...) #define C10_MPARK_DEFAULT(I) \ dispatcher<(I < lib::decay_t::size()), R>::template dispatch_at( \ index, lib::forward(f), lib::forward(v), lib::forward(vs)...) switch (index) { case B + 0: return C10_MPARK_DISPATCH_AT(B + 0); case B + 1: return C10_MPARK_DISPATCH_AT(B + 1); case B + 2: return C10_MPARK_DISPATCH_AT(B + 2); case B + 3: return C10_MPARK_DISPATCH_AT(B + 3); case B + 4: return C10_MPARK_DISPATCH_AT(B + 4); case B + 5: return C10_MPARK_DISPATCH_AT(B + 5); case B + 6: return C10_MPARK_DISPATCH_AT(B + 6); case B + 7: return C10_MPARK_DISPATCH_AT(B + 7); case B + 8: return C10_MPARK_DISPATCH_AT(B + 8); case B + 9: return C10_MPARK_DISPATCH_AT(B + 9); case B + 10: return C10_MPARK_DISPATCH_AT(B + 10); case B + 11: return C10_MPARK_DISPATCH_AT(B + 11); case B + 12: return C10_MPARK_DISPATCH_AT(B + 12); case B + 13: return C10_MPARK_DISPATCH_AT(B + 13); case B + 14: return C10_MPARK_DISPATCH_AT(B + 14); case B + 15: return C10_MPARK_DISPATCH_AT(B + 15); case B + 16: return C10_MPARK_DISPATCH_AT(B + 16); case B + 17: return C10_MPARK_DISPATCH_AT(B + 17); case B + 18: return C10_MPARK_DISPATCH_AT(B + 18); case B + 19: return C10_MPARK_DISPATCH_AT(B + 19); case B + 20: return C10_MPARK_DISPATCH_AT(B + 20); case B + 21: return C10_MPARK_DISPATCH_AT(B + 21); case B + 22: return C10_MPARK_DISPATCH_AT(B + 22); case B + 23: return C10_MPARK_DISPATCH_AT(B + 23); case B + 24: return C10_MPARK_DISPATCH_AT(B + 24); case B + 25: return C10_MPARK_DISPATCH_AT(B + 25); case B + 26: return C10_MPARK_DISPATCH_AT(B + 26); case B + 27: return C10_MPARK_DISPATCH_AT(B + 27); case B + 28: return C10_MPARK_DISPATCH_AT(B + 28); case B + 29: return C10_MPARK_DISPATCH_AT(B + 29); case B + 30: return C10_MPARK_DISPATCH_AT(B + 30); case B + 31: return C10_MPARK_DISPATCH_AT(B + 31); default: return C10_MPARK_DEFAULT(B + 32); } #undef C10_MPARK_DEFAULT #undef C10_MPARK_DISPATCH_AT } }; #else template inline static constexpr const T& at(const T& elem) noexcept { return elem; } template inline static constexpr const lib::remove_all_extents_t& at( const lib::array& elems, std::size_t i, Is... is) noexcept { return at(elems[i], is...); } template inline static constexpr lib::array, sizeof...(Fs) + 1> make_farray(F&& f, Fs&&... fs) { return {{lib::forward(f), lib::forward(fs)...}}; } template struct make_fmatrix_impl { template inline static constexpr dispatch_result_t dispatch( F&& f, Vs&&... vs) { using Expected = dispatch_result_t; using Actual = decltype(lib::invoke( lib::forward(f), access::base::get_alt(lib::forward(vs))...)); return visit_return_type_check::invoke( lib::forward(f), access::base::get_alt(lib::forward(vs))...); } #ifdef C10_MPARK_RETURN_TYPE_DEDUCTION template inline static constexpr auto impl(lib::index_sequence) { return &dispatch; } template inline static constexpr auto impl( Is, lib::index_sequence, Ls... ls) { return make_farray(impl(lib::push_back_t{}, ls...)...); } #else template struct impl; template struct impl> { inline constexpr AUTO operator()() const AUTO_RETURN(&dispatch) }; template struct impl, Ls...> { inline constexpr AUTO operator()() const AUTO_RETURN(make_farray(impl, Ls...>{}()...)) }; #endif }; #ifdef C10_MPARK_RETURN_TYPE_DEDUCTION template inline static constexpr auto make_fmatrix() { return make_fmatrix_impl::impl( lib::index_sequence<>{}, lib::make_index_sequence::size()>{}...); } #else template inline static constexpr AUTO make_fmatrix() AUTO_RETURN(typename make_fmatrix_impl::template impl< lib::index_sequence<>, lib::make_index_sequence::size()>...>{}()) #endif template struct make_fdiagonal_impl { template inline static constexpr dispatch_result_t dispatch( F&& f, Vs&&... vs) { using Expected = dispatch_result_t; using Actual = decltype(lib::invoke( lib::forward(f), access::base::get_alt(lib::forward(vs))...)); return visit_return_type_check::invoke( lib::forward(f), access::base::get_alt(lib::forward(vs))...); } template inline static constexpr AUTO impl(lib::index_sequence) AUTO_RETURN(make_farray(&dispatch...)) }; template inline static constexpr auto make_fdiagonal() -> decltype(make_fdiagonal_impl::impl( lib::make_index_sequence::size()>{})) { static_assert( lib::all<( lib::decay_t::size() == lib::decay_t::size())...>::value, "all of the variants must be the same size."); return make_fdiagonal_impl::impl( lib::make_index_sequence::size()>{}); } #endif }; #if !defined(C10_MPARK_VARIANT_SWITCH_VISIT) && \ (!defined(_MSC_VER) || _MSC_VER >= 1910) template using fmatrix_t = decltype(base::make_fmatrix()); template struct fmatrix { static constexpr fmatrix_t value = base::make_fmatrix(); }; template constexpr fmatrix_t fmatrix::value; template using fdiagonal_t = decltype(base::make_fdiagonal()); template struct fdiagonal { static constexpr fdiagonal_t value = base::make_fdiagonal(); }; template constexpr fdiagonal_t fdiagonal::value; #endif struct alt { template inline static constexpr DECLTYPE_AUTO visit_alt(Visitor&& visitor, Vs&&... vs) #ifdef C10_MPARK_VARIANT_SWITCH_VISIT DECLTYPE_AUTO_RETURN(base::dispatcher< true, base::dispatch_result_t< Visitor, decltype(as_base(lib::forward(vs)))...>>:: template dispatch<0>( lib::forward(visitor), as_base(lib::forward(vs))...)) #elif !defined(_MSC_VER) || _MSC_VER >= 1910 DECLTYPE_AUTO_RETURN(base::at( fmatrix(vs)))...>::value, vs.index()...)( lib::forward(visitor), as_base(lib::forward(vs))...)) #else DECLTYPE_AUTO_RETURN(base::at( base::make_fmatrix< Visitor&&, decltype(as_base(lib::forward(vs)))...>(), vs.index()...)( lib::forward(visitor), as_base(lib::forward(vs))...)) #endif template inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, Visitor&& visitor, Vs&&... vs) #ifdef C10_MPARK_VARIANT_SWITCH_VISIT DECLTYPE_AUTO_RETURN( base::dispatcher< true, base::dispatch_result_t< Visitor, decltype(as_base(lib::forward(vs)))...>>:: template dispatch_at<0>( index, lib::forward(visitor), as_base(lib::forward(vs))...)) #elif !defined(_MSC_VER) || _MSC_VER >= 1910 DECLTYPE_AUTO_RETURN(base::at( fdiagonal(vs)))...>:: value, index)( lib::forward(visitor), as_base(lib::forward(vs))...)) #else DECLTYPE_AUTO_RETURN(base::at( base::make_fdiagonal< Visitor&&, decltype(as_base(lib::forward(vs)))...>(), index)( lib::forward(visitor), as_base(lib::forward(vs))...)) #endif }; struct variant { private: template struct visitor { template inline static constexpr bool does_not_handle() { return lib::is_invocable::value; } }; template struct visit_exhaustiveness_check { static_assert( visitor::template does_not_handle(), "`visit` requires the visitor to be exhaustive."); inline static constexpr DECLTYPE_AUTO invoke( Visitor&& visitor, Values&&... values) DECLTYPE_AUTO_RETURN(lib::invoke( lib::forward(visitor), lib::forward(values)...)) }; template struct value_visitor { Visitor&& visitor_; template inline constexpr DECLTYPE_AUTO operator()(Alts&&... alts) const DECLTYPE_AUTO_RETURN(visit_exhaustiveness_check< Visitor, decltype((lib::forward(alts).value))...>:: invoke( lib::forward(visitor_), lib::forward(alts).value...)) }; template inline static constexpr AUTO make_value_visitor(Visitor&& visitor) AUTO_RETURN(value_visitor{lib::forward(visitor)}) public : template inline static constexpr DECLTYPE_AUTO visit_alt(Visitor&& visitor, Vs&&... vs) DECLTYPE_AUTO_RETURN(alt::visit_alt( lib::forward(visitor), lib::forward(vs).impl_...)) template inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, Visitor&& visitor, Vs&&... vs) DECLTYPE_AUTO_RETURN(alt::visit_alt_at( index, lib::forward(visitor), lib::forward(vs).impl_...)) template inline static constexpr DECLTYPE_AUTO visit_value(Visitor&& visitor, Vs&&... vs) DECLTYPE_AUTO_RETURN(visit_alt( make_value_visitor(lib::forward(visitor)), lib::forward(vs)...)) template inline static constexpr DECLTYPE_AUTO visit_value_at(std::size_t index, Visitor&& visitor, Vs&&... vs) DECLTYPE_AUTO_RETURN(visit_alt_at( index, make_value_visitor(lib::forward(visitor)), lib::forward(vs)...)) }; } // namespace visitation template struct alt { using value_type = T; #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4244) #endif template inline explicit constexpr alt(in_place_t, Args&&... args) : value(lib::forward(args)...) {} #ifdef _MSC_VER #pragma warning(pop) #endif T value; }; template union recursive_union; template union recursive_union {}; #define C10_MPARK_VARIANT_RECURSIVE_UNION(destructible_trait, destructor) \ template \ union recursive_union { \ public: \ inline explicit constexpr recursive_union(valueless_t) noexcept \ : dummy_{} {} \ \ template \ inline explicit constexpr recursive_union( \ in_place_index_t<0>, \ Args&&... args) \ : head_(in_place_t{}, lib::forward(args)...) {} \ \ template \ inline explicit constexpr recursive_union( \ in_place_index_t, \ Args&&... args) \ : tail_(in_place_index_t{}, lib::forward(args)...) {} \ \ recursive_union(const recursive_union&) = default; \ recursive_union(recursive_union&&) = default; \ \ destructor \ \ recursive_union& \ operator=(const recursive_union&) = default; \ recursive_union& operator=(recursive_union&&) = default; \ \ private: \ char dummy_; \ alt head_; \ recursive_union tail_; \ \ friend struct access::recursive_union; \ } C10_MPARK_VARIANT_RECURSIVE_UNION(Trait::TriviallyAvailable, ~recursive_union() = default;); C10_MPARK_VARIANT_RECURSIVE_UNION(Trait::Available, ~recursive_union(){}); C10_MPARK_VARIANT_RECURSIVE_UNION(Trait::Unavailable, ~recursive_union() = delete;); #undef C10_MPARK_VARIANT_RECURSIVE_UNION using index_t = unsigned int; template class base { public: inline explicit constexpr base(valueless_t tag) noexcept : data_(tag), index_(static_cast(-1)) {} template inline explicit constexpr base(in_place_index_t, Args&&... args) : data_(in_place_index_t{}, lib::forward(args)...), index_(I) {} inline constexpr bool valueless_by_exception() const noexcept { return index_ == static_cast(-1); } inline constexpr std::size_t index() const noexcept { return valueless_by_exception() ? variant_npos : index_; } protected: using data_t = recursive_union; friend inline constexpr base& as_base(base& b) { return b; } friend inline constexpr const base& as_base(const base& b) { return b; } friend inline constexpr base&& as_base(base&& b) { return lib::move(b); } friend inline constexpr const base&& as_base(const base&& b) { return lib::move(b); } friend inline constexpr data_t& data(base& b) { return b.data_; } friend inline constexpr const data_t& data(const base& b) { return b.data_; } friend inline constexpr data_t&& data(base&& b) { return lib::move(b).data_; } friend inline constexpr const data_t&& data(const base&& b) { return lib::move(b).data_; } inline static constexpr std::size_t size() { return sizeof...(Ts); } data_t data_; index_t index_; friend struct access::base; friend struct visitation::base; }; struct dtor { #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4100) #endif template inline void operator()(Alt& alt) const noexcept { alt.~Alt(); } #ifdef _MSC_VER #pragma warning(pop) #endif }; #if !defined(_MSC_VER) || _MSC_VER >= 1910 #define C10_MPARK_INHERITING_CTOR(type, base) using base::base; #else #define C10_MPARK_INHERITING_CTOR(type, base) \ template \ inline explicit constexpr type(Args&&... args) \ : base(lib::forward(args)...) {} #endif template class destructor; #define C10_MPARK_VARIANT_DESTRUCTOR(destructible_trait, definition, destroy) \ template \ class destructor, destructible_trait> \ : public base { \ using super = base; \ \ public: \ C10_MPARK_INHERITING_CTOR(destructor, super) \ using super::operator=; \ \ destructor(const destructor&) = default; \ destructor(destructor&&) = default; \ definition destructor& operator=(const destructor&) = default; \ destructor& operator=(destructor&&) = default; \ \ protected: \ destroy \ } C10_MPARK_VARIANT_DESTRUCTOR( Trait::TriviallyAvailable, ~destructor() = default; , inline void destroy() noexcept { this->index_ = static_cast(-1); }); C10_MPARK_VARIANT_DESTRUCTOR( Trait::Available, ~destructor() { destroy(); }, inline void destroy() noexcept { if (!this->valueless_by_exception()) { visitation::alt::visit_alt(dtor{}, *this); } this->index_ = static_cast(-1); }); C10_MPARK_VARIANT_DESTRUCTOR(Trait::Unavailable, ~destructor() = delete; , inline void destroy() noexcept = delete;); #undef C10_MPARK_VARIANT_DESTRUCTOR template class constructor : public destructor { using super = destructor; public: C10_MPARK_INHERITING_CTOR(constructor, super) using super::operator=; protected: #ifndef C10_MPARK_GENERIC_LAMBDAS struct ctor { template inline void operator()(LhsAlt& lhs_alt, RhsAlt&& rhs_alt) const { constructor::construct_alt(lhs_alt, lib::forward(rhs_alt).value); } }; #endif template inline static T& construct_alt(alt& a, Args&&... args) { auto* result = ::new (static_cast(lib::addressof(a))) alt(in_place_t{}, lib::forward(args)...); return result->value; } template inline static void generic_construct(constructor& lhs, Rhs&& rhs) { lhs.destroy(); if (!rhs.valueless_by_exception()) { visitation::alt::visit_alt_at( rhs.index(), #ifdef C10_MPARK_GENERIC_LAMBDAS [](auto& lhs_alt, auto&& rhs_alt) { constructor::construct_alt( lhs_alt, lib::forward(rhs_alt).value); } #else ctor {} #endif , lhs, lib::forward(rhs)); lhs.index_ = rhs.index_; } } }; template class move_constructor; #define C10_MPARK_VARIANT_MOVE_CONSTRUCTOR( \ move_constructible_trait, definition) \ template \ class move_constructor, move_constructible_trait> \ : public constructor> { \ using super = constructor>; \ \ public: \ C10_MPARK_INHERITING_CTOR(move_constructor, super) \ using super::operator=; \ \ move_constructor(const move_constructor&) = default; \ definition ~move_constructor() = default; \ move_constructor& operator=(const move_constructor&) = default; \ move_constructor& operator=(move_constructor&&) = default; \ } C10_MPARK_VARIANT_MOVE_CONSTRUCTOR( Trait::TriviallyAvailable, move_constructor(move_constructor&& that) = default;); C10_MPARK_VARIANT_MOVE_CONSTRUCTOR( Trait::Available, move_constructor(move_constructor&& that) noexcept( lib::all::value...>::value) : move_constructor(valueless_t{}) { this->generic_construct(*this, lib::move(that)); }); C10_MPARK_VARIANT_MOVE_CONSTRUCTOR( Trait::Unavailable, move_constructor(move_constructor&&) = delete;); #undef C10_MPARK_VARIANT_MOVE_CONSTRUCTOR template class copy_constructor; #define C10_MPARK_VARIANT_COPY_CONSTRUCTOR( \ copy_constructible_trait, definition) \ template \ class copy_constructor, copy_constructible_trait> \ : public move_constructor> { \ using super = move_constructor>; \ \ public: \ C10_MPARK_INHERITING_CTOR(copy_constructor, super) \ using super::operator=; \ \ definition copy_constructor(copy_constructor&&) = default; \ ~copy_constructor() = default; \ copy_constructor& operator=(const copy_constructor&) = default; \ copy_constructor& operator=(copy_constructor&&) = default; \ } C10_MPARK_VARIANT_COPY_CONSTRUCTOR( Trait::TriviallyAvailable, copy_constructor(const copy_constructor& that) = default;); C10_MPARK_VARIANT_COPY_CONSTRUCTOR( Trait::Available, copy_constructor(const copy_constructor& that) : copy_constructor(valueless_t{}) { this->generic_construct(*this, that); }); C10_MPARK_VARIANT_COPY_CONSTRUCTOR( Trait::Unavailable, copy_constructor(const copy_constructor&) = delete;); #undef C10_MPARK_VARIANT_COPY_CONSTRUCTOR template class assignment : public copy_constructor { using super = copy_constructor; public: C10_MPARK_INHERITING_CTOR(assignment, super) using super::operator=; template inline /* auto & */ auto emplace(Args&&... args) -> decltype(this->construct_alt( access::base::get_alt(*this), lib::forward(args)...)) { this->destroy(); auto& result = this->construct_alt( access::base::get_alt(*this), lib::forward(args)...); this->index_ = I; return result; } protected: #ifndef C10_MPARK_GENERIC_LAMBDAS template struct assigner { template inline void operator()(ThisAlt& this_alt, ThatAlt&& that_alt) const { self->assign_alt(this_alt, lib::forward(that_alt).value); } assignment* self; }; #endif template inline void assign_alt(alt& a, Arg&& arg) { if (this->index() == I) { #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4244) #endif a.value = lib::forward(arg); #ifdef _MSC_VER #pragma warning(pop) #endif } else { struct { void operator()(std::true_type) const { this_->emplace(lib::forward(arg_)); } void operator()(std::false_type) const { this_->emplace(T(lib::forward(arg_))); } assignment* this_; Arg&& arg_; } impl{this, lib::forward(arg)}; impl( lib::bool_constant < std::is_nothrow_constructible::value || !std::is_nothrow_move_constructible::value > {}); } } template inline void generic_assign(That&& that) { if (this->valueless_by_exception() && that.valueless_by_exception()) { // do nothing. } else if (that.valueless_by_exception()) { this->destroy(); } else { visitation::alt::visit_alt_at( that.index(), #ifdef C10_MPARK_GENERIC_LAMBDAS [this](auto& this_alt, auto&& that_alt) { this->assign_alt( this_alt, lib::forward(that_alt).value); } #else assigner { this } #endif , *this, lib::forward(that)); } } }; template class move_assignment; #define C10_MPARK_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, definition) \ template \ class move_assignment, move_assignable_trait> \ : public assignment> { \ using super = assignment>; \ \ public: \ C10_MPARK_INHERITING_CTOR(move_assignment, super) \ using super::operator=; \ \ move_assignment(const move_assignment&) = default; \ move_assignment(move_assignment&&) = default; \ ~move_assignment() = default; \ move_assignment& operator=(const move_assignment&) = default; \ definition \ } C10_MPARK_VARIANT_MOVE_ASSIGNMENT( Trait::TriviallyAvailable, move_assignment& operator=(move_assignment&& that) = default;); C10_MPARK_VARIANT_MOVE_ASSIGNMENT( Trait::Available, move_assignment& operator=(move_assignment&& that) noexcept( lib::all< (std::is_nothrow_move_constructible::value && std::is_nothrow_move_assignable::value)...>::value) { this->generic_assign(lib::move(that)); return *this; }); C10_MPARK_VARIANT_MOVE_ASSIGNMENT( Trait::Unavailable, move_assignment& operator=(move_assignment&&) = delete;); #undef C10_MPARK_VARIANT_MOVE_ASSIGNMENT template class copy_assignment; #define C10_MPARK_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, definition) \ template \ class copy_assignment, copy_assignable_trait> \ : public move_assignment> { \ using super = move_assignment>; \ \ public: \ C10_MPARK_INHERITING_CTOR(copy_assignment, super) \ using super::operator=; \ \ copy_assignment(const copy_assignment&) = default; \ copy_assignment(copy_assignment&&) = default; \ ~copy_assignment() = default; \ definition copy_assignment& operator=(copy_assignment&&) = default; \ } C10_MPARK_VARIANT_COPY_ASSIGNMENT( Trait::TriviallyAvailable, copy_assignment& operator=(const copy_assignment& that) = default;); C10_MPARK_VARIANT_COPY_ASSIGNMENT( Trait::Available, copy_assignment& operator=(const copy_assignment& that) { this->generic_assign(that); return *this; }); C10_MPARK_VARIANT_COPY_ASSIGNMENT( Trait::Unavailable, copy_assignment& operator=(const copy_assignment&) = delete;); #undef C10_MPARK_VARIANT_COPY_ASSIGNMENT template class impl : public copy_assignment> { using super = copy_assignment>; public: C10_MPARK_INHERITING_CTOR(impl, super) impl& operator=(const impl& other) = default; template inline void assign(Arg&& arg) { this->assign_alt(access::base::get_alt(*this), lib::forward(arg)); } inline void swap(impl& that) { if (this->valueless_by_exception() && that.valueless_by_exception()) { // do nothing. } else if (this->index() == that.index()) { visitation::alt::visit_alt_at( this->index(), #ifdef C10_MPARK_GENERIC_LAMBDAS [](auto& this_alt, auto& that_alt) { using std::swap; swap(this_alt.value, that_alt.value); } #else swapper {} #endif , *this, that); } else { impl* lhs = this; impl* rhs = lib::addressof(that); if (lhs->move_nothrow() && !rhs->move_nothrow()) { std::swap(lhs, rhs); } impl tmp(lib::move(*rhs)); #ifdef C10_MPARK_EXCEPTIONS // EXTENSION: When the move construction of `lhs` into `rhs` throws // and `tmp` is nothrow move constructible then we move `tmp` back // into `rhs` and provide the strong exception safety guarantee. try { this->generic_construct(*rhs, lib::move(*lhs)); } catch (...) { if (tmp.move_nothrow()) { this->generic_construct(*rhs, lib::move(tmp)); } throw; } #else this->generic_construct(*rhs, lib::move(*lhs)); #endif this->generic_construct(*lhs, lib::move(tmp)); } } private: #ifndef C10_MPARK_GENERIC_LAMBDAS struct swapper { template inline void operator()(ThisAlt& this_alt, ThatAlt& that_alt) const { using std::swap; swap(this_alt.value, that_alt.value); } }; #endif inline constexpr bool move_nothrow() const { return this->valueless_by_exception() || lib::array{ {std::is_nothrow_move_constructible::value...}}[this->index()]; } }; #undef C10_MPARK_INHERITING_CTOR template struct overload_leaf { using F = lib::size_constant (*)(T); operator F() const { return nullptr; } }; template struct overload_impl { private: template struct impl; template struct impl> : overload_leaf... {}; public: using type = impl>; }; template using overload = typename overload_impl::type; template using best_match = lib::invoke_result_t, T&&>; template struct is_in_place_index : std::false_type {}; template struct is_in_place_index> : std::true_type {}; template struct is_in_place_type : std::false_type {}; template struct is_in_place_type> : std::true_type {}; } // namespace detail_ template class variant { static_assert( 0 < sizeof...(Ts), "variant must consist of at least one alternative."); static_assert( lib::all::value...>::value, "variant can not have an array type as an alternative."); static_assert( lib::all::value...>::value, "variant can not have a reference type as an alternative."); static_assert( lib::all::value...>::value, "variant can not have a void type as an alternative."); public: template < typename Front = lib::type_pack_element_t<0, Ts...>, lib::enable_if_t::value, int> = 0> inline constexpr variant() noexcept( std::is_nothrow_default_constructible::value) : impl_(in_place_index_t<0>{}) {} variant(const variant&) = default; variant(variant&&) = default; // NOTE [gcc 7.3.1 bug workaround] // // The original line `typename T = lib::type_pack_element_t` // throws the following compiler error on gcc 7.3.1: // ``` // ../c10/util/variant.h:2250:9: internal compiler error: // unexpected expression ā€˜Iā€™ of kind template_parm_index // typename T = lib::type_pack_element_t, // ^~~~~~~~ // ``` // As a workaround, `I` is changed to `detail_::best_match::value`, which is the default value for `I` in this template. Note // that this workaround effectively disallows setting `I` to any other // non-default value, and we add a `static_assert` in the function body to // check for this. // // See the following issues for more context: // - https://github.com/mpark/variant/issues/43 // - https://github.com/eggs-cpp/variant/issues/31 template < typename Arg, typename Decayed = lib::decay_t, lib::enable_if_t::value, int> = 0, lib::enable_if_t::value, int> = 0, lib::enable_if_t::value, int> = 0, std::size_t I = detail_::best_match::value, typename T = lib:: type_pack_element_t::value, Ts...>, lib::enable_if_t::value, int> = 0> inline constexpr variant(Arg&& arg) noexcept( std::is_nothrow_constructible::value) : impl_(in_place_index_t{}, lib::forward(arg)) { static_assert( I == detail_::best_match::value, "Setting template parameter `I` to a custom non-default value is not supported. " "Please file a feature request if you see this."); } template < std::size_t I, typename... Args, typename T = lib::type_pack_element_t, lib::enable_if_t::value, int> = 0> inline explicit constexpr variant( in_place_index_t, Args&&... args) noexcept(std::is_nothrow_constructible::value) : impl_(in_place_index_t{}, lib::forward(args)...) {} template < std::size_t I, typename Up, typename... Args, typename T = lib::type_pack_element_t, lib::enable_if_t< std::is_constructible&, Args...>::value, int> = 0> inline explicit constexpr variant( in_place_index_t, std::initializer_list il, Args&&... args) noexcept(std:: is_nothrow_constructible< T, std::initializer_list&, Args...>::value) : impl_(in_place_index_t{}, il, lib::forward(args)...) {} template < typename T, typename... Args, std::size_t I = detail_::find_index_sfinae::value, lib::enable_if_t::value, int> = 0> inline explicit constexpr variant( in_place_type_t, Args&&... args) noexcept(std::is_nothrow_constructible::value) : impl_(in_place_index_t{}, lib::forward(args)...) {} template < typename T, typename Up, typename... Args, std::size_t I = detail_::find_index_sfinae::value, lib::enable_if_t< std::is_constructible&, Args...>::value, int> = 0> inline explicit constexpr variant( in_place_type_t, std::initializer_list il, Args&&... args) noexcept(std:: is_nothrow_constructible< T, std::initializer_list&, Args...>::value) : impl_(in_place_index_t{}, il, lib::forward(args)...) {} ~variant() = default; variant& operator=(const variant&) = default; variant& operator=(variant&&) = default; // NOTE: See NOTE [gcc 7.3.1 bug workaround] for the changes made to this // function. template < typename Arg, lib::enable_if_t, variant>::value, int> = 0, std::size_t I = detail_::best_match::value, typename T = lib:: type_pack_element_t::value, Ts...>, lib::enable_if_t< (std::is_assignable::value && std::is_constructible::value), int> = 0> inline variant& operator=(Arg&& arg) noexcept( (std::is_nothrow_assignable::value && std::is_nothrow_constructible::value)) { static_assert( I == detail_::best_match::value, "Setting template parameter `I` to a custom non-default value is not supported. " "Please file a feature request if you see this."); impl_.template assign(lib::forward(arg)); return *this; } template < std::size_t I, typename... Args, typename T = lib::type_pack_element_t, lib::enable_if_t::value, int> = 0> inline T& emplace(Args&&... args) { return impl_.template emplace(lib::forward(args)...); } template < std::size_t I, typename Up, typename... Args, typename T = lib::type_pack_element_t, lib::enable_if_t< std::is_constructible&, Args...>::value, int> = 0> inline T& emplace(std::initializer_list il, Args&&... args) { return impl_.template emplace(il, lib::forward(args)...); } template < typename T, typename... Args, std::size_t I = detail_::find_index_sfinae::value, lib::enable_if_t::value, int> = 0> inline T& emplace(Args&&... args) { return impl_.template emplace(lib::forward(args)...); } template < typename T, typename Up, typename... Args, std::size_t I = detail_::find_index_sfinae::value, lib::enable_if_t< std::is_constructible&, Args...>::value, int> = 0> inline T& emplace(std::initializer_list il, Args&&... args) { return impl_.template emplace(il, lib::forward(args)...); } inline constexpr bool valueless_by_exception() const noexcept { return impl_.valueless_by_exception(); } inline constexpr std::size_t index() const noexcept { return impl_.index(); } template < bool Dummy = true, lib::enable_if_t< lib::all< Dummy, (lib::dependent_type, Dummy>:: value && lib::dependent_type, Dummy>::value)...>:: value, int> = 0> inline void swap(variant& that) noexcept( lib::all< (std::is_nothrow_move_constructible::value && lib::is_nothrow_swappable::value)...>::value) { impl_.swap(that.impl_); } private: detail_::impl impl_; friend struct detail_::access::variant; friend struct detail_::visitation::variant; }; template inline constexpr bool holds_alternative(const variant& v) noexcept { return v.index() == I; } template inline constexpr bool holds_alternative(const variant& v) noexcept { return holds_alternative::value>(v); } namespace detail_ { template struct generic_get_impl { constexpr generic_get_impl(int) noexcept {} constexpr AUTO_REFREF operator()(V&& v) const AUTO_REFREF_RETURN(access::variant::get_alt(lib::forward(v)).value) }; template inline constexpr AUTO_REFREF generic_get(V&& v) AUTO_REFREF_RETURN(generic_get_impl( holds_alternative(v) ? 0 : (throw_bad_variant_access(), 0))(lib::forward(v))) } // namespace detail_ template inline constexpr variant_alternative_t>& get( variant& v) { return detail_::generic_get(v); } template inline constexpr variant_alternative_t>&& get( variant&& v) { return detail_::generic_get(lib::move(v)); } template inline constexpr const variant_alternative_t>& get( const variant& v) { return detail_::generic_get(v); } template inline constexpr const variant_alternative_t>&& get( const variant&& v) { return detail_::generic_get(lib::move(v)); } template inline constexpr T& get(variant& v) { return get::value>(v); } template inline constexpr T&& get(variant&& v) { return get::value>(lib::move(v)); } template inline constexpr const T& get(const variant& v) { return get::value>(v); } template inline constexpr const T&& get(const variant&& v) { return get::value>(lib::move(v)); } namespace detail_ { template inline constexpr /* auto * */ AUTO generic_get_if(V* v) noexcept AUTO_RETURN( v&& holds_alternative(*v) ? lib::addressof(access::variant::get_alt(*v).value) : nullptr) } // namespace detail_ template inline constexpr lib::add_pointer_t>> get_if(variant* v) noexcept { return detail_::generic_get_if(v); } template inline constexpr lib::add_pointer_t< const variant_alternative_t>> get_if(const variant* v) noexcept { return detail_::generic_get_if(v); } template inline constexpr lib::add_pointer_t get_if(variant* v) noexcept { return get_if::value>(v); } template inline constexpr lib::add_pointer_t get_if( const variant* v) noexcept { return get_if::value>(v); } namespace detail_ { template struct convert_to_bool { template inline constexpr bool operator()(Lhs&& lhs, Rhs&& rhs) const { static_assert( std::is_convertible, bool>::value, "relational operators must return a type" " implicitly convertible to bool"); return lib::invoke(RelOp{}, lib::forward(lhs), lib::forward(rhs)); } }; } // namespace detail_ template inline constexpr bool operator==( const variant& lhs, const variant& rhs) { using detail_::visitation::variant; using equal_to = detail_::convert_to_bool; #ifdef C10_MPARK_CPP14_CONSTEXPR if (lhs.index() != rhs.index()) return false; if (lhs.valueless_by_exception()) return true; return variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs); #else return lhs.index() == rhs.index() && (lhs.valueless_by_exception() || variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs)); #endif } template inline constexpr bool operator!=( const variant& lhs, const variant& rhs) { using detail_::visitation::variant; using not_equal_to = detail_::convert_to_bool; #ifdef C10_MPARK_CPP14_CONSTEXPR if (lhs.index() != rhs.index()) return true; if (lhs.valueless_by_exception()) return false; return variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs); #else return lhs.index() != rhs.index() || (!lhs.valueless_by_exception() && variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs)); #endif } template inline constexpr bool operator<( const variant& lhs, const variant& rhs) { using detail_::visitation::variant; using less = detail_::convert_to_bool; #ifdef C10_MPARK_CPP14_CONSTEXPR if (rhs.valueless_by_exception()) return false; if (lhs.valueless_by_exception()) return true; if (lhs.index() < rhs.index()) return true; if (lhs.index() > rhs.index()) return false; return variant::visit_value_at(lhs.index(), less{}, lhs, rhs); #else return !rhs.valueless_by_exception() && (lhs.valueless_by_exception() || lhs.index() < rhs.index() || (lhs.index() == rhs.index() && variant::visit_value_at(lhs.index(), less{}, lhs, rhs))); #endif } template inline constexpr bool operator>( const variant& lhs, const variant& rhs) { using detail_::visitation::variant; using greater = detail_::convert_to_bool; #ifdef C10_MPARK_CPP14_CONSTEXPR if (lhs.valueless_by_exception()) return false; if (rhs.valueless_by_exception()) return true; if (lhs.index() > rhs.index()) return true; if (lhs.index() < rhs.index()) return false; return variant::visit_value_at(lhs.index(), greater{}, lhs, rhs); #else return !lhs.valueless_by_exception() && (rhs.valueless_by_exception() || lhs.index() > rhs.index() || (lhs.index() == rhs.index() && variant::visit_value_at(lhs.index(), greater{}, lhs, rhs))); #endif } template inline constexpr bool operator<=( const variant& lhs, const variant& rhs) { using detail_::visitation::variant; using less_equal = detail_::convert_to_bool; #ifdef C10_MPARK_CPP14_CONSTEXPR if (lhs.valueless_by_exception()) return true; if (rhs.valueless_by_exception()) return false; if (lhs.index() < rhs.index()) return true; if (lhs.index() > rhs.index()) return false; return variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs); #else return lhs.valueless_by_exception() || (!rhs.valueless_by_exception() && (lhs.index() < rhs.index() || (lhs.index() == rhs.index() && variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs)))); #endif } template inline constexpr bool operator>=( const variant& lhs, const variant& rhs) { using detail_::visitation::variant; using greater_equal = detail_::convert_to_bool; #ifdef C10_MPARK_CPP14_CONSTEXPR if (rhs.valueless_by_exception()) return true; if (lhs.valueless_by_exception()) return false; if (lhs.index() > rhs.index()) return true; if (lhs.index() < rhs.index()) return false; return variant::visit_value_at(lhs.index(), greater_equal{}, lhs, rhs); #else return rhs.valueless_by_exception() || (!lhs.valueless_by_exception() && (lhs.index() > rhs.index() || (lhs.index() == rhs.index() && variant::visit_value_at(lhs.index(), greater_equal{}, lhs, rhs)))); #endif } struct monostate {}; inline constexpr bool operator<(monostate, monostate) noexcept { return false; } inline constexpr bool operator>(monostate, monostate) noexcept { return false; } inline constexpr bool operator<=(monostate, monostate) noexcept { return true; } inline constexpr bool operator>=(monostate, monostate) noexcept { return true; } inline constexpr bool operator==(monostate, monostate) noexcept { return true; } inline constexpr bool operator!=(monostate, monostate) noexcept { return false; } #ifdef C10_MPARK_CPP14_CONSTEXPR namespace detail_ { inline constexpr bool any(std::initializer_list bs) { for (bool b : bs) { if (b) { return true; } } return false; } } // namespace detail_ template inline constexpr decltype(auto) visit(Visitor&& visitor, Vs&&... vs) { return (!detail_::any({vs.valueless_by_exception()...}) ? (void)0 : throw_bad_variant_access()), detail_::visitation::variant::visit_value( lib::forward(visitor), lib::forward(vs)...); } #else namespace detail_ { template inline constexpr bool all_impl(const lib::array& bs, std::size_t idx) { return idx >= N || (bs[idx] && all_impl(bs, idx + 1)); } template inline constexpr bool all(const lib::array& bs) { return all_impl(bs, 0); } } // namespace detail_ template inline constexpr DECLTYPE_AUTO visit(Visitor&& visitor, Vs&&... vs) DECLTYPE_AUTO_RETURN( (detail_::all(lib::array{ {!vs.valueless_by_exception()...}}) ? (void)0 : throw_bad_variant_access()), detail_::visitation::variant::visit_value( lib::forward(visitor), lib::forward(vs)...)) #endif template inline auto swap(variant& lhs, variant& rhs) noexcept( noexcept(lhs.swap(rhs))) -> decltype(lhs.swap(rhs)) { lhs.swap(rhs); } namespace detail_ { template using enabled_type = T; namespace hash { template constexpr bool meets_requirements() noexcept { return std::is_copy_constructible::value && std::is_move_constructible::value && lib::is_invocable_r::value; } template constexpr bool is_enabled() noexcept { using H = std::hash; return meets_requirements() && std::is_default_constructible::value && std::is_copy_assignable::value && std::is_move_assignable::value; } } // namespace hash } // namespace detail_ #undef AUTO #undef AUTO_RETURN #undef AUTO_REFREF #undef AUTO_REFREF_RETURN #undef DECLTYPE_AUTO #undef DECLTYPE_AUTO_RETURN } // namespace c10 namespace std { template struct hash, c10::lib::enable_if_t>()...>::value>>> { using argument_type = c10::variant; using result_type = std::size_t; inline result_type operator()(const argument_type& v) const { using c10::detail_::visitation::variant; std::size_t result = v.valueless_by_exception() ? 299792458 // Random value chosen by the universe upon creation : variant::visit_alt( #ifdef C10_MPARK_GENERIC_LAMBDAS [](const auto& alt) { using alt_type = c10::lib::decay_t; using value_type = c10::lib::remove_const_t; return hash{}(alt.value); } #else hasher {} #endif , v); return hash_combine(result, hash{}(v.index())); } private: #ifndef C10_MPARK_GENERIC_LAMBDAS struct hasher { template inline std::size_t operator()(const Alt& alt) const { using alt_type = c10::lib::decay_t; using value_type = c10::lib::remove_const_t; return hash{}(alt.value); } }; #endif static std::size_t hash_combine(std::size_t lhs, std::size_t rhs) { return lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2); } }; template <> struct hash { using argument_type = c10::monostate; using result_type = std::size_t; inline result_type operator()(const argument_type&) const noexcept { return 66740831; // return a fundamentally attractive random value. } }; } // namespace std #endif // C10_UTIL_VARIANT_H_