2 * Copyright 2016 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 // included by Function.h, do not include directly.
28 struct SelectConstFunctionTag {
30 using QualifiedPointer = T const*;
32 struct SelectNonConstFunctionTag {
34 using QualifiedPointer = T*;
37 // Helper to check whether the return type of a callable matches that of
38 // a folly::Function object. Either because the former is convertible to
39 // the latter, or the latter is void (possibly cv-qualified)
40 template <typename CallableR, typename FollyFunctionR>
41 using ReturnTypeMatches = std::integral_constant<
43 std::is_convertible<CallableR, FollyFunctionR>::value ||
44 std::is_same<typename std::decay<FollyFunctionR>::type, void>::value>;
46 // Helper class to extract properties from a function type
48 struct FunctionTypeTraits;
50 // FunctionTypeTraits default implementation - this only exists to suppress
51 // very long compiler errors when Function is tried to be instantiated
52 // with an unsuitable type
54 struct FunctionTypeTraits {
55 using SuitableForFunction = std::false_type;
57 // The following definitions are here only to suppress long and misleading
59 using ResultType = void;
60 using ArgsTuple = int;
61 using ArgsRefTuple = int;
62 using NonConstFunctionType = void;
63 using ConstFunctionType = int;
66 class InvokeOperator {};
67 class ExecutorMixin {};
70 // FunctionTypeTraits for non-const function types
71 template <typename R, typename... Args>
72 struct FunctionTypeTraits<R(Args...)> {
73 using SuitableForFunction = std::true_type;
75 using ArgsTuple = std::tuple<Args...>;
76 using ArgsRefTuple = std::tuple<Args&&...>;
77 using NonConstFunctionType = R(Args...);
78 using ConstFunctionType = R(Args...) const;
79 using IsConst = std::false_type;
80 using DefaultSelectFunctionTag = SelectNonConstFunctionTag;
83 ReturnTypeMatches<typename std::result_of<F&(Args...)>::type, R>;
85 using QualifiedPointer = T*;
86 template <typename Obj>
87 using InvokeFunctionPtr = R (*)(Obj*, Args&&...);
89 // Function inherits from InvokeOperator<Function>. This is
90 // where Function's operator() is defined.
91 template <typename FunctionType>
92 class InvokeOperator {
95 * Invokes the stored callable via the invokePtr stored in the Executor.
97 * Throws std::bad_function_call if @c *this is empty.
99 ResultType operator()(Args... args) {
101 static_cast<FunctionType*>(this)
102 ->template access<typename FunctionType::ExecutorIf>();
103 return executor->invokePtr(executor, std::forward<Args>(args)...);
110 // FunctionTypeTraits for const function types
111 template <typename R, typename... Args>
112 struct FunctionTypeTraits<R(Args...) const> {
113 using SuitableForFunction = std::true_type;
114 using ResultType = R;
115 using ArgsTuple = std::tuple<Args...>;
116 using ArgsRefTuple = std::tuple<Args&&...>;
117 using NonConstFunctionType = R(Args...);
118 using ConstFunctionType = R(Args...) const;
119 using IsConst = std::true_type;
120 using DefaultSelectFunctionTag = SelectConstFunctionTag;
121 template <typename F>
123 ReturnTypeMatches<typename std::result_of<F const&(Args...)>::type, R>;
124 template <typename T>
125 using QualifiedPointer = T const*;
126 template <typename Obj>
127 using InvokeFunctionPtr = R (*)(Obj const*, Args&&...);
129 // Function inherits from InvokeOperator<Function>. This is
130 // where Function's operator() is defined.
131 template <typename FunctionType>
132 class InvokeOperator {
135 * Invokes the stored callable via the invokePtr stored in the Executor.
137 * Throws std::bad_function_call if @c *this is empty.
139 ResultType operator()(Args... args) const {
141 static_cast<FunctionType const*>(this)
142 ->template access<typename FunctionType::ExecutorIf>();
143 return executor->invokePtr(executor, std::forward<Args>(args)...);
150 // Helper template for checking if a type T is a Function with the same
151 // function type as OtherFunctionType (except for const-ness which may differ)
152 template <typename T, typename OtherFunctionType>
153 struct IsFunction : std::false_type {};
156 typename FunctionType,
157 FunctionMoveCtor NTM,
158 size_t EmbedFunctorSize,
159 typename OtherFunctionType>
161 ::folly::Function<FunctionType, NTM, EmbedFunctorSize>,
164 typename FunctionTypeTraits<FunctionType>::NonConstFunctionType,
165 typename FunctionTypeTraits<
166 OtherFunctionType>::NonConstFunctionType> {};
168 // Helper template to check if a functor can be called with arguments of type
169 // Args..., if it returns a type convertible to R (or R is void), and also is
170 // not a folly::Function.
171 // Function objects can constructed or assigned from types for which
172 // IsCallableHelper is true_type.
173 template <typename FunctionType>
174 struct IsCallableHelper {
175 using Traits = FunctionTypeTraits<FunctionType>;
177 template <typename F>
178 static std::integral_constant<bool, Traits::template IsCallable<F>::value>
180 template <typename F>
181 static std::false_type test(...);
184 template <typename F, typename FunctionType>
186 : public std::integral_constant<
188 (!IsFunction<typename std::decay<F>::type, FunctionType>::value &&
189 decltype(IsCallableHelper<FunctionType>::template test<
190 typename std::decay<F>::type>(0))::value)> {};
192 // MaybeUnaryOrBinaryFunction: helper template class for deriving
193 // Function from std::unary_function or std::binary_function
194 template <typename R, typename ArgsTuple>
195 struct MaybeUnaryOrBinaryFunctionImpl {
196 using result_type = R;
199 template <typename R, typename Arg>
200 struct MaybeUnaryOrBinaryFunctionImpl<R, std::tuple<Arg>>
201 : public std::unary_function<Arg, R> {};
203 template <typename R, typename Arg1, typename Arg2>
204 struct MaybeUnaryOrBinaryFunctionImpl<R, std::tuple<Arg1, Arg2>>
205 : public std::binary_function<Arg1, Arg2, R> {};
207 template <typename FunctionType>
208 using MaybeUnaryOrBinaryFunction = MaybeUnaryOrBinaryFunctionImpl<
209 typename FunctionTypeTraits<FunctionType>::ResultType,
210 typename FunctionTypeTraits<FunctionType>::ArgsTuple>;
213 template <typename F, typename... Args>
214 inline auto invoke(F&& f, Args&&... args)
215 -> decltype(std::forward<F>(f)(std::forward<Args>(args)...)) {
216 return std::forward<F>(f)(std::forward<Args>(args)...);
219 template <typename M, typename C, typename... Args>
220 inline auto invoke(M(C::*d), Args&&... args)
221 -> decltype(std::mem_fn(d)(std::forward<Args>(args)...)) {
222 return std::mem_fn(d)(std::forward<Args>(args)...);
225 // Executors helper class
226 template <typename FunctionType>
230 template <class F, class SelectFunctionTag>
231 class FunctorPtrExecutor;
232 template <class F, class SelectFunctionTag>
233 class FunctorExecutor;
235 using Traits = FunctionTypeTraits<FunctionType>;
236 using NonConstFunctionExecutors =
237 Executors<typename Traits::NonConstFunctionType>;
238 using ConstFunctionExecutors = Executors<typename Traits::ConstFunctionType>;
239 using InvokeFunctionPtr = typename Traits::template InvokeFunctionPtr<
240 Executors<FunctionType>::ExecutorIf>;
243 template <typename R, typename... Args>
244 class FunctionTypeTraits<R(Args...)>::ExecutorMixin {
246 using ExecutorIf = typename Executors<R(Args...)>::ExecutorIf;
247 using InvokeFunctionPtr = typename Executors<R(Args...)>::InvokeFunctionPtr;
249 ExecutorMixin(InvokeFunctionPtr invoke_ptr) : invokePtr(invoke_ptr) {}
250 virtual ~ExecutorMixin() {}
252 template <typename F>
253 static F* selectFunctionHelper(F* f, SelectNonConstFunctionTag) {
257 template <typename F>
258 static F const* selectFunctionHelper(F* f, SelectConstFunctionTag) {
262 static R invokeEmpty(ExecutorIf*, Args&&...) {
263 throw std::bad_function_call();
266 template <typename Ex>
267 static R invokeFunctor(ExecutorIf* executor, Args&&... args) {
268 return static_cast<R>(folly::detail::function::invoke(
269 *Ex::getFunctor(executor), std::forward<Args>(args)...));
272 // invokePtr is of type
273 // ReturnType (*)(ExecutorIf*, Args&&...)
274 // and it will be set to the address of one of the static functions above
275 // (invokeEmpty or invokeFunctor), which will invoke the stored callable
276 InvokeFunctionPtr const invokePtr;
279 template <typename R, typename... Args>
280 class FunctionTypeTraits<R(Args...) const>::ExecutorMixin {
282 using ExecutorIf = typename Executors<R(Args...) const>::ExecutorIf;
283 using InvokeFunctionPtr =
284 typename Executors<R(Args...) const>::InvokeFunctionPtr;
286 ExecutorMixin(InvokeFunctionPtr invoke_ptr) : invokePtr(invoke_ptr) {}
287 virtual ~ExecutorMixin() {}
289 template <typename F>
290 static F* selectFunctionHelper(F const* f, SelectNonConstFunctionTag) {
291 return const_cast<F*>(f);
294 template <typename F>
295 static F const* selectFunctionHelper(F const* f, SelectConstFunctionTag) {
299 static R invokeEmpty(ExecutorIf const*, Args&&...) {
300 throw std::bad_function_call();
303 template <typename Ex>
304 static R invokeFunctor(ExecutorIf const* executor, Args&&... args) {
305 return static_cast<R>(folly::detail::function::invoke(
306 *Ex::getFunctor(executor), std::forward<Args>(args)...));
309 // invokePtr is of type
310 // ReturnType (*)(ExecutorIf*, Args&&...)
311 // and it will be set to the address of one of the static functions above
312 // (invokeEmpty or invokeFunctor), which will invoke the stored callable
313 InvokeFunctionPtr const invokePtr;
316 } // namespace function
317 } // namespace detail