mirror of
https://github.com/zebrajr/pytorch.git
synced 2025-12-07 12:21:27 +01:00
Re-land of https://github.com/pytorch/pytorch/pull/82626 which somehow broke deploy build Fixes annoying warnings when building with clang: ``` ../c10/util/variant.h:2256:9: warning: definition of implicit copy constructor for 'impl<c10::Scalar, c10::basic_string_view<char>>' is deprecated because it has a user-declared copy assignment operator [-Wdeprecated-copy] impl& operator=(const impl& other) = default; ^ ``` Preliminary step for switching MacOS builds to ones with `-Werror` Pull Request resolved: https://github.com/pytorch/pytorch/pull/83030 Approved by: https://github.com/kit1980, https://github.com/seemethere
3026 lines
94 KiB
C++
3026 lines
94 KiB
C++
// 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_
|