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 class to extract properties from a function type
39 struct FunctionTypeTraits;
41 // FunctionTypeTraits default implementation - this only exists to suppress
42 // very long compiler errors when Function is tried to be instantiated
43 // with an unsuitable type
45 struct FunctionTypeTraits {
46 using SuitableForFunction = std::false_type;
48 // The following definitions are here only to suppress long and misleading
50 using ResultType = void;
51 using ArgsTuple = int;
52 using ArgsRefTuple = int;
53 using NonConstFunctionType = void;
54 using ConstFunctionType = int;
57 class InvokeOperator {};
58 class ExecutorMixin {};
61 // FunctionTypeTraits for non-const function types
62 template <typename R, typename... Args>
63 struct FunctionTypeTraits<R(Args...)> {
64 using SuitableForFunction = std::true_type;
66 using ArgsTuple = std::tuple<Args...>;
67 using ArgsRefTuple = std::tuple<Args&&...>;
68 using NonConstFunctionType = R(Args...);
69 using ConstFunctionType = R(Args...) const;
70 using IsConst = std::false_type;
71 using DefaultSelectFunctionTag = SelectNonConstFunctionTag;
74 std::is_convertible<typename std::result_of<F&(Args...)>::type, R>;
76 using QualifiedPointer = T*;
77 template <typename Obj>
78 using InvokeFunctionPtr = R (*)(Obj*, Args&&...);
80 // Function inherits from InvokeOperator<Function>. This is
81 // where Function's operator() is defined.
82 template <typename FunctionType>
83 class InvokeOperator {
86 * Invokes the stored callable via the invokePtr stored in the Executor.
88 * Throws std::bad_function_call if @c *this is empty.
90 ResultType operator()(Args... args) {
92 static_cast<FunctionType*>(this)
93 ->template access<typename FunctionType::ExecutorIf>();
94 return executor->invokePtr(executor, std::forward<Args>(args)...);
101 // FunctionTypeTraits for const function types
102 template <typename R, typename... Args>
103 struct FunctionTypeTraits<R(Args...) const> {
104 using SuitableForFunction = std::true_type;
105 using ResultType = R;
106 using ArgsTuple = std::tuple<Args...>;
107 using ArgsRefTuple = std::tuple<Args&&...>;
108 using NonConstFunctionType = R(Args...);
109 using ConstFunctionType = R(Args...) const;
110 using IsConst = std::true_type;
111 using DefaultSelectFunctionTag = SelectConstFunctionTag;
112 template <typename F>
114 std::is_convertible<typename std::result_of<F const&(Args...)>::type, R>;
115 template <typename T>
116 using QualifiedPointer = T const*;
117 template <typename Obj>
118 using InvokeFunctionPtr = R (*)(Obj const*, Args&&...);
120 // Function inherits from InvokeOperator<Function>. This is
121 // where Function's operator() is defined.
122 template <typename FunctionType>
123 class InvokeOperator {
126 * Invokes the stored callable via the invokePtr stored in the Executor.
128 * Throws std::bad_function_call if @c *this is empty.
130 ResultType operator()(Args... args) const {
132 static_cast<FunctionType const*>(this)
133 ->template access<typename FunctionType::ExecutorIf>();
134 return executor->invokePtr(executor, std::forward<Args>(args)...);
141 // Helper template for checking if a type is a Function
142 template <typename T>
143 struct IsFunction : public std::false_type {};
145 template <typename FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
146 struct IsFunction<::folly::Function<FunctionType, NTM, EmbedFunctorSize>>
147 : public std::true_type {};
149 // Helper template to check if a functor can be called with arguments of type
150 // Args..., if it returns a type convertible to R, and also is not a
152 // Function objects can constructed or assigned from types for which
153 // IsCallableHelper is true_type.
154 template <typename FunctionType>
155 struct IsCallableHelper {
156 using Traits = FunctionTypeTraits<FunctionType>;
158 template <typename F>
159 static std::integral_constant<bool, Traits::template IsCallable<F>::value>
161 template <typename F>
162 static std::false_type test(...);
165 template <typename F, typename FunctionType>
166 struct IsCallable : public std::integral_constant<
168 (!IsFunction<typename std::decay<F>::type>::value &&
169 decltype(IsCallableHelper<FunctionType>::template test<
170 typename std::decay<F>::type>(0))::value)> {};
172 // MaybeUnaryOrBinaryFunction: helper template class for deriving
173 // Function from std::unary_function or std::binary_function
174 template <typename R, typename ArgsTuple>
175 struct MaybeUnaryOrBinaryFunctionImpl {
176 using result_type = R;
179 template <typename R, typename Arg>
180 struct MaybeUnaryOrBinaryFunctionImpl<R, std::tuple<Arg>>
181 : public std::unary_function<Arg, R> {};
183 template <typename R, typename Arg1, typename Arg2>
184 struct MaybeUnaryOrBinaryFunctionImpl<R, std::tuple<Arg1, Arg2>>
185 : public std::binary_function<Arg1, Arg2, R> {};
187 template <typename FunctionType>
188 using MaybeUnaryOrBinaryFunction = MaybeUnaryOrBinaryFunctionImpl<
189 typename FunctionTypeTraits<FunctionType>::ResultType,
190 typename FunctionTypeTraits<FunctionType>::ArgsTuple>;
193 template <typename F, typename... Args>
194 inline auto invoke(F&& f, Args&&... args)
195 -> decltype(std::forward<F>(f)(std::forward<Args>(args)...)) {
196 return std::forward<F>(f)(std::forward<Args>(args)...);
199 template <typename M, typename C, typename... Args>
200 inline auto invoke(M(C::*d), Args&&... args)
201 -> decltype(std::mem_fn(d)(std::forward<Args>(args)...)) {
202 return std::mem_fn(d)(std::forward<Args>(args)...);
205 // Executors helper class
206 template <typename FunctionType>
210 template <class F, class SelectFunctionTag>
211 class FunctorPtrExecutor;
212 template <class F, class SelectFunctionTag>
213 class FunctorExecutor;
215 using Traits = FunctionTypeTraits<FunctionType>;
216 using NonConstFunctionExecutors =
217 Executors<typename Traits::NonConstFunctionType>;
218 using ConstFunctionExecutors = Executors<typename Traits::ConstFunctionType>;
219 using InvokeFunctionPtr = typename Traits::template InvokeFunctionPtr<
220 Executors<FunctionType>::ExecutorIf>;
223 template <typename R, typename... Args>
224 class FunctionTypeTraits<R(Args...)>::ExecutorMixin {
226 using ExecutorIf = typename Executors<R(Args...)>::ExecutorIf;
227 using InvokeFunctionPtr = typename Executors<R(Args...)>::InvokeFunctionPtr;
229 ExecutorMixin(InvokeFunctionPtr invoke_ptr) : invokePtr(invoke_ptr) {}
230 virtual ~ExecutorMixin() {}
232 template <typename F>
233 static F* selectFunctionHelper(F* f, SelectNonConstFunctionTag) {
237 template <typename F>
238 static F const* selectFunctionHelper(F* f, SelectConstFunctionTag) {
242 static R invokeEmpty(ExecutorIf*, Args&&...) {
243 throw std::bad_function_call();
246 template <typename Ex>
247 static R invokeFunctor(ExecutorIf* executor, Args&&... args) {
248 return folly::detail::function::invoke(
249 *Ex::getFunctor(executor), std::forward<Args>(args)...);
252 // invokePtr is of type
253 // ReturnType (*)(ExecutorIf*, Args&&...)
254 // and it will be set to the address of one of the static functions above
255 // (invokeEmpty or invokeFunctor), which will invoke the stored callable
256 InvokeFunctionPtr const invokePtr;
259 template <typename R, typename... Args>
260 class FunctionTypeTraits<R(Args...) const>::ExecutorMixin {
262 using ExecutorIf = typename Executors<R(Args...) const>::ExecutorIf;
263 using InvokeFunctionPtr =
264 typename Executors<R(Args...) const>::InvokeFunctionPtr;
266 ExecutorMixin(InvokeFunctionPtr invoke_ptr) : invokePtr(invoke_ptr) {}
267 virtual ~ExecutorMixin() {}
269 template <typename F>
270 static F* selectFunctionHelper(F const* f, SelectNonConstFunctionTag) {
271 return const_cast<F*>(f);
274 template <typename F>
275 static F const* selectFunctionHelper(F const* f, SelectConstFunctionTag) {
279 static R invokeEmpty(ExecutorIf const*, Args&&...) {
280 throw std::bad_function_call();
283 template <typename Ex>
284 static R invokeFunctor(ExecutorIf const* executor, Args&&... args) {
285 return folly::detail::function::invoke(
286 *Ex::getFunctor(executor), std::forward<Args>(args)...);
289 // invokePtr is of type
290 // ReturnType (*)(ExecutorIf*, Args&&...)
291 // and it will be set to the address of one of the static functions above
292 // (invokeEmpty or invokeFunctor), which will invoke the stored callable
293 InvokeFunctionPtr const invokePtr;
296 } // namespace function
297 } // namespace detail