1 | // Copyright 2017 The Abseil Authors. |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | // |
15 | // absl::base_internal::invoke(f, args...) is an implementation of |
16 | // INVOKE(f, args...) from section [func.require] of the C++ standard. |
17 | // When compiled as C++17 and later versions, it is implemented as an alias of |
18 | // std::invoke. |
19 | // |
20 | // [func.require] |
21 | // Define INVOKE (f, t1, t2, ..., tN) as follows: |
22 | // 1. (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T |
23 | // and t1 is an object of type T or a reference to an object of type T or a |
24 | // reference to an object of a type derived from T; |
25 | // 2. ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a |
26 | // class T and t1 is not one of the types described in the previous item; |
27 | // 3. t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is |
28 | // an object of type T or a reference to an object of type T or a reference |
29 | // to an object of a type derived from T; |
30 | // 4. (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 |
31 | // is not one of the types described in the previous item; |
32 | // 5. f(t1, t2, ..., tN) in all other cases. |
33 | // |
34 | // The implementation is SFINAE-friendly: substitution failure within invoke() |
35 | // isn't an error. |
36 | |
37 | #ifndef ABSL_BASE_INTERNAL_INVOKE_H_ |
38 | #define ABSL_BASE_INTERNAL_INVOKE_H_ |
39 | |
40 | #include "absl/base/config.h" |
41 | |
42 | #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L |
43 | |
44 | #include <functional> |
45 | |
46 | namespace absl { |
47 | ABSL_NAMESPACE_BEGIN |
48 | namespace base_internal { |
49 | |
50 | using std::invoke; |
51 | using std::invoke_result_t; |
52 | using std::is_invocable_r; |
53 | |
54 | } // namespace base_internal |
55 | ABSL_NAMESPACE_END |
56 | } // namespace absl |
57 | |
58 | #else // ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L |
59 | |
60 | #include <algorithm> |
61 | #include <type_traits> |
62 | #include <utility> |
63 | |
64 | #include "absl/meta/type_traits.h" |
65 | |
66 | // The following code is internal implementation detail. See the comment at the |
67 | // top of this file for the API documentation. |
68 | |
69 | namespace absl { |
70 | ABSL_NAMESPACE_BEGIN |
71 | namespace base_internal { |
72 | |
73 | // The five classes below each implement one of the clauses from the definition |
74 | // of INVOKE. The inner class template Accept<F, Args...> checks whether the |
75 | // clause is applicable; static function template Invoke(f, args...) does the |
76 | // invocation. |
77 | // |
78 | // By separating the clause selection logic from invocation we make sure that |
79 | // Invoke() does exactly what the standard says. |
80 | |
81 | template <typename Derived> |
82 | struct StrippedAccept { |
83 | template <typename... Args> |
84 | struct Accept : Derived::template AcceptImpl<typename std::remove_cv< |
85 | typename std::remove_reference<Args>::type>::type...> {}; |
86 | }; |
87 | |
88 | // (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T |
89 | // and t1 is an object of type T or a reference to an object of type T or a |
90 | // reference to an object of a type derived from T. |
91 | struct MemFunAndRef : StrippedAccept<MemFunAndRef> { |
92 | template <typename... Args> |
93 | struct AcceptImpl : std::false_type {}; |
94 | |
95 | template <typename MemFunType, typename C, typename Obj, typename... Args> |
96 | struct AcceptImpl<MemFunType C::*, Obj, Args...> |
97 | : std::integral_constant<bool, std::is_base_of<C, Obj>::value && |
98 | absl::is_function<MemFunType>::value> { |
99 | }; |
100 | |
101 | template <typename MemFun, typename Obj, typename... Args> |
102 | static decltype((std::declval<Obj>().* |
103 | std::declval<MemFun>())(std::declval<Args>()...)) |
104 | Invoke(MemFun&& mem_fun, Obj&& obj, Args&&... args) { |
105 | // Ignore bogus GCC warnings on this line. |
106 | // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101436 for similar example. |
107 | #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(11, 0) |
108 | #pragma GCC diagnostic push |
109 | #pragma GCC diagnostic ignored "-Warray-bounds" |
110 | #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" |
111 | #endif |
112 | return (std::forward<Obj>(obj).* |
113 | std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...); |
114 | #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(11, 0) |
115 | #pragma GCC diagnostic pop |
116 | #endif |
117 | } |
118 | }; |
119 | |
120 | // ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a |
121 | // class T and t1 is not one of the types described in the previous item. |
122 | struct MemFunAndPtr : StrippedAccept<MemFunAndPtr> { |
123 | template <typename... Args> |
124 | struct AcceptImpl : std::false_type {}; |
125 | |
126 | template <typename MemFunType, typename C, typename Ptr, typename... Args> |
127 | struct AcceptImpl<MemFunType C::*, Ptr, Args...> |
128 | : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value && |
129 | absl::is_function<MemFunType>::value> { |
130 | }; |
131 | |
132 | template <typename MemFun, typename Ptr, typename... Args> |
133 | static decltype(((*std::declval<Ptr>()).* |
134 | std::declval<MemFun>())(std::declval<Args>()...)) |
135 | Invoke(MemFun&& mem_fun, Ptr&& ptr, Args&&... args) { |
136 | return ((*std::forward<Ptr>(ptr)).* |
137 | std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...); |
138 | } |
139 | }; |
140 | |
141 | // t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is |
142 | // an object of type T or a reference to an object of type T or a reference |
143 | // to an object of a type derived from T. |
144 | struct DataMemAndRef : StrippedAccept<DataMemAndRef> { |
145 | template <typename... Args> |
146 | struct AcceptImpl : std::false_type {}; |
147 | |
148 | template <typename R, typename C, typename Obj> |
149 | struct AcceptImpl<R C::*, Obj> |
150 | : std::integral_constant<bool, std::is_base_of<C, Obj>::value && |
151 | !absl::is_function<R>::value> {}; |
152 | |
153 | template <typename DataMem, typename Ref> |
154 | static decltype(std::declval<Ref>().*std::declval<DataMem>()) Invoke( |
155 | DataMem&& data_mem, Ref&& ref) { |
156 | return std::forward<Ref>(ref).*std::forward<DataMem>(data_mem); |
157 | } |
158 | }; |
159 | |
160 | // (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 |
161 | // is not one of the types described in the previous item. |
162 | struct DataMemAndPtr : StrippedAccept<DataMemAndPtr> { |
163 | template <typename... Args> |
164 | struct AcceptImpl : std::false_type {}; |
165 | |
166 | template <typename R, typename C, typename Ptr> |
167 | struct AcceptImpl<R C::*, Ptr> |
168 | : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value && |
169 | !absl::is_function<R>::value> {}; |
170 | |
171 | template <typename DataMem, typename Ptr> |
172 | static decltype((*std::declval<Ptr>()).*std::declval<DataMem>()) Invoke( |
173 | DataMem&& data_mem, Ptr&& ptr) { |
174 | return (*std::forward<Ptr>(ptr)).*std::forward<DataMem>(data_mem); |
175 | } |
176 | }; |
177 | |
178 | // f(t1, t2, ..., tN) in all other cases. |
179 | struct Callable { |
180 | // Callable doesn't have Accept because it's the last clause that gets picked |
181 | // when none of the previous clauses are applicable. |
182 | template <typename F, typename... Args> |
183 | static decltype(std::declval<F>()(std::declval<Args>()...)) Invoke( |
184 | F&& f, Args&&... args) { |
185 | return std::forward<F>(f)(std::forward<Args>(args)...); |
186 | } |
187 | }; |
188 | |
189 | // Resolves to the first matching clause. |
190 | template <typename... Args> |
191 | struct Invoker { |
192 | typedef typename std::conditional< |
193 | MemFunAndRef::Accept<Args...>::value, MemFunAndRef, |
194 | typename std::conditional< |
195 | MemFunAndPtr::Accept<Args...>::value, MemFunAndPtr, |
196 | typename std::conditional< |
197 | DataMemAndRef::Accept<Args...>::value, DataMemAndRef, |
198 | typename std::conditional<DataMemAndPtr::Accept<Args...>::value, |
199 | DataMemAndPtr, Callable>::type>::type>:: |
200 | type>::type type; |
201 | }; |
202 | |
203 | // The result type of Invoke<F, Args...>. |
204 | template <typename F, typename... Args> |
205 | using invoke_result_t = decltype(Invoker<F, Args...>::type::Invoke( |
206 | std::declval<F>(), std::declval<Args>()...)); |
207 | |
208 | // Invoke(f, args...) is an implementation of INVOKE(f, args...) from section |
209 | // [func.require] of the C++ standard. |
210 | template <typename F, typename... Args> |
211 | invoke_result_t<F, Args...> invoke(F&& f, Args&&... args) { |
212 | return Invoker<F, Args...>::type::Invoke(std::forward<F>(f), |
213 | std::forward<Args>(args)...); |
214 | } |
215 | |
216 | template <typename AlwaysVoid, typename, typename, typename...> |
217 | struct IsInvocableRImpl : std::false_type {}; |
218 | |
219 | template <typename R, typename F, typename... Args> |
220 | struct IsInvocableRImpl< |
221 | absl::void_t<absl::base_internal::invoke_result_t<F, Args...> >, R, F, |
222 | Args...> |
223 | : std::integral_constant< |
224 | bool, |
225 | std::is_convertible<absl::base_internal::invoke_result_t<F, Args...>, |
226 | R>::value || |
227 | std::is_void<R>::value> {}; |
228 | |
229 | // Type trait whose member `value` is true if invoking `F` with `Args` is valid, |
230 | // and either the return type is convertible to `R`, or `R` is void. |
231 | // C++11-compatible version of `std::is_invocable_r`. |
232 | template <typename R, typename F, typename... Args> |
233 | using is_invocable_r = IsInvocableRImpl<void, R, F, Args...>; |
234 | |
235 | } // namespace base_internal |
236 | ABSL_NAMESPACE_END |
237 | } // namespace absl |
238 | |
239 | #endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L |
240 | |
241 | #endif // ABSL_BASE_INTERNAL_INVOKE_H_ |
242 | |