#pragma once #ifndef C10_UTIL_CPP17_H_ #define C10_UTIL_CPP17_H_ #include #include #include #include #include #include #include #include /* * This header adds some polyfills with C++14 and C++17 functionality */ namespace c10 { namespace guts { #ifdef __cpp_lib_transformation_trait_aliases template using conditional_t = std::conditional_t; template using enable_if_t = std::enable_if_t; template using add_lvalue_reference_t = std::add_lvalue_reference_t; template using remove_reference_t = std::remove_reference_t; template using remove_cv_t = std::remove_cv_t; template using result_of_t = std::result_of_t; template using decay_t = std::decay_t; template using remove_const_t = std::remove_const_t; template using remove_pointer_t = std::remove_pointer_t; template using common_type_t = std::common_type_t; #else template using conditional_t = typename std::conditional::type; template using enable_if_t = typename std::enable_if::type; template using add_lvalue_reference_t = typename std::add_lvalue_reference::type; template using remove_reference_t = typename std::remove_reference::type; template using remove_cv_t = typename std::remove_cv::type; template using result_of_t = typename std::result_of::type; template using decay_t = typename std::decay::type; template using remove_const_t = typename std::remove_const::type; template using remove_pointer_t = typename std::remove_pointer::type; template using common_type_t = typename std::common_type::type; #endif // C++11 doesn't have constexpr std::move / std::forward. // Implementation taken from libc++. template constexpr inline guts::remove_reference_t&& move(T&& t) noexcept { return static_cast&&>(t); } template constexpr inline T&& forward(guts::remove_reference_t& t) noexcept { return static_cast(t); } template constexpr inline T&& forward(guts::remove_reference_t&& t) noexcept { static_assert(!std::is_lvalue_reference::value, "can not forward an rvalue as an lvalue."); return static_cast(t); } #if __cplusplus >= 201402L || defined(__cpp_lib_make_unique) && __cpp_lib_make_unique >= 201304L || \ (defined(__ANDROID__) && __ANDROID__ && __cplusplus >= 201300L) || defined(_MSC_VER) && _MSC_VER >= 1900 /* using override */ using std::make_unique; #else // Implementation taken from folly template typename std::enable_if::value, std::unique_ptr>::type make_unique(Args&&... args) { return std::unique_ptr(new T(c10::guts::forward(args)...)); } // Allows 'make_unique(10)'. (N3690 s20.9.1.4 p3-4) template typename std::enable_if::value, std::unique_ptr>::type make_unique(const size_t n) { return std::unique_ptr(new typename std::remove_extent::type[n]()); } // Disallows 'make_unique()'. (N3690 s20.9.1.4 p5) template typename std::enable_if::value != 0, std::unique_ptr>::type make_unique(Args&&...) = delete; #endif template typename std::enable_if::value && !std::is_array::value && std::is_base_of::value, std::unique_ptr>::type make_unique_base(Args&&... args) { return std::unique_ptr(new Child(c10::guts::forward(args)...)); } #ifdef __cpp_lib_integer_sequence template using integer_sequence = std::integer_sequence; template using index_sequence = std::index_sequence; template using make_integer_sequence = std::make_integer_sequence; template using make_index_sequence = std::make_index_sequence; template using index_sequence_for = std::index_sequence_for; #else template struct integer_sequence { using value_type = T; static constexpr std::size_t size() noexcept {return sizeof...(Ints);} }; template using index_sequence = integer_sequence; namespace detail { template struct make_integer_sequence_ { using type = typename make_integer_sequence_::type; }; template struct make_integer_sequence_ { using type = integer_sequence; }; } template using make_integer_sequence = typename detail::make_integer_sequence_::type; template using make_index_sequence = make_integer_sequence; static_assert(std::is_same, make_index_sequence<0>>::value, ""); static_assert(std::is_same, make_index_sequence<3>>::value, ""); template using index_sequence_for = make_index_sequence; #endif #ifdef __cpp_lib_logical_traits template using conjunction = std::conjunction; template using disjunction = std::disjunction; template using bool_constant = std::bool_constant; template using negation = std::negation; #else // Implementation taken from http://en.cppreference.com/w/cpp/types/conjunction template struct conjunction : std::true_type { }; template struct conjunction : B1 { }; template struct conjunction : conditional_t, B1> {}; // Implementation taken from http://en.cppreference.com/w/cpp/types/disjunction template struct disjunction : std::false_type { }; template struct disjunction : B1 { }; template struct disjunction : conditional_t> { }; // Implementation taken from http://en.cppreference.com/w/cpp/types/integral_constant template using bool_constant = std::integral_constant; // Implementation taken from http://en.cppreference.com/w/cpp/types/negation template struct negation : bool_constant { }; #endif #ifdef __cpp_lib_void_t template using void_t = std::void_t; #else // Implementation taken from http://en.cppreference.com/w/cpp/types/void_t // (it takes CWG1558 into account and also works for older compilers) template struct make_void { typedef void type;}; template using void_t = typename make_void::type; #endif #ifdef __cpp_lib_apply template inline constexpr decltype(auto) apply(F&& f, Tuple&& t) { return std::apply(std::forward(f), std::forward(t)); } #else // Implementation from http://en.cppreference.com/w/cpp/utility/apply (but modified) // TODO This is an incomplete implementation of std::apply, not working for member functions. namespace detail { template #if defined(_MSC_VER) // MSVC has a problem with the decltype() return type, but it also doesn't need it // Also, nvcc on Windows needs C10_HOST_DEVICE here. C10_HOST_DEVICE constexpr auto apply_impl(F&& f, Tuple&& t, guts::index_sequence) #else // GCC/Clang need the decltype() return type and rocm doesn't like the C10_HOST_DEVICE constexpr auto apply_impl(F&& f, Tuple&& t, guts::index_sequence) -> decltype(c10::guts::forward(f)(std::get(c10::guts::forward(t))...)) #endif { return c10::guts::forward(f)(std::get(c10::guts::forward(t))...); } } // namespace detail template #if defined(_MSC_VER) C10_HOST_DEVICE // rocm doesn't like the C10_HOST_DEVICE #endif constexpr auto apply(F&& f, Tuple&& t) -> decltype(detail::apply_impl( c10::guts::forward(f), c10::guts::forward(t), guts::make_index_sequence>::value>{})) { return detail::apply_impl( c10::guts::forward(f), c10::guts::forward(t), guts::make_index_sequence>::value>{}); } #endif template typename std::enable_if< std::is_member_pointer::type>::value, typename std::result_of::type>::type invoke(Functor&& f, Args&&... args) { return std::mem_fn(f)(std::forward(args)...); } template typename std::enable_if< !std::is_member_pointer::type>::value, typename std::result_of::type>::type invoke(Functor&& f, Args&&... args) { return std::forward(f)(std::forward(args)...); } // GCC 4.8 doesn't define std::to_string, even though that's in C++11. Let's define it. namespace detail { class DummyClassForToString final {}; }}} namespace std { // We use SFINAE to detect if std::to_string exists for a type, but that only works // if the function name is defined. So let's define a std::to_string for a dummy type. // If you're getting an error here saying that this overload doesn't match your // std::to_string() call, then you're calling std::to_string() but should be calling // c10::guts::to_string(). inline std::string to_string(c10::guts::detail::DummyClassForToString) { return ""; } } namespace c10 { namespace guts { namespace detail { template struct to_string_ final { static std::string call(T value) { std::ostringstream str; str << value; return str.str(); } }; // If a std::to_string exists, use that instead template struct to_string_()))>> final { static std::string call(T value) { return std::to_string(value); } }; } template inline std::string to_string(T value) { return detail::to_string_::call(value); } }} #endif // C10_UTIL_CPP17_H_