blob: eda1555c0c6c07110b65590c5016b04e7579d469 [file] [log] [blame]
#pragma once
#ifndef C10_UTIL_CPP17_H_
#define C10_UTIL_CPP17_H_
#include <c10/macros/Macros.h>
#include <cstdlib>
#include <functional>
#include <memory>
#include <sstream>
#include <string>
#include <type_traits>
#include <utility>
#if !defined(__clang__) && !defined(_MSC_VER) && defined(__GNUC__) && \
__GNUC__ < 5
#error \
"You're trying to build PyTorch with a too old version of GCC. We need GCC 5 or later."
#endif
#if defined(__clang__) && __clang_major__ < 4
#error \
"You're trying to build PyTorch with a too old version of Clang. We need Clang 4 or later."
#endif
#if (defined(_MSC_VER) && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L)) || \
(!defined(_MSC_VER) && __cplusplus < 201703L)
#error You need C++17 to compile PyTorch
#endif
#if defined(_WIN32) && (defined(min) || defined(max))
#error Macro clash with min and max -- define NOMINMAX when compiling your program on Windows
#endif
/*
* This header adds some polyfills with C++17 functionality
*/
namespace c10 {
// in c++17 std::result_of has been superseded by std::invoke_result. Since
// c++20, std::result_of is removed.
template <typename F, typename... args>
#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703L
using invoke_result = typename std::invoke_result<F, args...>;
#else
using invoke_result = typename std::result_of<F && (args && ...)>;
#endif
template <typename F, typename... args>
using invoke_result_t = typename invoke_result<F, args...>::type;
// std::is_pod is deprecated in C++20, std::is_standard_layout and
// std::is_trivial are introduced in C++11, std::conjunction has been introduced
// in C++17.
template <typename T>
#if defined(__cpp_lib_logical_traits) && __cpp_lib_logical_traits >= 201510L
using is_pod = std::conjunction<std::is_standard_layout<T>, std::is_trivial<T>>;
#else
using is_pod = std::is_pod<T>;
#endif
template <typename T>
constexpr bool is_pod_v = is_pod<T>::value;
namespace guts {
template <typename Base, typename Child, typename... Args>
std::enable_if_t<
!std::is_array_v<Base> && !std::is_array_v<Child> &&
std::is_base_of_v<Base, Child>,
std::unique_ptr<Base>>
make_unique_base(Args&&... args) {
return std::unique_ptr<Base>(new Child(std::forward<Args>(args)...));
}
template <class... B>
using conjunction = std::conjunction<B...>;
template <class... B>
using disjunction = std::disjunction<B...>;
template <bool B>
using bool_constant = std::bool_constant<B>;
template <class B>
using negation = std::negation<B>;
template <class T>
using void_t = std::void_t<T>;
#if defined(USE_ROCM)
// rocm doesn't like the C10_HOST_DEVICE
#define CUDA_HOST_DEVICE
#else
#define CUDA_HOST_DEVICE C10_HOST_DEVICE
#endif
#if defined(__cpp_lib_apply) && !defined(__CUDA_ARCH__)
template <class F, class Tuple>
CUDA_HOST_DEVICE inline constexpr decltype(auto) apply(F&& f, Tuple&& t) {
return std::apply(std::forward<F>(f), std::forward<Tuple>(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 <class F, class Tuple, std::size_t... INDEX>
#if defined(_MSC_VER)
// MSVC has a problem with the decltype() return type, but it also doesn't need
// it
C10_HOST_DEVICE constexpr auto apply_impl(
F&& f,
Tuple&& t,
std::index_sequence<INDEX...>)
#else
// GCC/Clang need the decltype() return type
CUDA_HOST_DEVICE constexpr decltype(auto) apply_impl(
F&& f,
Tuple&& t,
std::index_sequence<INDEX...>)
#endif
{
return std::forward<F>(f)(std::get<INDEX>(std::forward<Tuple>(t))...);
}
} // namespace detail
template <class F, class Tuple>
CUDA_HOST_DEVICE constexpr decltype(auto) apply(F&& f, Tuple&& t) {
return detail::apply_impl(
std::forward<F>(f),
std::forward<Tuple>(t),
std::make_index_sequence<
std::tuple_size<std::remove_reference_t<Tuple>>::value>{});
}
#endif
#undef CUDA_HOST_DEVICE
template <typename Functor, typename... Args>
std::enable_if_t<
std::is_member_pointer_v<std::decay_t<Functor>>,
typename c10::invoke_result_t<Functor, Args...>>
invoke(Functor&& f, Args&&... args) {
return std::mem_fn(std::forward<Functor>(f))(std::forward<Args>(args)...);
}
template <typename Functor, typename... Args>
std::enable_if_t<
!std::is_member_pointer_v<std::decay_t<Functor>>,
typename c10::invoke_result_t<Functor, Args...>>
invoke(Functor&& f, Args&&... args) {
return std::forward<Functor>(f)(std::forward<Args>(args)...);
}
namespace detail {
struct _identity final {
template <class T>
using type_identity = T;
template <class T>
decltype(auto) operator()(T&& arg) {
return std::forward<T>(arg);
}
};
template <class Func, class Enable = void>
struct function_takes_identity_argument : std::false_type {};
template <class Func>
struct function_takes_identity_argument<
Func,
std::void_t<decltype(std::declval<Func>()(_identity()))>> : std::true_type {
};
} // namespace detail
} // namespace guts
} // namespace c10
#endif // C10_UTIL_CPP17_H_