folly::Function: improve conversion of return types
[folly.git] / folly / Function.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 /**
18  * @class Function
19  *
20  * @brief A polymorphic function wrapper that is not copyable and does not
21  *    require the wrapped function to be copy constructible.
22  *
23  * `folly::Function` is a polymorphic function wrapper, similar to
24  * `std::function`. The template parameters of the `folly::Function` define
25  * the parameter signature of the wrapped callable, but not the specific
26  * type of the embedded callable. E.g. a `folly::Function<int(int)>`
27  * can wrap callables that return an `int` when passed an `int`. This can be a
28  * function pointer or any class object implementing one or both of
29  *     int operator(int);
30  *     int operator(int) const;
31  * If both are defined, the non-const one takes precedence.
32  *
33  * Unlike `std::function`, a `folly::Function` can wrap objects that are not
34  * copy constructible. As a consequence of this, `folly::Function` itself
35  * is not copyable, either.
36  *
37  * Another difference is that, unlike `std::function`, `folly::Function` treats
38  * const-ness of methods correctly. While a `std::function` allows to wrap
39  * an object that only implements a non-const `operator()` and invoke
40  * a const-reference of the `std::function`, `folly::Function` requires you to
41  * declare a function type as const in order to be able to execute it on a
42  * const-reference.
43  *
44  * For example:
45  *     class Foo {
46  *      public:
47  *       void operator()() {
48  *         // mutates the Foo object
49  *       }
50  *     };
51  *
52  *     class Bar {
53  *       std::function<void(void)> foo_; // wraps a Foo object
54  *      public:
55  *       void mutateFoo() const
56  *       {
57  *         foo_();
58  *       }
59  *     };
60  * Even though `mutateFoo` is a const-method, so it can only reference `foo_`
61  * as const, it is able to call the non-const `operator()` of the Foo
62  * object that is embedded in the foo_ function.
63  *
64  * `folly::Function` will not allow you to do that. You will have to decide
65  * whether you need to invoke your wrapped callable from a const reference
66  * (like in the example above), in which case it will only wrap a
67  * `operator() const`. If your functor does not implement that,
68  * compilation will fail. If you do not require to be able to invoke the
69  * wrapped function in a const context, you can wrap any functor that
70  * implements either or both of const and non-const `operator()`.
71  *
72  * The first (and usually only specified) template parameter of
73  * `folly::Function`, the `FunctionType`, can be const-qualified. Be aware
74  * that the const is part of the function signature. It does not mean that
75  * the function type is a const type.
76  *
77  *   using FunctionType = R(Args...);
78  *   using ConstFunctionType = R(Args...) const;
79  *
80  * In this example, `FunctionType` and `ConstFunctionType` are different
81  * types. `ConstFunctionType` is not the same as `const FunctionType`.
82  * As a matter of fact, trying to use the latter should emit a compiler
83  * warning or error, because it has no defined meaning.
84  *
85  *     // This will not compile:
86  *     folly::Function<void(void) const> func = Foo();
87  *     // because Foo does not have a member function of the form:
88  *     //   void operator()() const;
89  *
90  *     // This will compile just fine:
91  *     folly::Function<void(void)> func = Foo();
92  *     // and it will wrap the existing member function:
93  *     //   void operator()();
94  *
95  * When should a const function type be used? As a matter of fact, you will
96  * probably not need to use const function types very often. See the following
97  * example:
98  *
99  *     class Bar {
100  *       folly::Function<void()> func_;
101  *       folly::Function<void() const> constFunc_;
102  *
103  *       void someMethod() {
104  *         // Can call func_.
105  *         func_();
106  *         // Can call constFunc_.
107  *         constFunc_();
108  *       }
109  *
110  *       void someConstMethod() const {
111  *         // Can call constFunc_.
112  *         constFunc_();
113  *         // However, cannot call func_ because a non-const method cannot
114  *         // be called from a const one.
115  *       }
116  *     };
117  *
118  * As you can see, whether the `folly::Function`'s function type should
119  * be declared const or not is identical to whether a corresponding method
120  * would be declared const or not.
121  *
122  * You only require a `folly::Function` to hold a const function type, if you
123  * intend to invoke it from within a const context. This is to ensure that
124  * you cannot mutate its inner state when calling in a const context.
125  *
126  * This is how the const/non-const choice relates to lambda functions:
127  *
128  *     // Non-mutable lambdas: can be stored in a non-const...
129  *     folly::Function<void(int)> print_number =
130  *       [] (int number) { std::cout << number << std::endl; };
131  *
132  *     // ...as well as in a const folly::Function
133  *     folly::Function<void(int) const> print_number_const =
134  *       [] (int number) { std::cout << number << std::endl; };
135  *
136  *     // Mutable lambda: can only be stored in a non-const folly::Function:
137  *     int number = 0;
138  *     folly::Function<void()> print_number =
139  *       [number] () mutable { std::cout << ++number << std::endl; };
140  *     // Trying to store the above mutable lambda in a
141  *     // `folly::Function<void() const>` would lead to a compiler error:
142  *     // error: no viable conversion from '(lambda at ...)' to
143  *     // 'folly::Function<void () const>'
144  *
145  * Casting between const and non-const `folly::Function`s:
146  * conversion from const to non-const signatures happens implicitly. Any
147  * function that takes a `folly::Function<R(Args...)>` can be passed
148  * a `folly::Function<R(Args...) const>` without explicit conversion.
149  * This is safe, because casting from const to non-const only entails giving
150  * up the ability to invoke the function from a const context.
151  * Casting from a non-const to a const signature is potentially dangerous,
152  * as it means that a function that may change its inner state when invoked
153  * is made possible to call from a const context. Therefore this cast does
154  * not happen implicitly. The function `folly::constCastfolly::Function` can
155  * be used to perform the cast.
156  *
157  *     // Mutable lambda: can only be stored in a non-const folly::Function:
158  *     int number = 0;
159  *     folly::Function<void()> print_number =
160  *       [number] () mutable { std::cout << ++number << std::endl; };
161  *
162  *     // const-cast to a const folly::Function:
163  *     folly::Function<void() const> print_number_const =
164  *       constCastfolly::Function(std::move(print_number));
165  *
166  * When to use const function types?
167  * Generally, only when you need them. When you use a `folly::Function` as a
168  * member of a struct or class, only use a const function signature when you
169  * need to invoke the function from const context.
170  * When passing a `folly::Function` to a function, the function should accept
171  * a non-const `folly::Function` whenever possible, i.e. when it does not
172  * need to pass on or store a const `folly::Function`. This is the least
173  * possible constraint: you can always pass a const `folly::Function` when
174  * the function accepts a non-const one.
175  *
176  * How does the const behaviour compare to `std::function`?
177  * `std::function` can wrap object with non-const invokation behaviour but
178  * exposes them as const. The equivalent behaviour can be achieved with
179  * `folly::Function` like so:
180  *
181  *     std::function<void(void)> stdfunc = someCallable;
182  *
183  *     folly::Function<void(void) const> uniqfunc = constCastfolly::Function(
184  *       folly::Function<void(void)>(someCallable)
185  *     );
186  *
187  * You need to wrap the callable first in a non-const `folly::Function` to
188  * select a non-const invoke operator (or the const one if no non-const one is
189  * present), and then move it into a const `folly::Function` using
190  * `constCastfolly::Function`.
191  * The name of `constCastfolly::Function` should warn you that something
192  * potentially dangerous is happening. As a matter of fact, using
193  * `std::function` always involves this potentially dangerous aspect, which
194  * is why it is not considered fully const-safe or even const-correct.
195  * However, in most of the cases you will not need the dangerous aspect at all.
196  * Either you do not require invokation of the function from a const context,
197  * in which case you do not need to use `constCastfolly::Function` and just
198  * use the inner `folly::Function` in the example above, i.e. just use a
199  * non-const `folly::Function`. Or, you may need invokation from const, but
200  * the callable you are wrapping does not mutate its state (e.g. it is a class
201  * object and implements `operator() const`, or it is a normal,
202  * non-mutable lambda), in which case you can wrap the callable in a const
203  * `folly::Function` directly, without using `constCastfolly::Function`.
204  * Only if you require invokation from a const context of a callable that
205  * may mutate itself when invoked you have to go through the above procedure.
206  * However, in that case what you do is potentially dangerous and requires
207  * the equivalent of a `const_cast`, hence you need to call
208  * `constCastfolly::Function`.
209  *
210  * `folly::Function` also has two additional template paremeters:
211  *   * `NTM`: if set to `folly::FunctionMoveCtor::NO_THROW`, the
212  *     `folly::Function` object is guaranteed to be nothrow move constructible.
213  *     The downside is that any function object that itself is
214  *     not nothrow move constructible cannot be stored in-place in the
215  *     `folly::Function` object and will be stored on the heap instead.
216  *   * `EmbedFunctorSize`: a number of bytes that will be reserved in the
217  *     `folly::Function` object to store callable objects in-place. If you
218  *     wrap a callable object bigger than this in a `folly::Function` object,
219  *     it will be stored on the heap and the `folly::Function` object will keep
220  *     a `std::unique_ptr` to it.
221  */
222
223 #pragma once
224
225 #include <functional>
226 #include <type_traits>
227 #include <typeinfo>
228 #include <utility>
229
230 #include <folly/ScopeGuard.h>
231 #include <folly/portability/Constexpr.h>
232
233 namespace folly {
234
235 enum class FunctionMoveCtor { NO_THROW, MAY_THROW };
236
237 template <
238     typename FunctionType,
239     FunctionMoveCtor NTM = FunctionMoveCtor::NO_THROW,
240     size_t EmbedFunctorSize = (NTM == FunctionMoveCtor::NO_THROW)
241         ? sizeof(void (*)(void))
242         : sizeof(std::function<void(void)>)>
243 class Function;
244
245 } // folly
246
247 // boring predeclarations and details
248 #include "Function-pre.h"
249
250 namespace folly {
251
252 template <typename FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
253 class Function final
254     : public detail::function::FunctionTypeTraits<FunctionType>::
255           template InvokeOperator<
256               Function<FunctionType, NTM, EmbedFunctorSize>>,
257       public detail::function::MaybeUnaryOrBinaryFunction<FunctionType> {
258  private:
259   using Traits = detail::function::FunctionTypeTraits<FunctionType>;
260   static_assert(
261       Traits::SuitableForFunction::value,
262       "Function<FunctionType>: FunctionType must be of the "
263       "form 'R(Args...)' or 'R(Args...) const'");
264
265   using ThisType = Function<FunctionType, NTM, EmbedFunctorSize>;
266   using InvokeOperator = typename Traits::template InvokeOperator<ThisType>;
267
268   static constexpr bool hasNoExceptMoveCtor() noexcept {
269     return NTM == FunctionMoveCtor::NO_THROW;
270   };
271
272  public:
273   // not copyable
274   Function(Function const&) = delete;
275   Function& operator=(Function const&) = delete;
276
277   /**
278    * Default constructor. Constructs an empty Function.
279    */
280   Function() noexcept {
281     initializeEmptyExecutor();
282   }
283
284   ~Function() {
285     destroyExecutor();
286
287     static_assert(
288         kStorageSize == sizeof(*this),
289         "There is something wrong with the size of Function");
290   }
291
292   // construct/assign from Function
293   /**
294    * Move constructor
295    */
296   Function(Function&& other) noexcept(hasNoExceptMoveCtor());
297   /**
298    * Move assignment operator
299    */
300   Function& operator=(Function&& rhs) noexcept(hasNoExceptMoveCtor());
301
302   /**
303    * Constructs a `Function` by moving from one with different template
304    * parameters with regards to const-ness, no-except-movability and internal
305    * storage size.
306    */
307   template <
308       typename OtherFunctionType,
309       FunctionMoveCtor OtherNTM,
310       size_t OtherEmbedFunctorSize>
311   Function(
312       Function<OtherFunctionType, OtherNTM, OtherEmbedFunctorSize>&& other,
313       typename std::enable_if<std::is_same<
314           typename Traits::NonConstFunctionType,
315           typename detail::function::FunctionTypeTraits<
316               OtherFunctionType>::NonConstFunctionType>::value>::type* =
317           0) noexcept(OtherNTM == FunctionMoveCtor::NO_THROW &&
318           EmbedFunctorSize >= OtherEmbedFunctorSize);
319
320   /**
321    * Moves a `Function` with different template parameters with regards
322    * to const-ness, no-except-movability and internal storage size into this
323    * one.
324    */
325   template <
326       typename RhsFunctionType,
327       FunctionMoveCtor RhsNTM,
328       size_t RhsEmbedFunctorSize>
329   Function& operator=(Function<RhsFunctionType, RhsNTM, RhsEmbedFunctorSize>&&
330                           rhs) noexcept(RhsNTM == FunctionMoveCtor::NO_THROW);
331
332   /**
333    * Constructs an empty `Function`.
334    */
335   /* implicit */ Function(std::nullptr_t) noexcept : Function() {}
336
337   /**
338    * Clears this `Function`.
339    */
340   Function& operator=(std::nullptr_t) noexcept {
341     destroyExecutor();
342     initializeEmptyExecutor();
343     return *this;
344   }
345
346   /**
347    * Constructs a new `Function` from any callable object. This
348    * handles function pointers, pointers to static member functions,
349    * `std::reference_wrapper` objects, `std::function` objects, and arbitrary
350    * objects that implement `operator()` if the parameter signature
351    * matches (i.e. it returns R when called with Args...).
352    * For a `Function` with a const function type, the object must be
353    * callable from a const-reference, i.e. implement `operator() const`.
354    * For a `Function` with a non-const function type, the object will
355    * be called from a non-const reference, which means that it will execute
356    * a non-const `operator()` if it is defined, and falls back to
357    * `operator() const` otherwise
358    */
359   template <typename F>
360   /* implicit */ Function(
361       F&& f,
362       typename std::enable_if<
363           detail::function::IsCallable<F, FunctionType>::value>::type* =
364           0) noexcept(noexcept(typename std::decay<F>::
365                                    type(std::forward<F>(f)))) {
366     createExecutor(std::forward<F>(f));
367   }
368
369   /**
370    * Assigns a callable object to this `Function`.
371    */
372   template <typename F>
373   typename std::enable_if<
374       detail::function::IsCallable<F, FunctionType>::value,
375       Function&>::type
376   operator=(F&& f) noexcept(
377       noexcept(typename std::decay<F>::type(std::forward<F>(f)))) {
378     destroyExecutor();
379     SCOPE_FAIL {
380       initializeEmptyExecutor();
381     };
382     createExecutor(std::forward<F>(f));
383     return *this;
384   }
385
386   /**
387    * Exchanges the callable objects of `*this` and `other`. `other` can be
388    * a Function with different settings with regard to
389    * no-except-movability and internal storage size, but must match
390    * `*this` with regards to return type and argument types.
391    */
392   template <FunctionMoveCtor OtherNTM, size_t OtherEmbedFunctorSize>
393   void
394   swap(Function<FunctionType, OtherNTM, OtherEmbedFunctorSize>& o) noexcept(
395       hasNoExceptMoveCtor() && OtherNTM == FunctionMoveCtor::NO_THROW);
396
397   /**
398    * Returns `true` if this `Function` contains a callable, i.e. is
399    * non-empty.
400    */
401   explicit operator bool() const noexcept;
402
403   /**
404    * Returns `true` if this `Function` stores the callable on the
405    * heap. If `false` is returned, there has been no additional memory
406    * allocation and the callable is stored inside the `Function`
407    * object itself.
408    */
409   bool hasAllocatedMemory() const noexcept;
410
411   /**
412    * Returns the `type_info` (as returned by `typeid`) of the callable stored
413    * in this `Function`. Returns `typeid(void)` if empty.
414    */
415   std::type_info const& target_type() const noexcept;
416
417   /**
418    * Returns a pointer to the stored callable if its type matches `T`, and
419    * `nullptr` otherwise.
420    */
421   template <typename T>
422   T* target() noexcept;
423
424   /**
425    * Returns a const-pointer to the stored callable if its type matches `T`,
426    * and `nullptr` otherwise.
427    */
428   template <typename T>
429   const T* target() const noexcept;
430
431   /**
432    * Move out this `Function` into one with a const function type.
433    *
434    * This is a potentially dangerous operation, equivalent to a `const_cast`.
435    * This converts a `Function` with a non-const function type, i.e.
436    * one that can only be called when in the form of a non-const reference,
437    * into one that can be called in a const context. Use at your own risk!
438    */
439   Function<typename Traits::ConstFunctionType, NTM, EmbedFunctorSize>
440       castToConstFunction() && noexcept(hasNoExceptMoveCtor());
441
442   using SignatureType = FunctionType;
443   using ResultType = typename Traits::ResultType;
444   using ArgsTuple = typename Traits::ArgsTuple;
445
446  private:
447   template <class, FunctionMoveCtor, size_t>
448   friend class Function;
449
450   friend struct detail::function::FunctionTypeTraits<FunctionType>;
451
452   using ExecutorIf =
453       typename detail::function::Executors<FunctionType>::ExecutorIf;
454   using EmptyExecutor =
455       typename detail::function::Executors<FunctionType>::EmptyExecutor;
456   template <typename F, typename SelectFunctionTag>
457   using FunctorPtrExecutor = typename detail::function::Executors<
458       FunctionType>::template FunctorPtrExecutor<F, SelectFunctionTag>;
459   template <typename F, typename SelectFunctionTag>
460   using FunctorExecutor = typename detail::function::Executors<
461       FunctionType>::template FunctorExecutor<F, SelectFunctionTag>;
462
463   template <typename T>
464   T const* access() const;
465
466   template <typename T>
467   T* access();
468
469   void initializeEmptyExecutor() noexcept;
470
471   template <typename F>
472   void createExecutor(F&& f) noexcept(
473       noexcept(typename std::decay<F>::type(std::forward<F>(f))));
474
475   void destroyExecutor() noexcept;
476
477   struct MinStorageSize;
478
479   typename std::aligned_storage<MinStorageSize::value>::type data_;
480   static constexpr size_t kStorageSize = sizeof(data_);
481 };
482
483 // operator==
484 template <typename FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
485 inline bool operator==(
486     Function<FunctionType, NTM, EmbedFunctorSize> const& f,
487     std::nullptr_t) noexcept {
488   return !f;
489 }
490
491 template <typename FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
492 inline bool operator==(
493     std::nullptr_t,
494     Function<FunctionType, NTM, EmbedFunctorSize> const& f) noexcept {
495   return !f;
496 }
497
498 template <typename FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
499 inline bool operator!=(
500     Function<FunctionType, NTM, EmbedFunctorSize> const& f,
501     std::nullptr_t) noexcept {
502   return !!f;
503 }
504
505 template <typename FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
506 inline bool operator!=(
507     std::nullptr_t,
508     Function<FunctionType, NTM, EmbedFunctorSize> const& f) noexcept {
509   return !!f;
510 }
511
512 /**
513  * Cast a `Function` into one with a const function type.
514  *
515  * This is a potentially dangerous operation, equivalent to a `const_cast`.
516  * This converts a `Function` with a non-const function type, i.e.
517  * one that can only be called when in the form of a non-const reference,
518  * into one that can be called in a const context. Use at your own risk!
519  */
520 template <typename FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
521 Function<
522     typename detail::function::FunctionTypeTraits<
523         FunctionType>::ConstFunctionType,
524     NTM,
525     EmbedFunctorSize>
526 constCastFunction(Function<FunctionType, NTM, EmbedFunctorSize>&&
527                       from) noexcept(NTM == FunctionMoveCtor::NO_THROW) {
528   return std::move(from).castToConstFunction();
529 }
530
531 } // folly
532
533 namespace std {
534 template <typename FunctionType, bool NOM1, bool NOM2, size_t S1, size_t S2>
535 void swap(
536     ::folly::Function<FunctionType, NOM1, S1>& lhs,
537     ::folly::Function<FunctionType, NOM2, S2>& rhs) {
538   lhs.swap(rhs);
539 }
540 } // std
541
542 #include "Function-inl.h"