1 | #pragma once |
2 | |
3 | #include <c10/util/C++17.h> |
4 | #include <functional> |
5 | |
6 | namespace c10 { |
7 | namespace guts { |
8 | |
9 | /** |
10 | * is_equality_comparable<T> is true_type iff the equality operator is defined |
11 | * for T. |
12 | */ |
13 | template <class T, class Enable = void> |
14 | struct is_equality_comparable : std::false_type {}; |
15 | template <class T> |
16 | struct is_equality_comparable< |
17 | T, |
18 | void_t<decltype(std::declval<T&>() == std::declval<T&>())>> |
19 | : std::true_type {}; |
20 | template <class T> |
21 | using is_equality_comparable_t = typename is_equality_comparable<T>::type; |
22 | |
23 | /** |
24 | * is_hashable<T> is true_type iff std::hash is defined for T |
25 | */ |
26 | template <class T, class Enable = void> |
27 | struct is_hashable : std::false_type {}; |
28 | template <class T> |
29 | struct is_hashable<T, void_t<decltype(std::hash<T>()(std::declval<T&>()))>> |
30 | : std::true_type {}; |
31 | template <class T> |
32 | using is_hashable_t = typename is_hashable<T>::type; |
33 | |
34 | /** |
35 | * is_function_type<T> is true_type iff T is a plain function type (i.e. |
36 | * "Result(Args...)") |
37 | */ |
38 | template <class T> |
39 | struct is_function_type : std::false_type {}; |
40 | template <class Result, class... Args> |
41 | struct is_function_type<Result(Args...)> : std::true_type {}; |
42 | template <class T> |
43 | using is_function_type_t = typename is_function_type<T>::type; |
44 | |
45 | /** |
46 | * is_instantiation_of<T, I> is true_type iff I is a template instantiation of T |
47 | * (e.g. vector<int> is an instantiation of vector) Example: |
48 | * is_instantiation_of_t<vector, vector<int>> // true |
49 | * is_instantiation_of_t<pair, pair<int, string>> // true |
50 | * is_instantiation_of_t<vector, pair<int, string>> // false |
51 | */ |
52 | template <template <class...> class Template, class T> |
53 | struct is_instantiation_of : std::false_type {}; |
54 | template <template <class...> class Template, class... Args> |
55 | struct is_instantiation_of<Template, Template<Args...>> : std::true_type {}; |
56 | template <template <class...> class Template, class T> |
57 | using is_instantiation_of_t = typename is_instantiation_of<Template, T>::type; |
58 | |
59 | namespace detail { |
60 | /** |
61 | * strip_class: helper to remove the class type from pointers to `operator()`. |
62 | */ |
63 | |
64 | template <typename T> |
65 | struct strip_class {}; |
66 | template <typename Class, typename Result, typename... Args> |
67 | struct strip_class<Result (Class::*)(Args...)> { |
68 | using type = Result(Args...); |
69 | }; |
70 | template <typename Class, typename Result, typename... Args> |
71 | struct strip_class<Result (Class::*)(Args...) const> { |
72 | using type = Result(Args...); |
73 | }; |
74 | template <typename T> |
75 | using strip_class_t = typename strip_class<T>::type; |
76 | } // namespace detail |
77 | |
78 | /** |
79 | * Evaluates to true_type, iff the given class is a Functor |
80 | * (i.e. has a call operator with some set of arguments) |
81 | */ |
82 | |
83 | template <class Functor, class Enable = void> |
84 | struct is_functor : std::false_type {}; |
85 | template <class Functor> |
86 | struct is_functor< |
87 | Functor, |
88 | std::enable_if_t<is_function_type< |
89 | detail::strip_class_t<decltype(&Functor::operator())>>::value>> |
90 | : std::true_type {}; |
91 | |
92 | /** |
93 | * lambda_is_stateless<T> is true iff the lambda type T is stateless |
94 | * (i.e. does not have a closure). |
95 | * Example: |
96 | * auto stateless_lambda = [] (int a) {return a;}; |
97 | * lambda_is_stateless<decltype(stateless_lambda)> // true |
98 | * auto stateful_lambda = [&] (int a) {return a;}; |
99 | * lambda_is_stateless<decltype(stateful_lambda)> // false |
100 | */ |
101 | namespace detail { |
102 | template <class LambdaType, class FuncType> |
103 | struct is_stateless_lambda__ final { |
104 | static_assert( |
105 | !std::is_same<LambdaType, LambdaType>::value, |
106 | "Base case shouldn't be hit" ); |
107 | }; |
108 | // implementation idea: According to the C++ standard, stateless lambdas are |
109 | // convertible to function pointers |
110 | template <class LambdaType, class C, class Result, class... Args> |
111 | struct is_stateless_lambda__<LambdaType, Result (C::*)(Args...) const> |
112 | : std::is_convertible<LambdaType, Result (*)(Args...)> {}; |
113 | template <class LambdaType, class C, class Result, class... Args> |
114 | struct is_stateless_lambda__<LambdaType, Result (C::*)(Args...)> |
115 | : std::is_convertible<LambdaType, Result (*)(Args...)> {}; |
116 | |
117 | // case where LambdaType is not even a functor |
118 | template <class LambdaType, class Enable = void> |
119 | struct is_stateless_lambda_ final : std::false_type {}; |
120 | // case where LambdaType is a functor |
121 | template <class LambdaType> |
122 | struct is_stateless_lambda_< |
123 | LambdaType, |
124 | std::enable_if_t<is_functor<LambdaType>::value>> |
125 | : is_stateless_lambda__<LambdaType, decltype(&LambdaType::operator())> {}; |
126 | } // namespace detail |
127 | template <class T> |
128 | using is_stateless_lambda = detail::is_stateless_lambda_<std::decay_t<T>>; |
129 | |
130 | /** |
131 | * is_type_condition<C> is true_type iff C<...> is a type trait representing a |
132 | * condition (i.e. has a constexpr static bool ::value member) Example: |
133 | * is_type_condition<std::is_reference> // true |
134 | */ |
135 | template <template <class> class C, class Enable = void> |
136 | struct is_type_condition : std::false_type {}; |
137 | template <template <class> class C> |
138 | struct is_type_condition< |
139 | C, |
140 | std::enable_if_t< |
141 | std::is_same<bool, std::remove_cv_t<decltype(C<int>::value)>>::value>> |
142 | : std::true_type {}; |
143 | |
144 | /** |
145 | * is_fundamental<T> is true_type iff the lambda type T is a fundamental type |
146 | * (that is, arithmetic type, void, or nullptr_t). Example: is_fundamental<int> |
147 | * // true We define it here to resolve a MSVC bug. See |
148 | * https://github.com/pytorch/pytorch/issues/30932 for details. |
149 | */ |
150 | template <class T> |
151 | struct is_fundamental : std::is_fundamental<T> {}; |
152 | } // namespace guts |
153 | } // namespace c10 |
154 | |