xref: /aosp_15_r20/external/pytorch/c10/util/C++17.h (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1 #pragma once
2 #ifndef C10_UTIL_CPP17_H_
3 #define C10_UTIL_CPP17_H_
4 
5 #include <c10/macros/Macros.h>
6 #include <functional>
7 #include <memory>
8 #include <type_traits>
9 #include <utility>
10 
11 #if !defined(__clang__) && !defined(_MSC_VER) && defined(__GNUC__) && \
12     __GNUC__ < 9
13 #error \
14     "You're trying to build PyTorch with a too old version of GCC. We need GCC 9 or later."
15 #endif
16 
17 #if defined(__clang__) && __clang_major__ < 9
18 #error \
19     "You're trying to build PyTorch with a too old version of Clang. We need Clang 9 or later."
20 #endif
21 
22 #if (defined(_MSC_VER) && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L)) || \
23     (!defined(_MSC_VER) && __cplusplus < 201703L)
24 #error You need C++17 to compile PyTorch
25 #endif
26 
27 #if defined(_WIN32) && (defined(min) || defined(max))
28 #error Macro clash with min and max -- define NOMINMAX when compiling your program on Windows
29 #endif
30 
31 /*
32  * This header adds some polyfills with C++17 functionality
33  */
34 
35 namespace c10 {
36 
37 // std::is_pod is deprecated in C++20, std::is_standard_layout and
38 // std::is_trivial are introduced in C++11, std::conjunction has been introduced
39 // in C++17.
40 template <typename T>
41 using is_pod = std::conjunction<std::is_standard_layout<T>, std::is_trivial<T>>;
42 
43 template <typename T>
44 constexpr bool is_pod_v = is_pod<T>::value;
45 
46 namespace guts {
47 
48 template <typename Base, typename Child, typename... Args>
49 std::enable_if_t<
50     !std::is_array_v<Base> && !std::is_array_v<Child> &&
51         std::is_base_of_v<Base, Child>,
52     std::unique_ptr<Base>>
make_unique_base(Args &&...args)53 make_unique_base(Args&&... args) {
54   return std::unique_ptr<Base>(new Child(std::forward<Args>(args)...));
55 }
56 
57 #if defined(__cpp_lib_apply) && !defined(__CUDA_ARCH__) && !defined(__HIP__)
58 
59 template <class F, class Tuple>
decltype(auto)60 C10_HOST_DEVICE inline constexpr decltype(auto) apply(F&& f, Tuple&& t) {
61   return std::apply(std::forward<F>(f), std::forward<Tuple>(t));
62 }
63 
64 #else
65 
66 // Implementation from http://en.cppreference.com/w/cpp/utility/apply (but
67 // modified)
68 // TODO This is an incomplete implementation of std::apply, not working for
69 // member functions.
70 namespace detail {
71 template <class F, class Tuple, std::size_t... INDEX>
72 #if defined(_MSC_VER)
73 // MSVC has a problem with the decltype() return type, but it also doesn't need
74 // it
apply_impl(F && f,Tuple && t,std::index_sequence<INDEX...>)75 C10_HOST_DEVICE constexpr auto apply_impl(
76     F&& f,
77     Tuple&& t,
78     std::index_sequence<INDEX...>)
79 #else
80 // GCC/Clang need the decltype() return type
81 C10_HOST_DEVICE constexpr decltype(auto) apply_impl(
82     F&& f,
83     Tuple&& t,
84     std::index_sequence<INDEX...>)
85 #endif
86 {
87   return std::forward<F>(f)(std::get<INDEX>(std::forward<Tuple>(t))...);
88 }
89 } // namespace detail
90 
91 template <class F, class Tuple>
decltype(auto)92 C10_HOST_DEVICE constexpr decltype(auto) apply(F&& f, Tuple&& t) {
93   return detail::apply_impl(
94       std::forward<F>(f),
95       std::forward<Tuple>(t),
96       std::make_index_sequence<
97           std::tuple_size<std::remove_reference_t<Tuple>>::value>{});
98 }
99 
100 #endif
101 
102 template <typename Functor, typename... Args>
103 std::enable_if_t<
104     std::is_member_pointer_v<std::decay_t<Functor>>,
105     typename std::invoke_result_t<Functor, Args...>>
invoke(Functor && f,Args &&...args)106 invoke(Functor&& f, Args&&... args) {
107   return std::mem_fn(std::forward<Functor>(f))(std::forward<Args>(args)...);
108 }
109 
110 template <typename Functor, typename... Args>
111 std::enable_if_t<
112     !std::is_member_pointer_v<std::decay_t<Functor>>,
113     typename std::invoke_result_t<Functor, Args...>>
invoke(Functor && f,Args &&...args)114 invoke(Functor&& f, Args&&... args) {
115   return std::forward<Functor>(f)(std::forward<Args>(args)...);
116 }
117 
118 namespace detail {
119 struct _identity final {
120   template <class T>
121   using type_identity = T;
122 
123   template <class T>
decltypefinal124   decltype(auto) operator()(T&& arg) {
125     return std::forward<T>(arg);
126   }
127 };
128 
129 template <class Func, class Enable = void>
130 struct function_takes_identity_argument : std::false_type {};
131 
132 template <class Func>
133 struct function_takes_identity_argument<
134     Func,
135     std::void_t<decltype(std::declval<Func>()(_identity()))>> : std::true_type {
136 };
137 } // namespace detail
138 
139 } // namespace guts
140 } // namespace c10
141 
142 #endif // C10_UTIL_CPP17_H_
143