Introducing folly::Function
[folly.git] / folly / Function-pre.h
1 /*
2  * Copyright 2016 Facebook, Inc.
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #pragma once
18
19 // included by Function.h, do not include directly.
20
21 #include <memory>
22
23 namespace folly {
24
25 namespace detail {
26 namespace function {
27
28 struct SelectConstFunctionTag {
29   template <typename T>
30   using QualifiedPointer = T const*;
31 };
32 struct SelectNonConstFunctionTag {
33   template <typename T>
34   using QualifiedPointer = T*;
35 };
36
37 // Helper class to extract properties from a function type
38 template <typename T>
39 struct FunctionTypeTraits;
40
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
44 template <typename T>
45 struct FunctionTypeTraits {
46   using SuitableForFunction = std::false_type;
47
48   // The following definitions are here only to suppress long and misleading
49   // compiler errors.
50   using ResultType = void;
51   using ArgsTuple = int;
52   using ArgsRefTuple = int;
53   using NonConstFunctionType = void;
54   using ConstFunctionType = int;
55
56   template <typename X>
57   class InvokeOperator {};
58   class ExecutorMixin {};
59 };
60
61 // FunctionTypeTraits for non-const function types
62 template <typename R, typename... Args>
63 struct FunctionTypeTraits<R(Args...)> {
64   using SuitableForFunction = std::true_type;
65   using ResultType = R;
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;
72   template <typename F>
73   using IsCallable =
74       std::is_convertible<typename std::result_of<F&(Args...)>::type, R>;
75   template <typename T>
76   using QualifiedPointer = T*;
77   template <typename Obj>
78   using InvokeFunctionPtr = R (*)(Obj*, Args&&...);
79
80   // Function inherits from InvokeOperator<Function>. This is
81   // where Function's operator() is defined.
82   template <typename FunctionType>
83   class InvokeOperator {
84    public:
85     /**
86      * Invokes the stored callable via the invokePtr stored in the Executor.
87      *
88      * Throws std::bad_function_call if @c *this is empty.
89      */
90     ResultType operator()(Args... args) {
91       auto executor =
92           static_cast<FunctionType*>(this)
93               ->template access<typename FunctionType::ExecutorIf>();
94       return executor->invokePtr(executor, std::forward<Args>(args)...);
95     }
96   };
97
98   class ExecutorMixin;
99 };
100
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>
113   using IsCallable =
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&&...);
119
120   // Function inherits from InvokeOperator<Function>. This is
121   // where Function's operator() is defined.
122   template <typename FunctionType>
123   class InvokeOperator {
124    public:
125     /**
126      * Invokes the stored callable via the invokePtr stored in the Executor.
127      *
128      * Throws std::bad_function_call if @c *this is empty.
129      */
130     ResultType operator()(Args... args) const {
131       auto executor =
132           static_cast<FunctionType const*>(this)
133               ->template access<typename FunctionType::ExecutorIf>();
134       return executor->invokePtr(executor, std::forward<Args>(args)...);
135     }
136   };
137
138   class ExecutorMixin;
139 };
140
141 // Helper template for checking if a type is a Function
142 template <typename T>
143 struct IsFunction : public std::false_type {};
144
145 template <typename FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
146 struct IsFunction<::folly::Function<FunctionType, NTM, EmbedFunctorSize>>
147     : public std::true_type {};
148
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
151 // Function.
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>;
157
158   template <typename F>
159   static std::integral_constant<bool, Traits::template IsCallable<F>::value>
160   test(int);
161   template <typename F>
162   static std::false_type test(...);
163 };
164
165 template <typename F, typename FunctionType>
166 struct IsCallable : public std::integral_constant<
167                         bool,
168                         (!IsFunction<typename std::decay<F>::type>::value &&
169                          decltype(IsCallableHelper<FunctionType>::template test<
170                                   typename std::decay<F>::type>(0))::value)> {};
171
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;
177 };
178
179 template <typename R, typename Arg>
180 struct MaybeUnaryOrBinaryFunctionImpl<R, std::tuple<Arg>>
181     : public std::unary_function<Arg, R> {};
182
183 template <typename R, typename Arg1, typename Arg2>
184 struct MaybeUnaryOrBinaryFunctionImpl<R, std::tuple<Arg1, Arg2>>
185     : public std::binary_function<Arg1, Arg2, R> {};
186
187 template <typename FunctionType>
188 using MaybeUnaryOrBinaryFunction = MaybeUnaryOrBinaryFunctionImpl<
189     typename FunctionTypeTraits<FunctionType>::ResultType,
190     typename FunctionTypeTraits<FunctionType>::ArgsTuple>;
191
192 // Invoke helper
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)...);
197 }
198
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)...);
203 }
204
205 // Executors helper class
206 template <typename FunctionType>
207 struct Executors {
208   class ExecutorIf;
209   class EmptyExecutor;
210   template <class F, class SelectFunctionTag>
211   class FunctorPtrExecutor;
212   template <class F, class SelectFunctionTag>
213   class FunctorExecutor;
214
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>;
221 };
222
223 template <typename R, typename... Args>
224 class FunctionTypeTraits<R(Args...)>::ExecutorMixin {
225  public:
226   using ExecutorIf = typename Executors<R(Args...)>::ExecutorIf;
227   using InvokeFunctionPtr = typename Executors<R(Args...)>::InvokeFunctionPtr;
228
229   ExecutorMixin(InvokeFunctionPtr invoke_ptr) : invokePtr(invoke_ptr) {}
230   virtual ~ExecutorMixin() {}
231
232   template <typename F>
233   static F* selectFunctionHelper(F* f, SelectNonConstFunctionTag) {
234     return f;
235   }
236
237   template <typename F>
238   static F const* selectFunctionHelper(F* f, SelectConstFunctionTag) {
239     return f;
240   }
241
242   static R invokeEmpty(ExecutorIf*, Args&&...) {
243     throw std::bad_function_call();
244   }
245
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)...);
250   }
251
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;
257 };
258
259 template <typename R, typename... Args>
260 class FunctionTypeTraits<R(Args...) const>::ExecutorMixin {
261  public:
262   using ExecutorIf = typename Executors<R(Args...) const>::ExecutorIf;
263   using InvokeFunctionPtr =
264       typename Executors<R(Args...) const>::InvokeFunctionPtr;
265
266   ExecutorMixin(InvokeFunctionPtr invoke_ptr) : invokePtr(invoke_ptr) {}
267   virtual ~ExecutorMixin() {}
268
269   template <typename F>
270   static F* selectFunctionHelper(F const* f, SelectNonConstFunctionTag) {
271     return const_cast<F*>(f);
272   }
273
274   template <typename F>
275   static F const* selectFunctionHelper(F const* f, SelectConstFunctionTag) {
276     return f;
277   }
278
279   static R invokeEmpty(ExecutorIf const*, Args&&...) {
280     throw std::bad_function_call();
281   }
282
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)...);
287   }
288
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;
294 };
295
296 } // namespace function
297 } // namespace detail
298 } // namespace folly