| // 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<Arg, Ts...>::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 <std::size_t I> |
| // struct in_place_index_t { explicit in_place_index_t() = default; }; |
| // |
| // template <typename T> |
| // 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... Types> |
| class variant { |
| public: |
| |
| // 20.7.2.1, constructors |
| constexpr variant() noexcept(see below); |
| variant(const variant&); |
| variant(variant&&) noexcept(see below); |
| |
| template <class T> constexpr variant(T&&) noexcept(see below); |
| |
| template <class T, class... Args> |
| constexpr explicit variant(in_place_type_t<T>, Args&&...); |
| |
| template <class T, class U, class... Args> |
| constexpr explicit variant( |
| in_place_type_t<T>, initializer_list<U>, Args&&...); |
| |
| template <size_t I, class... Args> |
| constexpr explicit variant(in_place_index_t<I>, Args&&...); |
| |
| template <size_t I, class U, class... Args> |
| constexpr explicit variant( |
| in_place_index_t<I>, initializer_list<U>, Args&&...); |
| |
| // 20.7.2.2, destructor |
| ~variant(); |
| |
| // 20.7.2.3, assignment |
| variant& operator=(const variant&); |
| variant& operator=(variant&&) noexcept(see below); |
| |
| template <class T> variant& operator=(T&&) noexcept(see below); |
| |
| // 20.7.2.4, modifiers |
| template <class T, class... Args> |
| T& emplace(Args&&...); |
| |
| template <class T, class U, class... Args> |
| T& emplace(initializer_list<U>, Args&&...); |
| |
| template <size_t I, class... Args> |
| variant_alternative<I, variant>& emplace(Args&&...); |
| |
| template <size_t I, class U, class... Args> |
| variant_alternative<I, variant>& emplace(initializer_list<U>, 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 <class T> struct variant_size; // undefined |
| |
| template <class T> |
| constexpr size_t variant_size_v = variant_size<T>::value; |
| |
| template <class T> struct variant_size<const T>; |
| template <class T> struct variant_size<volatile T>; |
| template <class T> struct variant_size<const volatile T>; |
| |
| template <class... Types> |
| struct variant_size<variant<Types...>>; |
| |
| template <size_t I, class T> struct variant_alternative; // undefined |
| |
| template <size_t I, class T> |
| using variant_alternative_t = typename variant_alternative<I, T>::type; |
| |
| template <size_t I, class T> struct variant_alternative<I, const T>; |
| template <size_t I, class T> struct variant_alternative<I, volatile T>; |
| template <size_t I, class T> struct variant_alternative<I, const volatile T>; |
| |
| template <size_t I, class... Types> |
| struct variant_alternative<I, variant<Types...>>; |
| |
| constexpr size_t variant_npos = -1; |
| |
| // 20.7.4, value access |
| template <class T, class... Types> |
| constexpr bool holds_alternative(const variant<Types...>&) noexcept; |
| |
| template <size_t I, class... Types> |
| constexpr variant_alternative_t<I, variant<Types...>>& |
| get(variant<Types...>&); |
| |
| template <size_t I, class... Types> |
| constexpr variant_alternative_t<I, variant<Types...>>&& |
| get(variant<Types...>&&); |
| |
| template <size_t I, class... Types> |
| constexpr variant_alternative_t<I, variant<Types...>> const& |
| get(const variant<Types...>&); |
| |
| template <size_t I, class... Types> |
| constexpr variant_alternative_t<I, variant<Types...>> const&& |
| get(const variant<Types...>&&); |
| |
| template <class T, class... Types> |
| constexpr T& get(variant<Types...>&); |
| |
| template <class T, class... Types> |
| constexpr T&& get(variant<Types...>&&); |
| |
| template <class T, class... Types> |
| constexpr const T& get(const variant<Types...>&); |
| |
| template <class T, class... Types> |
| constexpr const T&& get(const variant<Types...>&&); |
| |
| template <size_t I, class... Types> |
| constexpr add_pointer_t<variant_alternative_t<I, variant<Types...>>> |
| get_if(variant<Types...>*) noexcept; |
| |
| template <size_t I, class... Types> |
| constexpr add_pointer_t<const variant_alternative_t<I, variant<Types...>>> |
| get_if(const variant<Types...>*) noexcept; |
| |
| template <class T, class... Types> |
| constexpr add_pointer_t<T> |
| get_if(variant<Types...>*) noexcept; |
| |
| template <class T, class... Types> |
| constexpr add_pointer_t<const T> |
| get_if(const variant<Types...>*) noexcept; |
| |
| // 20.7.5, relational operators |
| template <class... Types> |
| constexpr bool operator==(const variant<Types...>&, const variant<Types...>&); |
| |
| template <class... Types> |
| constexpr bool operator!=(const variant<Types...>&, const variant<Types...>&); |
| |
| template <class... Types> |
| constexpr bool operator<(const variant<Types...>&, const variant<Types...>&); |
| |
| template <class... Types> |
| constexpr bool operator>(const variant<Types...>&, const variant<Types...>&); |
| |
| template <class... Types> |
| constexpr bool operator<=(const variant<Types...>&, const variant<Types...>&); |
| |
| template <class... Types> |
| constexpr bool operator>=(const variant<Types...>&, const variant<Types...>&); |
| |
| // 20.7.6, visitation |
| template <class Visitor, class... Variants> |
| 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 <class... Types> |
| void swap(variant<Types...>&, variant<Types...>&) noexcept(see below); |
| |
| // 20.7.10, class bad_variant_access |
| class bad_variant_access; |
| |
| // 20.7.11, hash support |
| template <class T> struct hash; |
| template <class... Types> struct hash<variant<Types...>>; |
| template <> struct hash<monostate>; |
| |
| } // namespace std |
| |
| */ |
| |
| #include <cstddef> |
| #include <exception> |
| #include <functional> |
| #include <initializer_list> |
| #include <new> |
| #include <type_traits> |
| #include <utility> |
| |
| // 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 |
| |
| // NOTE [nvcc bug workaround] |
| // |
| // The original line `typename Front = lib::type_pack_element_t<0, Ts...>,` |
| // throws the following compiler error on nvcc: |
| // ``` |
| // c10/util/variant.h(2367): error: parameter pack "Ts" was referenced but not |
| // expanded |
| // ``` |
| // As a workaround, we skip defining C10_MPARK_TYPE_PACK_ELEMENT for nvcc |
| // compiler |
| // |
| // See the following issues for more context: |
| // https://github.com/pytorch/extension-cpp/issues/58 |
| // https://github.com/mpark/variant/issues/77 |
| #if __has_builtin(__type_pack_element) && !defined(__CUDACC__) |
| #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(<codecvt>) // >= libstdc++-5 |
| #define C10_MPARK_TRIVIALITY_TYPE_TRAITS |
| #define C10_MPARK_INCOMPLETE_TYPE_TRAITS |
| #endif |
| |
| #ifdef _WIN32 |
| #define C10_MPARK_VISIBILITY_HIDDEN |
| #else |
| #define C10_MPARK_VISIBILITY_HIDDEN __attribute__((visibility("hidden"))) |
| #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 <c10/util/in_place.h> |
| |
| #include <cstddef> |
| |
| namespace c10 { |
| |
| #ifdef C10_MPARK_VARIABLE_TEMPLATES |
| template <std::size_t I> |
| constexpr in_place_index_t<I> in_place_index{}; |
| |
| template <typename T> |
| constexpr in_place_type_t<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 <functional> |
| #include <memory> |
| #include <type_traits> |
| #include <utility> |
| |
| #define C10_MPARK_RETURN(...) \ |
| noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) { \ |
| return __VA_ARGS__; \ |
| } |
| |
| namespace c10 { |
| namespace lib { |
| template <typename T> |
| struct identity { |
| using type = T; |
| }; |
| |
| inline namespace cpp14 { |
| template <typename T, std::size_t N> |
| struct array { |
| constexpr const T& operator[](std::size_t index) const { |
| return data[index]; |
| } |
| |
| T data[N == 0 ? 1 : N]; |
| }; |
| |
| template <typename T> |
| using add_pointer_t = typename std::add_pointer<T>::type; |
| |
| template <typename... Ts> |
| using common_type_t = typename std::common_type<Ts...>::type; |
| |
| template <typename T> |
| using decay_t = typename std::decay<T>::type; |
| |
| template <bool B, typename T = void> |
| using enable_if_t = typename std::enable_if<B, T>::type; |
| |
| template <typename T> |
| using remove_const_t = typename std::remove_const<T>::type; |
| |
| template <typename T> |
| using remove_reference_t = typename std::remove_reference<T>::type; |
| |
| template <typename T> |
| inline constexpr T&& forward(remove_reference_t<T>& t) noexcept { |
| return static_cast<T&&>(t); |
| } |
| |
| template <typename T> |
| inline constexpr T&& forward(remove_reference_t<T>&& t) noexcept { |
| static_assert( |
| !std::is_lvalue_reference<T>::value, |
| "can not forward an rvalue as an lvalue"); |
| return static_cast<T&&>(t); |
| } |
| |
| template <typename T> |
| inline constexpr remove_reference_t<T>&& move(T&& t) noexcept { |
| return static_cast<remove_reference_t<T>&&>(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 <typename T, T... Is> |
| struct integer_sequence { |
| using value_type = T; |
| static constexpr std::size_t size() noexcept { |
| return sizeof...(Is); |
| } |
| }; |
| |
| template <std::size_t... Is> |
| using index_sequence = integer_sequence<std::size_t, Is...>; |
| |
| template <typename Lhs, typename Rhs> |
| struct make_index_sequence_concat; |
| |
| template <std::size_t... Lhs, std::size_t... Rhs> |
| struct make_index_sequence_concat< |
| index_sequence<Lhs...>, |
| index_sequence<Rhs...>> |
| : identity<index_sequence<Lhs..., (sizeof...(Lhs) + Rhs)...>> {}; |
| |
| template <std::size_t N> |
| struct make_index_sequence_impl; |
| |
| template <std::size_t N> |
| using make_index_sequence = typename make_index_sequence_impl<N>::type; |
| |
| template <std::size_t N> |
| struct make_index_sequence_impl : make_index_sequence_concat< |
| make_index_sequence<N / 2>, |
| make_index_sequence<N - (N / 2)>> {}; |
| |
| template <> |
| struct make_index_sequence_impl<0> : identity<index_sequence<>> {}; |
| |
| template <> |
| struct make_index_sequence_impl<1> : identity<index_sequence<0>> {}; |
| |
| template <typename... Ts> |
| using index_sequence_for = make_index_sequence<sizeof...(Ts)>; |
| #endif |
| |
| // <functional> |
| #ifdef C10_MPARK_TRANSPARENT_OPERATORS |
| using equal_to = std::equal_to<>; |
| #else |
| struct equal_to { |
| template <typename Lhs, typename Rhs> |
| inline constexpr auto operator()(Lhs&& lhs, Rhs&& rhs) const |
| C10_MPARK_RETURN(lib::forward<Lhs>(lhs) == lib::forward<Rhs>(rhs)) |
| }; |
| #endif |
| |
| #ifdef C10_MPARK_TRANSPARENT_OPERATORS |
| using not_equal_to = std::not_equal_to<>; |
| #else |
| struct not_equal_to { |
| template <typename Lhs, typename Rhs> |
| inline constexpr auto operator()(Lhs&& lhs, Rhs&& rhs) const |
| C10_MPARK_RETURN(lib::forward<Lhs>(lhs) != lib::forward<Rhs>(rhs)) |
| }; |
| #endif |
| |
| #ifdef C10_MPARK_TRANSPARENT_OPERATORS |
| using less = std::less<>; |
| #else |
| struct less { |
| template <typename Lhs, typename Rhs> |
| inline constexpr auto operator()(Lhs&& lhs, Rhs&& rhs) const |
| C10_MPARK_RETURN(lib::forward<Lhs>(lhs) < lib::forward<Rhs>(rhs)) |
| }; |
| #endif |
| |
| #ifdef C10_MPARK_TRANSPARENT_OPERATORS |
| using greater = std::greater<>; |
| #else |
| struct greater { |
| template <typename Lhs, typename Rhs> |
| inline constexpr auto operator()(Lhs&& lhs, Rhs&& rhs) const |
| C10_MPARK_RETURN(lib::forward<Lhs>(lhs) > lib::forward<Rhs>(rhs)) |
| }; |
| #endif |
| |
| #ifdef C10_MPARK_TRANSPARENT_OPERATORS |
| using less_equal = std::less_equal<>; |
| #else |
| struct less_equal { |
| template <typename Lhs, typename Rhs> |
| inline constexpr auto operator()(Lhs&& lhs, Rhs&& rhs) const |
| C10_MPARK_RETURN(lib::forward<Lhs>(lhs) <= lib::forward<Rhs>(rhs)) |
| }; |
| #endif |
| |
| #ifdef C10_MPARK_TRANSPARENT_OPERATORS |
| using greater_equal = std::greater_equal<>; |
| #else |
| struct greater_equal { |
| template <typename Lhs, typename Rhs> |
| inline constexpr auto operator()(Lhs&& lhs, Rhs&& rhs) const |
| C10_MPARK_RETURN(lib::forward<Lhs>(lhs) >= lib::forward<Rhs>(rhs)) |
| }; |
| #endif |
| } // namespace cpp14 |
| |
| inline namespace cpp17 { |
| |
| // <type_traits> |
| template <bool B> |
| using bool_constant = std::integral_constant<bool, B>; |
| |
| template <typename...> |
| struct voider : identity<void> {}; |
| |
| template <typename... Ts> |
| using void_t = typename voider<Ts...>::type; |
| |
| namespace detail_ { |
| namespace swappable { |
| |
| using std::swap; |
| |
| template <typename T> |
| struct is_swappable { |
| private: |
| template < |
| typename U, |
| typename = decltype(swap(std::declval<U&>(), std::declval<U&>()))> |
| inline static std::true_type test(int); |
| |
| template <typename U> |
| inline static std::false_type test(...); |
| |
| public: |
| static constexpr bool value = decltype(test<T>(0))::value; |
| }; |
| |
| template <bool IsSwappable, typename T> |
| struct is_nothrow_swappable { |
| static constexpr bool value = |
| noexcept(swap(std::declval<T&>(), std::declval<T&>())); |
| }; |
| |
| template <typename T> |
| struct is_nothrow_swappable<false, T> : std::false_type {}; |
| |
| } // namespace swappable |
| } // namespace detail_ |
| |
| using detail_::swappable::is_swappable; |
| |
| template <typename T> |
| using is_nothrow_swappable = |
| detail_::swappable::is_nothrow_swappable<is_swappable<T>::value, T>; |
| |
| // <functional> |
| namespace detail_ { |
| |
| template <typename T> |
| struct is_reference_wrapper : std::false_type {}; |
| |
| template <typename T> |
| struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {}; |
| |
| template <bool, int> |
| struct Invoke; |
| |
| template <> |
| struct Invoke<true /* pmf */, 0 /* is_base_of */> { |
| template <typename R, typename T, typename Arg, typename... Args> |
| inline static constexpr auto invoke(R T::*pmf, Arg&& arg, Args&&... args) |
| C10_MPARK_RETURN( |
| (lib::forward<Arg>(arg).*pmf)(lib::forward<Args>(args)...)) |
| }; |
| |
| template <> |
| struct Invoke<true /* pmf */, 1 /* is_reference_wrapper */> { |
| template <typename R, typename T, typename Arg, typename... Args> |
| inline static constexpr auto invoke(R T::*pmf, Arg&& arg, Args&&... args) |
| C10_MPARK_RETURN( |
| (lib::forward<Arg>(arg).get().*pmf)(lib::forward<Args>(args)...)) |
| }; |
| |
| template <> |
| struct Invoke<true /* pmf */, 2 /* otherwise */> { |
| template <typename R, typename T, typename Arg, typename... Args> |
| inline static constexpr auto invoke(R T::*pmf, Arg&& arg, Args&&... args) |
| C10_MPARK_RETURN( |
| ((*lib::forward<Arg>(arg)).*pmf)(lib::forward<Args>(args)...)) |
| }; |
| |
| template <> |
| struct Invoke<false /* pmo */, 0 /* is_base_of */> { |
| template <typename R, typename T, typename Arg> |
| inline static constexpr auto invoke(R T::*pmo, Arg&& arg) |
| C10_MPARK_RETURN(lib::forward<Arg>(arg).*pmo) |
| }; |
| |
| template <> |
| struct Invoke<false /* pmo */, 1 /* is_reference_wrapper */> { |
| template <typename R, typename T, typename Arg> |
| inline static constexpr auto invoke(R T::*pmo, Arg&& arg) |
| C10_MPARK_RETURN(lib::forward<Arg>(arg).get().*pmo) |
| }; |
| |
| template <> |
| struct Invoke<false /* pmo */, 2 /* otherwise */> { |
| template <typename R, typename T, typename Arg> |
| inline static constexpr auto invoke(R T::*pmo, Arg&& arg) |
| C10_MPARK_RETURN((*lib::forward<Arg>(arg)).*pmo) |
| }; |
| |
| template <typename R, typename T, typename Arg, typename... Args> |
| inline constexpr auto invoke(R T::*f, Arg&& arg, Args&&... args) |
| C10_MPARK_RETURN( |
| Invoke< |
| std::is_function<R>::value, |
| (std::is_base_of<T, lib::decay_t<Arg>>::value ? 0 |
| : is_reference_wrapper<lib::decay_t<Arg>>::value ? 1 |
| : 2)>:: |
| invoke(f, lib::forward<Arg>(arg), lib::forward<Args>(args)...)) |
| |
| #ifdef _MSC_VER |
| #pragma warning(push) |
| #pragma warning(disable : 4100) |
| #endif |
| template <typename F, typename... Args> |
| inline constexpr auto invoke(F&& f, Args&&... args) |
| C10_MPARK_RETURN(lib::forward<F>(f)(lib::forward<Args>(args)...)) |
| #ifdef _MSC_VER |
| #pragma warning(pop) |
| #endif |
| } // namespace detail_ |
| |
| template <typename F, typename... Args> |
| inline constexpr auto invoke(F&& f, Args&&... args) C10_MPARK_RETURN( |
| detail_::invoke(lib::forward<F>(f), lib::forward<Args>(args)...)) |
| |
| namespace detail_ { |
| template <typename Void, typename, typename...> |
| struct invoke_result {}; |
| |
| template <typename F, typename... Args> |
| struct invoke_result< |
| void_t<decltype(lib::invoke(std::declval<F>(), std::declval<Args>()...))>, |
| F, |
| Args...> |
| : identity<decltype(lib::invoke( |
| std::declval<F>(), std::declval<Args>()...))> {}; |
| |
| } // namespace detail_ |
| |
| template <typename F, typename... Args> |
| using invoke_result = detail_::invoke_result<void, F, Args...>; |
| |
| template <typename F, typename... Args> |
| using invoke_result_t = typename invoke_result<F, Args...>::type; |
| |
| namespace detail_ { |
| |
| template <typename Void, typename, typename...> |
| struct is_invocable : std::false_type {}; |
| |
| template <typename F, typename... Args> |
| struct is_invocable<void_t<invoke_result_t<F, Args...>>, F, Args...> |
| : std::true_type {}; |
| |
| template <typename Void, typename, typename, typename...> |
| struct is_invocable_r : std::false_type {}; |
| |
| template <typename R, typename F, typename... Args> |
| struct is_invocable_r<void_t<invoke_result_t<F, Args...>>, R, F, Args...> |
| : std::is_convertible<invoke_result_t<F, Args...>, R> {}; |
| |
| } // namespace detail_ |
| |
| template <typename F, typename... Args> |
| using is_invocable = detail_::is_invocable<void, F, Args...>; |
| |
| template <typename R, typename F, typename... Args> |
| using is_invocable_r = detail_::is_invocable_r<void, R, F, Args...>; |
| |
| namespace detail_ { |
| |
| template <bool Invocable, typename F, typename... Args> |
| struct is_nothrow_invocable { |
| static constexpr bool value = |
| noexcept(lib::invoke(std::declval<F>(), std::declval<Args>()...)); |
| }; |
| |
| template <typename F, typename... Args> |
| struct is_nothrow_invocable<false, F, Args...> : std::false_type {}; |
| |
| template <bool Invocable, typename R, typename F, typename... Args> |
| struct is_nothrow_invocable_r { |
| private: |
| inline static R impl() { |
| return lib::invoke(std::declval<F>(), std::declval<Args>()...); |
| } |
| |
| public: |
| static constexpr bool value = noexcept(impl()); |
| }; |
| |
| template <typename R, typename F, typename... Args> |
| struct is_nothrow_invocable_r<false, R, F, Args...> : std::false_type {}; |
| |
| } // namespace detail_ |
| |
| template <typename F, typename... Args> |
| using is_nothrow_invocable = |
| detail_::is_nothrow_invocable<is_invocable<F, Args...>::value, F, Args...>; |
| |
| template <typename R, typename F, typename... Args> |
| using is_nothrow_invocable_r = detail_:: |
| is_nothrow_invocable_r<is_invocable_r<R, F, Args...>::value, R, F, Args...>; |
| |
| // <memory> |
| #ifdef C10_MPARK_BUILTIN_ADDRESSOF |
| template <typename T> |
| inline constexpr T* addressof(T& arg) noexcept { |
| return __builtin_addressof(arg); |
| } |
| #else |
| namespace detail_ { |
| |
| namespace has_addressof_impl { |
| |
| struct fail; |
| |
| template <typename T> |
| inline fail operator&(T&&); |
| |
| template <typename T> |
| inline static constexpr bool impl() { |
| return (std::is_class<T>::value || std::is_union<T>::value) && |
| !std::is_same<decltype(&std::declval<T&>()), fail>::value; |
| } |
| |
| } // namespace has_addressof_impl |
| |
| template <typename T> |
| using has_addressof = bool_constant<has_addressof_impl::impl<T>()>; |
| |
| template <typename T> |
| inline constexpr T* addressof(T& arg, std::true_type) noexcept { |
| return std::addressof(arg); |
| } |
| |
| template <typename T> |
| inline constexpr T* addressof(T& arg, std::false_type) noexcept { |
| return &arg; |
| } |
| |
| } // namespace detail_ |
| |
| template <typename T> |
| inline constexpr T* addressof(T& arg) noexcept { |
| return detail_::addressof(arg, detail_::has_addressof<T>{}); |
| } |
| #endif |
| |
| template <typename T> |
| inline constexpr T* addressof(const T&&) = delete; |
| |
| } // namespace cpp17 |
| |
| template <typename T> |
| struct remove_all_extents : identity<T> {}; |
| |
| template <typename T, std::size_t N> |
| struct remove_all_extents<array<T, N>> : remove_all_extents<T> {}; |
| |
| template <typename T> |
| using remove_all_extents_t = typename remove_all_extents<T>::type; |
| |
| template <std::size_t N> |
| using size_constant = std::integral_constant<std::size_t, N>; |
| |
| template <std::size_t I, typename T> |
| struct indexed_type : size_constant<I> { |
| using type = T; |
| }; |
| |
| template <bool... Bs> |
| using all = std::is_same< |
| integer_sequence<bool, true, Bs...>, |
| integer_sequence<bool, Bs..., true>>; |
| |
| #ifdef C10_MPARK_TYPE_PACK_ELEMENT |
| template <std::size_t I, typename... Ts> |
| using type_pack_element_t = __type_pack_element<I, Ts...>; |
| #else |
| template <std::size_t I, typename... Ts> |
| struct type_pack_element_impl { |
| private: |
| template <typename> |
| struct set; |
| |
| template <std::size_t... Is> |
| struct set<index_sequence<Is...>> : indexed_type<Is, Ts>... {}; |
| |
| template <typename T> |
| inline static std::enable_if<true, T> impl(indexed_type<I, T>); |
| |
| inline static std::enable_if<false> impl(...); |
| |
| public: |
| using type = decltype(impl(set<index_sequence_for<Ts...>>{})); |
| }; |
| |
| template <std::size_t I, typename... Ts> |
| using type_pack_element = typename type_pack_element_impl<I, Ts...>::type; |
| |
| template <std::size_t I, typename... Ts> |
| using type_pack_element_t = typename type_pack_element<I, Ts...>::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 <typename T> |
| struct is_trivially_copy_constructible |
| : bool_constant<std::is_copy_constructible<T>::value&& __has_trivial_copy( |
| T)> {}; |
| |
| template <typename T> |
| struct is_trivially_move_constructible : bool_constant<__is_trivial(T)> {}; |
| |
| template <typename T> |
| struct is_trivially_copy_assignable |
| : bool_constant<std::is_copy_assignable<T>::value&& __has_trivial_assign( |
| T)> {}; |
| |
| template <typename T> |
| struct is_trivially_move_assignable : bool_constant<__is_trivial(T)> {}; |
| #endif |
| |
| template <typename T, bool> |
| struct dependent_type : T {}; |
| |
| template <typename Is, std::size_t J> |
| struct push_back; |
| |
| template <typename Is, std::size_t J> |
| using push_back_t = typename push_back<Is, J>::type; |
| |
| template <std::size_t... Is, std::size_t J> |
| struct push_back<index_sequence<Is...>, J> { |
| using type = index_sequence<Is..., J>; |
| }; |
| |
| } // 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<decltype(__VA_ARGS__)> { \ |
| return __VA_ARGS__; \ |
| } |
| |
| #define AUTO_REFREF auto |
| #define AUTO_REFREF_RETURN(...) \ |
| ->decltype((__VA_ARGS__)) { \ |
| static_assert(std::is_reference<decltype((__VA_ARGS__))>::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 <typename... Ts> |
| class variant; |
| |
| template <typename T> |
| struct variant_size; |
| |
| #ifdef C10_MPARK_VARIABLE_TEMPLATES |
| template <typename T> |
| constexpr std::size_t variant_size_v = variant_size<T>::value; |
| #endif |
| |
| template <typename T> |
| struct variant_size<const T> : variant_size<T> {}; |
| |
| template <typename T> |
| struct variant_size<volatile T> : variant_size<T> {}; |
| |
| template <typename T> |
| struct variant_size<const volatile T> : variant_size<T> {}; |
| |
| template <typename... Ts> |
| struct variant_size<variant<Ts...>> : lib::size_constant<sizeof...(Ts)> {}; |
| |
| template <std::size_t I, typename T> |
| struct variant_alternative; |
| |
| template <std::size_t I, typename T> |
| using variant_alternative_t = typename variant_alternative<I, T>::type; |
| |
| template <std::size_t I, typename T> |
| struct variant_alternative<I, const T> |
| : std::add_const<variant_alternative_t<I, T>> {}; |
| |
| template <std::size_t I, typename T> |
| struct variant_alternative<I, volatile T> |
| : std::add_volatile<variant_alternative_t<I, T>> {}; |
| |
| template <std::size_t I, typename T> |
| struct variant_alternative<I, const volatile T> |
| : std::add_cv<variant_alternative_t<I, T>> {}; |
| |
| template <std::size_t I, typename... Ts> |
| struct variant_alternative<I, variant<Ts...>> { |
| static_assert( |
| I < sizeof...(Ts), |
| "index out of bounds in `std::variant_alternative<>`"); |
| using type = lib::type_pack_element_t<I, Ts...>; |
| }; |
| |
| constexpr std::size_t variant_npos = static_cast<std::size_t>(-1); |
| |
| namespace detail_ { |
| |
| constexpr std::size_t not_found = static_cast<std::size_t>(-1); |
| constexpr std::size_t ambiguous = static_cast<std::size_t>(-2); |
| |
| #ifdef C10_MPARK_CPP14_CONSTEXPR |
| template <typename T, typename... Ts> |
| inline constexpr std::size_t find_index() { |
| constexpr lib::array<bool, sizeof...(Ts)> matches = { |
| {std::is_same<T, Ts>::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 <typename... Bs> |
| 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 <typename T, typename... Ts> |
| inline constexpr std::size_t find_index() { |
| return find_index_impl(not_found, 0, std::is_same<T, Ts>::value...); |
| } |
| #endif |
| |
| template <std::size_t I> |
| using find_index_sfinae_impl = |
| lib::enable_if_t<I != not_found && I != ambiguous, lib::size_constant<I>>; |
| |
| template <typename T, typename... Ts> |
| using find_index_sfinae = find_index_sfinae_impl<find_index<T, Ts...>()>; |
| |
| template <std::size_t I> |
| struct find_index_checked_impl : lib::size_constant<I> { |
| static_assert(I != not_found, "the specified type is not found."); |
| static_assert(I != ambiguous, "the specified type is ambiguous."); |
| }; |
| |
| template <typename T, typename... Ts> |
| using find_index_checked = find_index_checked_impl<find_index<T, Ts...>()>; |
| |
| struct valueless_t {}; |
| |
| enum class Trait { TriviallyAvailable, Available, Unavailable }; |
| |
| template < |
| typename T, |
| template <typename> |
| class IsTriviallyAvailable, |
| template <typename> |
| class IsAvailable> |
| inline constexpr Trait trait() { |
| return IsTriviallyAvailable<T>::value ? Trait::TriviallyAvailable |
| : IsAvailable<T>::value ? Trait::Available |
| : Trait::Unavailable; |
| } |
| |
| #ifdef C10_MPARK_CPP14_CONSTEXPR |
| template <typename... Traits> |
| inline constexpr Trait common_trait(Traits... traits_) { |
| Trait result = Trait::TriviallyAvailable; |
| lib::array<Trait, sizeof...(Traits)> traits = {{traits_...}}; |
| for (std::size_t i = 0; i < sizeof...(Traits); ++i) { |
| Trait t = traits[i]; |
| if (static_cast<int>(t) > static_cast<int>(result)) { |
| result = t; |
| } |
| } |
| return result; |
| } |
| #else |
| inline constexpr Trait common_trait_impl(Trait result) { |
| return result; |
| } |
| |
| template <typename... Traits> |
| inline constexpr Trait common_trait_impl(Trait result, Trait t, Traits... ts) { |
| return static_cast<int>(t) > static_cast<int>(result) |
| ? common_trait_impl(t, ts...) |
| : common_trait_impl(result, ts...); |
| } |
| |
| template <typename... Traits> |
| inline constexpr Trait common_trait(Traits... ts) { |
| return common_trait_impl(Trait::TriviallyAvailable, ts...); |
| } |
| #endif |
| |
| template <typename... Ts> |
| 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<Ts, std::is_trivially_destructible, std::is_destructible>()...); |
| }; |
| |
| namespace access { |
| |
| struct recursive_union { |
| #ifdef C10_MPARK_RETURN_TYPE_DEDUCTION |
| template <typename V> |
| inline static constexpr auto&& get_alt(V&& v, in_place_index_t<0>) { |
| return lib::forward<V>(v).head_; |
| } |
| |
| template <typename V, std::size_t I> |
| inline static constexpr auto&& get_alt(V&& v, in_place_index_t<I>) { |
| return get_alt(lib::forward<V>(v).tail_, in_place_index_t<I - 1>{}); |
| } |
| #else |
| template <std::size_t I, bool Dummy = true> |
| struct get_alt_impl { |
| template <typename V> |
| inline constexpr AUTO_REFREF operator()(V&& v) const |
| AUTO_REFREF_RETURN(get_alt_impl<I - 1>{}(lib::forward<V>(v).tail_)) |
| }; |
| |
| template <bool Dummy> |
| struct get_alt_impl<0, Dummy> { |
| template <typename V> |
| inline constexpr AUTO_REFREF operator()(V&& v) const |
| AUTO_REFREF_RETURN(lib::forward<V>(v).head_) |
| }; |
| |
| template <typename V, std::size_t I> |
| inline static constexpr AUTO_REFREF get_alt(V&& v, in_place_index_t<I>) |
| AUTO_REFREF_RETURN(get_alt_impl<I>{}(lib::forward<V>(v))) |
| #endif |
| }; |
| |
| struct base { |
| template <std::size_t I, typename V> |
| inline static constexpr AUTO_REFREF get_alt(V&& v) |
| #ifdef _MSC_VER |
| AUTO_REFREF_RETURN(recursive_union::get_alt( |
| lib::forward<V>(v).data_, |
| in_place_index_t<I>{})) |
| #else |
| AUTO_REFREF_RETURN(recursive_union::get_alt( |
| data(lib::forward<V>(v)), |
| in_place_index_t<I>{})) |
| #endif |
| }; |
| |
| struct variant { |
| template <std::size_t I, typename V> |
| inline static constexpr AUTO_REFREF get_alt(V&& v) |
| AUTO_REFREF_RETURN(base::get_alt<I>(lib::forward<V>(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 <typename Visitor, typename... Vs> |
| using dispatch_result_t = decltype(lib::invoke( |
| std::declval<Visitor>(), |
| access::base::get_alt<0>(std::declval<Vs>())...)); |
| |
| template <typename Expected> |
| struct expected { |
| template <typename Actual> |
| inline static constexpr bool but_got() { |
| return std::is_same<Expected, Actual>::value; |
| } |
| }; |
| |
| template <typename Expected, typename Actual> |
| struct visit_return_type_check { |
| static_assert( |
| expected<Expected>::template but_got<Actual>(), |
| "`visit` requires the visitor to have a single return type"); |
| |
| template <typename Visitor, typename... Alts> |
| inline static constexpr DECLTYPE_AUTO invoke( |
| Visitor&& visitor, |
| Alts&&... alts) |
| DECLTYPE_AUTO_RETURN(lib::invoke( |
| lib::forward<Visitor>(visitor), |
| lib::forward<Alts>(alts)...)) |
| }; |
| |
| #ifdef C10_MPARK_VARIANT_SWITCH_VISIT |
| template <bool B, typename R, typename... ITs> |
| struct dispatcher; |
| |
| template <typename R, typename... ITs> |
| struct dispatcher<false, R, ITs...> { |
| template <std::size_t B, typename F, typename... Vs> |
| C10_MPARK_ALWAYS_INLINE static constexpr R dispatch( |
| F&&, |
| typename ITs::type&&..., |
| Vs&&...) { |
| C10_MPARK_BUILTIN_UNREACHABLE; |
| } |
| |
| template <std::size_t I, typename F, typename... Vs> |
| C10_MPARK_ALWAYS_INLINE static constexpr R dispatch_case(F&&, Vs&&...) { |
| C10_MPARK_BUILTIN_UNREACHABLE; |
| } |
| |
| template <std::size_t B, typename F, typename... Vs> |
| C10_MPARK_ALWAYS_INLINE static constexpr R dispatch_at( |
| std::size_t, |
| F&&, |
| Vs&&...) { |
| C10_MPARK_BUILTIN_UNREACHABLE; |
| } |
| }; |
| |
| template <typename R, typename... ITs> |
| struct dispatcher<true, R, ITs...> { |
| template <std::size_t B, typename F> |
| 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>(f), |
| access::base::get_alt<ITs::value>( |
| lib::forward<typename ITs::type>(visited_vs))...)); |
| return visit_return_type_check<Expected, Actual>::invoke( |
| lib::forward<F>(f), |
| access::base::get_alt<ITs::value>( |
| lib::forward<typename ITs::type>(visited_vs))...); |
| } |
| |
| template <std::size_t B, typename F, typename V, typename... Vs> |
| 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<V>::size()), \ |
| R, \ |
| ITs..., \ |
| lib::indexed_type<I, V>>:: \ |
| template dispatch<0>( \ |
| lib::forward<F>(f), \ |
| lib::forward<typename ITs::type>(visited_vs)..., \ |
| lib::forward<V>(v), \ |
| lib::forward<Vs>(vs)...) |
| |
| #define C10_MPARK_DEFAULT(I) \ |
| dispatcher<(I < lib::decay_t<V>::size()), R, ITs...>::template dispatch<I>( \ |
| lib::forward<F>(f), \ |
| lib::forward<typename ITs::type>(visited_vs)..., \ |
| lib::forward<V>(v), \ |
| lib::forward<Vs>(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 <std::size_t I, typename F, typename... Vs> |
| C10_MPARK_ALWAYS_INLINE static constexpr R dispatch_case( |
| F&& f, |
| Vs&&... vs) { |
| using Expected = R; |
| using Actual = decltype(lib::invoke( |
| lib::forward<F>(f), |
| access::base::get_alt<I>(lib::forward<Vs>(vs))...)); |
| return visit_return_type_check<Expected, Actual>::invoke( |
| lib::forward<F>(f), |
| access::base::get_alt<I>(lib::forward<Vs>(vs))...); |
| } |
| |
| template <std::size_t B, typename F, typename V, typename... Vs> |
| 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<V>::size() == lib::decay_t<Vs>::size())...>::value, |
| "all of the variants must be the same size."); |
| #define C10_MPARK_DISPATCH_AT(I) \ |
| dispatcher<(I < lib::decay_t<V>::size()), R>::template dispatch_case<I>( \ |
| lib::forward<F>(f), lib::forward<V>(v), lib::forward<Vs>(vs)...) |
| |
| #define C10_MPARK_DEFAULT(I) \ |
| dispatcher<(I < lib::decay_t<V>::size()), R>::template dispatch_at<I>( \ |
| index, lib::forward<F>(f), lib::forward<V>(v), lib::forward<Vs>(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 <typename T> |
| inline static constexpr const T& at(const T& elem) noexcept { |
| return elem; |
| } |
| |
| template <typename T, std::size_t N, typename... Is> |
| inline static constexpr const lib::remove_all_extents_t<T>& at( |
| const lib::array<T, N>& elems, |
| std::size_t i, |
| Is... is) noexcept { |
| return at(elems[i], is...); |
| } |
| |
| template <typename F, typename... Fs> |
| inline static constexpr lib::array<lib::decay_t<F>, sizeof...(Fs) + 1> |
| make_farray(F&& f, Fs&&... fs) { |
| return {{lib::forward<F>(f), lib::forward<Fs>(fs)...}}; |
| } |
| |
| template <typename F, typename... Vs> |
| struct make_fmatrix_impl { |
| template <std::size_t... Is> |
| inline static constexpr dispatch_result_t<F, Vs...> dispatch( |
| F&& f, |
| Vs&&... vs) { |
| using Expected = dispatch_result_t<F, Vs...>; |
| using Actual = decltype(lib::invoke( |
| lib::forward<F>(f), |
| access::base::get_alt<Is>(lib::forward<Vs>(vs))...)); |
| return visit_return_type_check<Expected, Actual>::invoke( |
| lib::forward<F>(f), |
| access::base::get_alt<Is>(lib::forward<Vs>(vs))...); |
| } |
| |
| #ifdef C10_MPARK_RETURN_TYPE_DEDUCTION |
| template <std::size_t... Is> |
| inline static constexpr auto impl(lib::index_sequence<Is...>) { |
| return &dispatch<Is...>; |
| } |
| |
| template <typename Is, std::size_t... Js, typename... Ls> |
| inline static constexpr auto impl( |
| Is, |
| lib::index_sequence<Js...>, |
| Ls... ls) { |
| return make_farray(impl(lib::push_back_t<Is, Js>{}, ls...)...); |
| } |
| #else |
| template <typename...> |
| struct impl; |
| |
| template <std::size_t... Is> |
| struct impl<lib::index_sequence<Is...>> { |
| inline constexpr AUTO operator()() const AUTO_RETURN(&dispatch<Is...>) |
| }; |
| |
| template <typename Is, std::size_t... Js, typename... Ls> |
| struct impl<Is, lib::index_sequence<Js...>, Ls...> { |
| inline constexpr AUTO operator()() const |
| AUTO_RETURN(make_farray(impl<lib::push_back_t<Is, Js>, Ls...>{}()...)) |
| }; |
| #endif |
| }; |
| |
| #ifdef C10_MPARK_RETURN_TYPE_DEDUCTION |
| template <typename F, typename... Vs> |
| inline static constexpr auto make_fmatrix() { |
| return make_fmatrix_impl<F, Vs...>::impl( |
| lib::index_sequence<>{}, |
| lib::make_index_sequence<lib::decay_t<Vs>::size()>{}...); |
| } |
| #else |
| template <typename F, typename... Vs> |
| inline static constexpr AUTO make_fmatrix() |
| AUTO_RETURN(typename make_fmatrix_impl<F, Vs...>::template impl< |
| lib::index_sequence<>, |
| lib::make_index_sequence<lib::decay_t<Vs>::size()>...>{}()) |
| #endif |
| |
| template <typename F, typename... Vs> |
| struct make_fdiagonal_impl { |
| template <std::size_t I> |
| inline static constexpr dispatch_result_t<F, Vs...> dispatch( |
| F&& f, |
| Vs&&... vs) { |
| using Expected = dispatch_result_t<F, Vs...>; |
| using Actual = decltype(lib::invoke( |
| lib::forward<F>(f), |
| access::base::get_alt<I>(lib::forward<Vs>(vs))...)); |
| return visit_return_type_check<Expected, Actual>::invoke( |
| lib::forward<F>(f), |
| access::base::get_alt<I>(lib::forward<Vs>(vs))...); |
| } |
| |
| template <std::size_t... Is> |
| inline static constexpr AUTO impl(lib::index_sequence<Is...>) |
| AUTO_RETURN(make_farray(&dispatch<Is>...)) |
| }; |
| |
| template <typename F, typename V, typename... Vs> |
| inline static constexpr auto make_fdiagonal() |
| -> decltype(make_fdiagonal_impl<F, V, Vs...>::impl( |
| lib::make_index_sequence<lib::decay_t<V>::size()>{})) { |
| static_assert( |
| lib::all<( |
| lib::decay_t<V>::size() == lib::decay_t<Vs>::size())...>::value, |
| "all of the variants must be the same size."); |
| return make_fdiagonal_impl<F, V, Vs...>::impl( |
| lib::make_index_sequence<lib::decay_t<V>::size()>{}); |
| } |
| #endif |
| }; |
| |
| #if !defined(C10_MPARK_VARIANT_SWITCH_VISIT) && \ |
| (!defined(_MSC_VER) || _MSC_VER >= 1910) |
| template <typename F, typename... Vs> |
| using fmatrix_t = decltype(base::make_fmatrix<F, Vs...>()); |
| |
| template <typename F, typename... Vs> |
| struct fmatrix { |
| static constexpr fmatrix_t<F, Vs...> value = base::make_fmatrix<F, Vs...>(); |
| }; |
| |
| template <typename F, typename... Vs> |
| constexpr fmatrix_t<F, Vs...> fmatrix<F, Vs...>::value; |
| |
| template <typename F, typename... Vs> |
| using fdiagonal_t = decltype(base::make_fdiagonal<F, Vs...>()); |
| |
| template <typename F, typename... Vs> |
| struct fdiagonal { |
| static constexpr fdiagonal_t<F, Vs...> value = |
| base::make_fdiagonal<F, Vs...>(); |
| }; |
| |
| template <typename F, typename... Vs> |
| constexpr fdiagonal_t<F, Vs...> fdiagonal<F, Vs...>::value; |
| #endif |
| |
| struct alt { |
| template <typename Visitor, typename... Vs> |
| 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>(vs)))...>>:: |
| template dispatch<0>( |
| lib::forward<Visitor>(visitor), |
| as_base(lib::forward<Vs>(vs))...)) |
| #elif !defined(_MSC_VER) || _MSC_VER >= 1910 |
| DECLTYPE_AUTO_RETURN(base::at( |
| fmatrix<Visitor&&, decltype(as_base(lib::forward<Vs>(vs)))...>::value, |
| vs.index()...)( |
| lib::forward<Visitor>(visitor), |
| as_base(lib::forward<Vs>(vs))...)) |
| #else |
| DECLTYPE_AUTO_RETURN(base::at( |
| base::make_fmatrix< |
| Visitor&&, |
| decltype(as_base(lib::forward<Vs>(vs)))...>(), |
| vs.index()...)( |
| lib::forward<Visitor>(visitor), |
| as_base(lib::forward<Vs>(vs))...)) |
| #endif |
| |
| template <typename Visitor, typename... Vs> |
| 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>(vs)))...>>:: |
| template dispatch_at<0>( |
| index, |
| lib::forward<Visitor>(visitor), |
| as_base(lib::forward<Vs>(vs))...)) |
| #elif !defined(_MSC_VER) || _MSC_VER >= 1910 |
| DECLTYPE_AUTO_RETURN(base::at( |
| fdiagonal<Visitor&&, decltype(as_base(lib::forward<Vs>(vs)))...>:: |
| value, |
| index)( |
| lib::forward<Visitor>(visitor), |
| as_base(lib::forward<Vs>(vs))...)) |
| #else |
| DECLTYPE_AUTO_RETURN(base::at( |
| base::make_fdiagonal< |
| Visitor&&, |
| decltype(as_base(lib::forward<Vs>(vs)))...>(), |
| index)( |
| lib::forward<Visitor>(visitor), |
| as_base(lib::forward<Vs>(vs))...)) |
| #endif |
| }; |
| |
| struct variant { |
| private: |
| template <typename Visitor> |
| struct visitor { |
| template <typename... Values> |
| inline static constexpr bool does_not_handle() { |
| return lib::is_invocable<Visitor, Values...>::value; |
| } |
| }; |
| |
| template <typename Visitor, typename... Values> |
| struct visit_exhaustiveness_check { |
| static_assert( |
| visitor<Visitor>::template does_not_handle<Values...>(), |
| "`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>(visitor), |
| lib::forward<Values>(values)...)) |
| }; |
| |
| template <typename Visitor> |
| struct C10_MPARK_VISIBILITY_HIDDEN value_visitor { |
| Visitor&& visitor_; |
| |
| template <typename... Alts> |
| inline constexpr DECLTYPE_AUTO operator()(Alts&&... alts) const |
| DECLTYPE_AUTO_RETURN(visit_exhaustiveness_check< |
| Visitor, |
| decltype((lib::forward<Alts>(alts).value))...>:: |
| invoke( |
| lib::forward<Visitor>(visitor_), |
| lib::forward<Alts>(alts).value...)) |
| }; |
| |
| template <typename Visitor> |
| inline static constexpr AUTO make_value_visitor(Visitor&& visitor) |
| AUTO_RETURN(value_visitor<Visitor>{lib::forward<Visitor>(visitor)}) |
| |
| public |
| : template <typename Visitor, typename... Vs> |
| inline static constexpr DECLTYPE_AUTO |
| visit_alt(Visitor&& visitor, Vs&&... vs) |
| DECLTYPE_AUTO_RETURN(alt::visit_alt( |
| lib::forward<Visitor>(visitor), |
| lib::forward<Vs>(vs).impl_...)) |
| |
| template <typename Visitor, typename... Vs> |
| 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>(visitor), |
| lib::forward<Vs>(vs).impl_...)) |
| |
| template <typename Visitor, typename... Vs> |
| inline static constexpr DECLTYPE_AUTO |
| visit_value(Visitor&& visitor, Vs&&... vs) |
| DECLTYPE_AUTO_RETURN(visit_alt( |
| make_value_visitor(lib::forward<Visitor>(visitor)), |
| lib::forward<Vs>(vs)...)) |
| |
| template <typename Visitor, typename... Vs> |
| 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>(visitor)), |
| lib::forward<Vs>(vs)...)) |
| }; |
| |
| } // namespace visitation |
| |
| template <std::size_t Index, typename T> |
| struct alt { |
| using value_type = T; |
| |
| #ifdef _MSC_VER |
| #pragma warning(push) |
| #pragma warning(disable : 4244) |
| #endif |
| template <typename... Args> |
| inline explicit constexpr alt(in_place_t, Args&&... args) |
| : value(lib::forward<Args>(args)...) {} |
| #ifdef _MSC_VER |
| #pragma warning(pop) |
| #endif |
| |
| T value; |
| }; |
| |
| template <Trait DestructibleTrait, std::size_t Index, typename... Ts> |
| union recursive_union; |
| |
| template <Trait DestructibleTrait, std::size_t Index> |
| union recursive_union<DestructibleTrait, Index> {}; |
| |
| #define C10_MPARK_VARIANT_RECURSIVE_UNION(destructible_trait, destructor) \ |
| template <std::size_t Index, typename T, typename... Ts> \ |
| union recursive_union<destructible_trait, Index, T, Ts...> { \ |
| public: \ |
| inline explicit constexpr recursive_union(valueless_t) noexcept \ |
| : dummy_{} {} \ |
| \ |
| template <typename... Args> \ |
| inline explicit constexpr recursive_union( \ |
| in_place_index_t<0>, \ |
| Args&&... args) \ |
| : head_(in_place_t{}, lib::forward<Args>(args)...) {} \ |
| \ |
| template <std::size_t I, typename... Args> \ |
| inline explicit constexpr recursive_union( \ |
| in_place_index_t<I>, \ |
| Args&&... args) \ |
| : tail_(in_place_index_t<I - 1>{}, lib::forward<Args>(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<Index, T> head_; \ |
| recursive_union<destructible_trait, Index + 1, Ts...> 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 <Trait DestructibleTrait, typename... Ts> |
| class base { |
| public: |
| inline explicit constexpr base(valueless_t tag) noexcept |
| : data_(tag), index_(static_cast<index_t>(-1)) {} |
| |
| template <std::size_t I, typename... Args> |
| inline explicit constexpr base(in_place_index_t<I>, Args&&... args) |
| : data_(in_place_index_t<I>{}, lib::forward<Args>(args)...), index_(I) {} |
| |
| inline constexpr bool valueless_by_exception() const noexcept { |
| return index_ == static_cast<index_t>(-1); |
| } |
| |
| inline constexpr std::size_t index() const noexcept { |
| return valueless_by_exception() ? variant_npos : index_; |
| } |
| |
| protected: |
| using data_t = recursive_union<DestructibleTrait, 0, Ts...>; |
| |
| 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 <typename Alt> |
| 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 <typename... Args> \ |
| inline explicit constexpr type(Args&&... args) \ |
| : base(lib::forward<Args>(args)...) {} |
| #endif |
| |
| template <typename Traits, Trait = Traits::destructible_trait> |
| class destructor; |
| |
| #define C10_MPARK_VARIANT_DESTRUCTOR(destructible_trait, definition, destroy) \ |
| template <typename... Ts> \ |
| class destructor<traits<Ts...>, destructible_trait> \ |
| : public base<destructible_trait, Ts...> { \ |
| using super = base<destructible_trait, Ts...>; \ |
| \ |
| 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<index_t>(-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<index_t>(-1); |
| }); |
| |
| C10_MPARK_VARIANT_DESTRUCTOR(Trait::Unavailable, ~destructor() = delete; |
| , inline void destroy() noexcept = delete;); |
| |
| #undef C10_MPARK_VARIANT_DESTRUCTOR |
| |
| template <typename Traits> |
| class constructor : public destructor<Traits> { |
| using super = destructor<Traits>; |
| |
| public: |
| C10_MPARK_INHERITING_CTOR(constructor, super) |
| using super::operator=; |
| |
| protected: |
| #ifndef C10_MPARK_GENERIC_LAMBDAS |
| struct ctor { |
| template <typename LhsAlt, typename RhsAlt> |
| inline void operator()(LhsAlt& lhs_alt, RhsAlt&& rhs_alt) const { |
| constructor::construct_alt(lhs_alt, lib::forward<RhsAlt>(rhs_alt).value); |
| } |
| }; |
| #endif |
| |
| template <std::size_t I, typename T, typename... Args> |
| inline static T& construct_alt(alt<I, T>& a, Args&&... args) { |
| auto* result = ::new (static_cast<void*>(lib::addressof(a))) |
| alt<I, T>(in_place_t{}, lib::forward<Args>(args)...); |
| return result->value; |
| } |
| |
| template <typename Rhs> |
| 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<decltype(rhs_alt)>(rhs_alt).value); |
| } |
| #else |
| ctor {} |
| #endif |
| , |
| lhs, |
| lib::forward<Rhs>(rhs)); |
| lhs.index_ = rhs.index_; |
| } |
| } |
| }; |
| |
| template <typename Traits, Trait = Traits::move_constructible_trait> |
| class move_constructor; |
| |
| #define C10_MPARK_VARIANT_MOVE_CONSTRUCTOR( \ |
| move_constructible_trait, definition) \ |
| template <typename... Ts> \ |
| class move_constructor<traits<Ts...>, move_constructible_trait> \ |
| : public constructor<traits<Ts...>> { \ |
| using super = constructor<traits<Ts...>>; \ |
| \ |
| 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<std::is_nothrow_move_constructible<Ts>::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 <typename Traits, Trait = Traits::copy_constructible_trait> |
| class copy_constructor; |
| |
| #define C10_MPARK_VARIANT_COPY_CONSTRUCTOR( \ |
| copy_constructible_trait, definition) \ |
| template <typename... Ts> \ |
| class copy_constructor<traits<Ts...>, copy_constructible_trait> \ |
| : public move_constructor<traits<Ts...>> { \ |
| using super = move_constructor<traits<Ts...>>; \ |
| \ |
| 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 <typename Traits> |
| class assignment : public copy_constructor<Traits> { |
| using super = copy_constructor<Traits>; |
| |
| public: |
| C10_MPARK_INHERITING_CTOR(assignment, super) |
| using super::operator=; |
| |
| template <std::size_t I, typename... Args> |
| inline /* auto & */ auto emplace(Args&&... args) |
| -> decltype(this->construct_alt( |
| access::base::get_alt<I>(*this), |
| lib::forward<Args>(args)...)) { |
| this->destroy(); |
| auto& result = this->construct_alt( |
| access::base::get_alt<I>(*this), lib::forward<Args>(args)...); |
| this->index_ = I; |
| return result; |
| } |
| |
| protected: |
| #ifndef C10_MPARK_GENERIC_LAMBDAS |
| template <typename That> |
| struct assigner { |
| template <typename ThisAlt, typename ThatAlt> |
| inline void operator()(ThisAlt& this_alt, ThatAlt&& that_alt) const { |
| self->assign_alt(this_alt, lib::forward<ThatAlt>(that_alt).value); |
| } |
| assignment* self; |
| }; |
| #endif |
| |
| template <std::size_t I, typename T, typename Arg> |
| inline void assign_alt(alt<I, T>& a, Arg&& arg) { |
| if (this->index() == I) { |
| #ifdef _MSC_VER |
| #pragma warning(push) |
| #pragma warning(disable : 4244) |
| #endif |
| a.value = lib::forward<Arg>(arg); |
| #ifdef _MSC_VER |
| #pragma warning(pop) |
| #endif |
| } else { |
| struct { |
| void operator()(std::true_type) const { |
| this_->emplace<I>(lib::forward<Arg>(arg_)); |
| } |
| void operator()(std::false_type) const { |
| this_->emplace<I>(T(lib::forward<Arg>(arg_))); |
| } |
| assignment* this_; |
| Arg&& arg_; |
| } impl{this, lib::forward<Arg>(arg)}; |
| impl( |
| lib::bool_constant < std::is_nothrow_constructible<T, Arg>::value || |
| !std::is_nothrow_move_constructible<T>::value > {}); |
| } |
| } |
| |
| template <typename That> |
| 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<decltype(that_alt)>(that_alt).value); |
| } |
| #else |
| assigner<That> { this } |
| #endif |
| , |
| *this, |
| lib::forward<That>(that)); |
| } |
| } |
| }; |
| |
| template <typename Traits, Trait = Traits::move_assignable_trait> |
| class move_assignment; |
| |
| #define C10_MPARK_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, definition) \ |
| template <typename... Ts> \ |
| class move_assignment<traits<Ts...>, move_assignable_trait> \ |
| : public assignment<traits<Ts...>> { \ |
| using super = assignment<traits<Ts...>>; \ |
| \ |
| 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<Ts>::value && |
| std::is_nothrow_move_assignable<Ts>::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 <typename Traits, Trait = Traits::copy_assignable_trait> |
| class copy_assignment; |
| |
| #define C10_MPARK_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, definition) \ |
| template <typename... Ts> \ |
| class copy_assignment<traits<Ts...>, copy_assignable_trait> \ |
| : public move_assignment<traits<Ts...>> { \ |
| using super = move_assignment<traits<Ts...>>; \ |
| \ |
| 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 <typename... Ts> |
| class impl : public copy_assignment<traits<Ts...>> { |
| using super = copy_assignment<traits<Ts...>>; |
| |
| public: |
| C10_MPARK_INHERITING_CTOR(impl, super) |
| |
| template <std::size_t I, typename Arg> |
| inline void assign(Arg&& arg) { |
| this->assign_alt(access::base::get_alt<I>(*this), lib::forward<Arg>(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 <typename ThisAlt, typename ThatAlt> |
| 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<bool, sizeof...(Ts)>{ |
| {std::is_nothrow_move_constructible<Ts>::value...}}[this->index()]; |
| } |
| }; |
| |
| #undef C10_MPARK_INHERITING_CTOR |
| |
| template <std::size_t I, typename T> |
| struct overload_leaf { |
| using F = lib::size_constant<I> (*)(T); |
| operator F() const { |
| return nullptr; |
| } |
| }; |
| |
| template <typename... Ts> |
| struct overload_impl { |
| private: |
| template <typename> |
| struct impl; |
| |
| template <std::size_t... Is> |
| struct impl<lib::index_sequence<Is...>> : overload_leaf<Is, Ts>... {}; |
| |
| public: |
| using type = impl<lib::index_sequence_for<Ts...>>; |
| }; |
| |
| template <typename... Ts> |
| using overload = typename overload_impl<Ts...>::type; |
| |
| template <typename T, typename... Ts> |
| using best_match = lib::invoke_result_t<overload<Ts...>, T&&>; |
| |
| template <typename T> |
| struct is_in_place_index : std::false_type {}; |
| |
| template <std::size_t I> |
| struct is_in_place_index<in_place_index_t<I>> : std::true_type {}; |
| |
| template <typename T> |
| struct is_in_place_type : std::false_type {}; |
| |
| template <typename T> |
| struct is_in_place_type<in_place_type_t<T>> : std::true_type {}; |
| |
| } // namespace detail_ |
| |
| template <typename... Ts> |
| class variant { |
| static_assert( |
| 0 < sizeof...(Ts), |
| "variant must consist of at least one alternative."); |
| |
| static_assert( |
| lib::all<!std::is_array<Ts>::value...>::value, |
| "variant can not have an array type as an alternative."); |
| |
| static_assert( |
| lib::all<!std::is_reference<Ts>::value...>::value, |
| "variant can not have a reference type as an alternative."); |
| |
| static_assert( |
| lib::all<!std::is_void<Ts>::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<std::is_default_constructible<Front>::value, int> = 0> |
| inline constexpr variant() noexcept( |
| std::is_nothrow_default_constructible<Front>::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<I, Ts...>` |
| // 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<I, Ts...>, |
| // ^~~~~~~~ |
| // ``` |
| // As a workaround, `I` is changed to `detail_::best_match<Arg, |
| // Ts...>::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<Arg>, |
| lib::enable_if_t<!std::is_same<Decayed, variant>::value, int> = 0, |
| lib::enable_if_t<!detail_::is_in_place_index<Decayed>::value, int> = 0, |
| lib::enable_if_t<!detail_::is_in_place_type<Decayed>::value, int> = 0, |
| std::size_t I = detail_::best_match<Arg, Ts...>::value, |
| typename T = lib:: |
| type_pack_element_t<detail_::best_match<Arg, Ts...>::value, Ts...>, |
| lib::enable_if_t<std::is_constructible<T, Arg>::value, int> = 0> |
| inline constexpr variant(Arg&& arg) noexcept( |
| std::is_nothrow_constructible<T, Arg>::value) |
| : impl_(in_place_index_t<I>{}, lib::forward<Arg>(arg)) { |
| static_assert( |
| I == detail_::best_match<Arg, Ts...>::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<I, Ts...>, |
| lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> |
| inline explicit constexpr variant( |
| in_place_index_t<I>, |
| Args&&... args) noexcept(std::is_nothrow_constructible<T, Args...>::value) |
| : impl_(in_place_index_t<I>{}, lib::forward<Args>(args)...) {} |
| |
| template < |
| std::size_t I, |
| typename Up, |
| typename... Args, |
| typename T = lib::type_pack_element_t<I, Ts...>, |
| lib::enable_if_t< |
| std::is_constructible<T, std::initializer_list<Up>&, Args...>::value, |
| int> = 0> |
| inline explicit constexpr variant( |
| in_place_index_t<I>, |
| std::initializer_list<Up> il, |
| Args&&... args) noexcept(std:: |
| is_nothrow_constructible< |
| T, |
| std::initializer_list<Up>&, |
| Args...>::value) |
| : impl_(in_place_index_t<I>{}, il, lib::forward<Args>(args)...) {} |
| |
| template < |
| typename T, |
| typename... Args, |
| std::size_t I = detail_::find_index_sfinae<T, Ts...>::value, |
| lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> |
| inline explicit constexpr variant( |
| in_place_type_t<T>, |
| Args&&... args) noexcept(std::is_nothrow_constructible<T, Args...>::value) |
| : impl_(in_place_index_t<I>{}, lib::forward<Args>(args)...) {} |
| |
| template < |
| typename T, |
| typename Up, |
| typename... Args, |
| std::size_t I = detail_::find_index_sfinae<T, Ts...>::value, |
| lib::enable_if_t< |
| std::is_constructible<T, std::initializer_list<Up>&, Args...>::value, |
| int> = 0> |
| inline explicit constexpr variant( |
| in_place_type_t<T>, |
| std::initializer_list<Up> il, |
| Args&&... args) noexcept(std:: |
| is_nothrow_constructible< |
| T, |
| std::initializer_list<Up>&, |
| Args...>::value) |
| : impl_(in_place_index_t<I>{}, il, lib::forward<Args>(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<!std::is_same<lib::decay_t<Arg>, variant>::value, int> = |
| 0, |
| std::size_t I = detail_::best_match<Arg, Ts...>::value, |
| typename T = lib:: |
| type_pack_element_t<detail_::best_match<Arg, Ts...>::value, Ts...>, |
| lib::enable_if_t< |
| (std::is_assignable<T&, Arg>::value && |
| std::is_constructible<T, Arg>::value), |
| int> = 0> |
| inline variant& operator=(Arg&& arg) noexcept( |
| (std::is_nothrow_assignable<T&, Arg>::value && |
| std::is_nothrow_constructible<T, Arg>::value)) { |
| static_assert( |
| I == detail_::best_match<Arg, Ts...>::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<I>(lib::forward<Arg>(arg)); |
| return *this; |
| } |
| |
| template < |
| std::size_t I, |
| typename... Args, |
| typename T = lib::type_pack_element_t<I, Ts...>, |
| lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> |
| inline T& emplace(Args&&... args) { |
| return impl_.template emplace<I>(lib::forward<Args>(args)...); |
| } |
| |
| template < |
| std::size_t I, |
| typename Up, |
| typename... Args, |
| typename T = lib::type_pack_element_t<I, Ts...>, |
| lib::enable_if_t< |
| std::is_constructible<T, std::initializer_list<Up>&, Args...>::value, |
| int> = 0> |
| inline T& emplace(std::initializer_list<Up> il, Args&&... args) { |
| return impl_.template emplace<I>(il, lib::forward<Args>(args)...); |
| } |
| |
| template < |
| typename T, |
| typename... Args, |
| std::size_t I = detail_::find_index_sfinae<T, Ts...>::value, |
| lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> |
| inline T& emplace(Args&&... args) { |
| return impl_.template emplace<I>(lib::forward<Args>(args)...); |
| } |
| |
| template < |
| typename T, |
| typename Up, |
| typename... Args, |
| std::size_t I = detail_::find_index_sfinae<T, Ts...>::value, |
| lib::enable_if_t< |
| std::is_constructible<T, std::initializer_list<Up>&, Args...>::value, |
| int> = 0> |
| inline T& emplace(std::initializer_list<Up> il, Args&&... args) { |
| return impl_.template emplace<I>(il, lib::forward<Args>(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<std::is_move_constructible<Ts>, Dummy>:: |
| value && |
| lib::dependent_type<lib::is_swappable<Ts>, Dummy>::value)...>:: |
| value, |
| int> = 0> |
| inline void swap(variant& that) noexcept( |
| lib::all< |
| (std::is_nothrow_move_constructible<Ts>::value && |
| lib::is_nothrow_swappable<Ts>::value)...>::value) { |
| impl_.swap(that.impl_); |
| } |
| |
| private: |
| detail_::impl<Ts...> impl_; |
| |
| friend struct detail_::access::variant; |
| friend struct detail_::visitation::variant; |
| }; |
| |
| template <std::size_t I, typename... Ts> |
| inline constexpr bool holds_alternative(const variant<Ts...>& v) noexcept { |
| return v.index() == I; |
| } |
| |
| template <typename T, typename... Ts> |
| inline constexpr bool holds_alternative(const variant<Ts...>& v) noexcept { |
| return holds_alternative<detail_::find_index_checked<T, Ts...>::value>(v); |
| } |
| |
| namespace detail_ { |
| template <std::size_t I, typename V> |
| struct generic_get_impl { |
| constexpr generic_get_impl(int) noexcept {} |
| |
| constexpr AUTO_REFREF operator()(V&& v) const |
| AUTO_REFREF_RETURN(access::variant::get_alt<I>(lib::forward<V>(v)).value) |
| }; |
| |
| template <std::size_t I, typename V> |
| inline constexpr AUTO_REFREF generic_get(V&& v) |
| AUTO_REFREF_RETURN(generic_get_impl<I, V>( |
| holds_alternative<I>(v) |
| ? 0 |
| : (throw_bad_variant_access(), 0))(lib::forward<V>(v))) |
| } // namespace detail_ |
| |
| template <std::size_t I, typename... Ts> |
| inline constexpr variant_alternative_t<I, variant<Ts...>>& get( |
| variant<Ts...>& v) { |
| return detail_::generic_get<I>(v); |
| } |
| |
| template <std::size_t I, typename... Ts> |
| inline constexpr variant_alternative_t<I, variant<Ts...>>&& get( |
| variant<Ts...>&& v) { |
| return detail_::generic_get<I>(lib::move(v)); |
| } |
| |
| template <std::size_t I, typename... Ts> |
| inline constexpr const variant_alternative_t<I, variant<Ts...>>& get( |
| const variant<Ts...>& v) { |
| return detail_::generic_get<I>(v); |
| } |
| |
| template <std::size_t I, typename... Ts> |
| inline constexpr const variant_alternative_t<I, variant<Ts...>>&& get( |
| const variant<Ts...>&& v) { |
| return detail_::generic_get<I>(lib::move(v)); |
| } |
| |
| template <typename T, typename... Ts> |
| inline constexpr T& get(variant<Ts...>& v) { |
| return get<detail_::find_index_checked<T, Ts...>::value>(v); |
| } |
| |
| template <typename T, typename... Ts> |
| inline constexpr T&& get(variant<Ts...>&& v) { |
| return get<detail_::find_index_checked<T, Ts...>::value>(lib::move(v)); |
| } |
| |
| template <typename T, typename... Ts> |
| inline constexpr const T& get(const variant<Ts...>& v) { |
| return get<detail_::find_index_checked<T, Ts...>::value>(v); |
| } |
| |
| template <typename T, typename... Ts> |
| inline constexpr const T&& get(const variant<Ts...>&& v) { |
| return get<detail_::find_index_checked<T, Ts...>::value>(lib::move(v)); |
| } |
| |
| namespace detail_ { |
| |
| template <std::size_t I, typename V> |
| inline constexpr /* auto * */ AUTO generic_get_if(V* v) noexcept AUTO_RETURN( |
| v&& holds_alternative<I>(*v) |
| ? lib::addressof(access::variant::get_alt<I>(*v).value) |
| : nullptr) |
| |
| } // namespace detail_ |
| |
| template <std::size_t I, typename... Ts> |
| inline constexpr lib::add_pointer_t<variant_alternative_t<I, variant<Ts...>>> |
| get_if(variant<Ts...>* v) noexcept { |
| return detail_::generic_get_if<I>(v); |
| } |
| |
| template <std::size_t I, typename... Ts> |
| inline constexpr lib::add_pointer_t< |
| const variant_alternative_t<I, variant<Ts...>>> |
| get_if(const variant<Ts...>* v) noexcept { |
| return detail_::generic_get_if<I>(v); |
| } |
| |
| template <typename T, typename... Ts> |
| inline constexpr lib::add_pointer_t<T> get_if(variant<Ts...>* v) noexcept { |
| return get_if<detail_::find_index_checked<T, Ts...>::value>(v); |
| } |
| |
| template <typename T, typename... Ts> |
| inline constexpr lib::add_pointer_t<const T> get_if( |
| const variant<Ts...>* v) noexcept { |
| return get_if<detail_::find_index_checked<T, Ts...>::value>(v); |
| } |
| |
| namespace detail_ { |
| template <typename RelOp> |
| struct convert_to_bool { |
| template <typename Lhs, typename Rhs> |
| inline constexpr bool operator()(Lhs&& lhs, Rhs&& rhs) const { |
| static_assert( |
| std::is_convertible<lib::invoke_result_t<RelOp, Lhs, Rhs>, bool>::value, |
| "relational operators must return a type" |
| " implicitly convertible to bool"); |
| return lib::invoke(RelOp{}, lib::forward<Lhs>(lhs), lib::forward<Rhs>(rhs)); |
| } |
| }; |
| } // namespace detail_ |
| |
| template <typename... Ts> |
| inline constexpr bool operator==( |
| const variant<Ts...>& lhs, |
| const variant<Ts...>& rhs) { |
| using detail_::visitation::variant; |
| using equal_to = detail_::convert_to_bool<lib::equal_to>; |
| #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 <typename... Ts> |
| inline constexpr bool operator!=( |
| const variant<Ts...>& lhs, |
| const variant<Ts...>& rhs) { |
| using detail_::visitation::variant; |
| using not_equal_to = detail_::convert_to_bool<lib::not_equal_to>; |
| #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 <typename... Ts> |
| inline constexpr bool operator<( |
| const variant<Ts...>& lhs, |
| const variant<Ts...>& rhs) { |
| using detail_::visitation::variant; |
| using less = detail_::convert_to_bool<lib::less>; |
| #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 <typename... Ts> |
| inline constexpr bool operator>( |
| const variant<Ts...>& lhs, |
| const variant<Ts...>& rhs) { |
| using detail_::visitation::variant; |
| using greater = detail_::convert_to_bool<lib::greater>; |
| #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 <typename... Ts> |
| inline constexpr bool operator<=( |
| const variant<Ts...>& lhs, |
| const variant<Ts...>& rhs) { |
| using detail_::visitation::variant; |
| using less_equal = detail_::convert_to_bool<lib::less_equal>; |
| #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 <typename... Ts> |
| inline constexpr bool operator>=( |
| const variant<Ts...>& lhs, |
| const variant<Ts...>& rhs) { |
| using detail_::visitation::variant; |
| using greater_equal = detail_::convert_to_bool<lib::greater_equal>; |
| #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<bool> bs) { |
| for (bool b : bs) { |
| if (b) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| } // namespace detail_ |
| |
| template <typename Visitor, typename... Vs> |
| 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>(visitor), lib::forward<Vs>(vs)...); |
| } |
| #else |
| namespace detail_ { |
| |
| template <std::size_t N> |
| inline constexpr bool all_impl(const lib::array<bool, N>& bs, std::size_t idx) { |
| return idx >= N || (bs[idx] && all_impl(bs, idx + 1)); |
| } |
| |
| template <std::size_t N> |
| inline constexpr bool all(const lib::array<bool, N>& bs) { |
| return all_impl(bs, 0); |
| } |
| |
| } // namespace detail_ |
| |
| template <typename Visitor, typename... Vs> |
| inline constexpr DECLTYPE_AUTO visit(Visitor&& visitor, Vs&&... vs) |
| DECLTYPE_AUTO_RETURN( |
| (detail_::all(lib::array<bool, sizeof...(Vs)>{ |
| {!vs.valueless_by_exception()...}}) |
| ? (void)0 |
| : throw_bad_variant_access()), |
| detail_::visitation::variant::visit_value( |
| lib::forward<Visitor>(visitor), |
| lib::forward<Vs>(vs)...)) |
| #endif |
| |
| template <typename... Ts> |
| inline auto swap(variant<Ts...>& lhs, variant<Ts...>& rhs) noexcept( |
| noexcept(lhs.swap(rhs))) -> decltype(lhs.swap(rhs)) { |
| lhs.swap(rhs); |
| } |
| |
| namespace detail_ { |
| |
| template <typename T, typename...> |
| using enabled_type = T; |
| |
| namespace hash { |
| |
| template <typename H, typename K> |
| constexpr bool meets_requirements() noexcept { |
| return std::is_copy_constructible<H>::value && |
| std::is_move_constructible<H>::value && |
| lib::is_invocable_r<std::size_t, H, const K&>::value; |
| } |
| |
| template <typename K> |
| constexpr bool is_enabled() noexcept { |
| using H = std::hash<K>; |
| return meets_requirements<H, K>() && |
| std::is_default_constructible<H>::value && |
| std::is_copy_assignable<H>::value && std::is_move_assignable<H>::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 <typename... Ts> |
| struct hash<c10::detail_::enabled_type< |
| c10::variant<Ts...>, |
| c10::lib::enable_if_t<c10::lib::all<c10::detail_::hash::is_enabled< |
| c10::lib::remove_const_t<Ts>>()...>::value>>> { |
| using argument_type = c10::variant<Ts...>; |
| 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<decltype(alt)>; |
| using value_type = |
| c10::lib::remove_const_t<typename alt_type::value_type>; |
| return hash<value_type>{}(alt.value); |
| } |
| #else |
| hasher {} |
| #endif |
| , |
| v); |
| return hash_combine(result, hash<std::size_t>{}(v.index())); |
| } |
| |
| private: |
| #ifndef C10_MPARK_GENERIC_LAMBDAS |
| struct hasher { |
| template <typename Alt> |
| inline std::size_t operator()(const Alt& alt) const { |
| using alt_type = c10::lib::decay_t<Alt>; |
| using value_type = |
| c10::lib::remove_const_t<typename alt_type::value_type>; |
| return hash<value_type>{}(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<c10::monostate> { |
| 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_ |