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.
20 * @brief A polymorphic function wrapper that is not copyable and does not
21 * require the wrapped function to be copy constructible.
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
31 * int operator(int) const;
33 * If both are defined, the non-const one takes precedence.
35 * Unlike `std::function`, a `folly::Function` can wrap objects that are not
36 * copy constructible. As a consequence of this, `folly::Function` itself
37 * is not copyable, either.
39 * Another difference is that, unlike `std::function`, `folly::Function` treats
40 * const-ness of methods correctly. While a `std::function` allows to wrap
41 * an object that only implements a non-const `operator()` and invoke
42 * a const-reference of the `std::function`, `folly::Function` requires you to
43 * declare a function type as const in order to be able to execute it on a
51 * // mutates the Foo object
56 * std::function<void(void)> foo_; // wraps a Foo object
58 * void mutateFoo() const
64 * Even though `mutateFoo` is a const-method, so it can only reference `foo_`
65 * as const, it is able to call the non-const `operator()` of the Foo
66 * object that is embedded in the foo_ function.
68 * `folly::Function` will not allow you to do that. You will have to decide
69 * whether you need to invoke your wrapped callable from a const reference
70 * (like in the example above), in which case it will only wrap a
71 * `operator() const`. If your functor does not implement that,
72 * compilation will fail. If you do not require to be able to invoke the
73 * wrapped function in a const context, you can wrap any functor that
74 * implements either or both of const and non-const `operator()`.
76 * The first (and usually only specified) template parameter of
77 * `folly::Function`, the `FunctionType`, can be const-qualified. Be aware
78 * that the const is part of the function signature. It does not mean that
79 * the function type is a const type.
81 * using FunctionType = R(Args...);
82 * using ConstFunctionType = R(Args...) const;
84 * In this example, `FunctionType` and `ConstFunctionType` are different
85 * types. `ConstFunctionType` is not the same as `const FunctionType`.
86 * As a matter of fact, trying to use the latter should emit a compiler
87 * warning or error, because it has no defined meaning.
89 * // This will not compile:
90 * folly::Function<void(void) const> func = Foo();
91 * // because Foo does not have a member function of the form:
92 * // void operator()() const;
94 * // This will compile just fine:
95 * folly::Function<void(void)> func = Foo();
96 * // and it will wrap the existing member function:
97 * // void operator()();
99 * When should a const function type be used? As a matter of fact, you will
100 * probably not need to use const function types very often. See the following
104 * folly::Function<void()> func_;
105 * folly::Function<void() const> constFunc_;
107 * void someMethod() {
110 * // Can call constFunc_.
114 * void someConstMethod() const {
115 * // Can call constFunc_.
117 * // However, cannot call func_ because a non-const method cannot
118 * // be called from a const one.
122 * As you can see, whether the `folly::Function`'s function type should
123 * be declared const or not is identical to whether a corresponding method
124 * would be declared const or not.
126 * You only require a `folly::Function` to hold a const function type, if you
127 * intend to invoke it from within a const context. This is to ensure that
128 * you cannot mutate its inner state when calling in a const context.
130 * This is how the const/non-const choice relates to lambda functions:
132 * // Non-mutable lambdas: can be stored in a non-const...
133 * folly::Function<void(int)> print_number =
134 * [] (int number) { std::cout << number << std::endl; };
136 * // ...as well as in a const folly::Function
137 * folly::Function<void(int) const> print_number_const =
138 * [] (int number) { std::cout << number << std::endl; };
140 * // Mutable lambda: can only be stored in a non-const folly::Function:
142 * folly::Function<void()> print_number =
143 * [number] () mutable { std::cout << ++number << std::endl; };
144 * // Trying to store the above mutable lambda in a
145 * // `folly::Function<void() const>` would lead to a compiler error:
146 * // error: no viable conversion from '(lambda at ...)' to
147 * // 'folly::Function<void () const>'
149 * Casting between const and non-const `folly::Function`s:
150 * conversion from const to non-const signatures happens implicitly. Any
151 * function that takes a `folly::Function<R(Args...)>` can be passed
152 * a `folly::Function<R(Args...) const>` without explicit conversion.
153 * This is safe, because casting from const to non-const only entails giving
154 * up the ability to invoke the function from a const context.
155 * Casting from a non-const to a const signature is potentially dangerous,
156 * as it means that a function that may change its inner state when invoked
157 * is made possible to call from a const context. Therefore this cast does
158 * not happen implicitly. The function `folly::constCastFunction` can
159 * be used to perform the cast.
161 * // Mutable lambda: can only be stored in a non-const folly::Function:
163 * folly::Function<void()> print_number =
164 * [number] () mutable { std::cout << ++number << std::endl; };
166 * // const-cast to a const folly::Function:
167 * folly::Function<void() const> print_number_const =
168 * constCastFunction(std::move(print_number));
170 * When to use const function types?
171 * Generally, only when you need them. When you use a `folly::Function` as a
172 * member of a struct or class, only use a const function signature when you
173 * need to invoke the function from const context.
174 * When passing a `folly::Function` to a function, the function should accept
175 * a non-const `folly::Function` whenever possible, i.e. when it does not
176 * need to pass on or store a const `folly::Function`. This is the least
177 * possible constraint: you can always pass a const `folly::Function` when
178 * the function accepts a non-const one.
180 * How does the const behaviour compare to `std::function`?
181 * `std::function` can wrap object with non-const invokation behaviour but
182 * exposes them as const. The equivalent behaviour can be achieved with
183 * `folly::Function` like so:
185 * std::function<void(void)> stdfunc = someCallable;
187 * folly::Function<void(void) const> uniqfunc = constCastFunction(
188 * folly::Function<void(void)>(someCallable)
191 * You need to wrap the callable first in a non-const `folly::Function` to
192 * select a non-const invoke operator (or the const one if no non-const one is
193 * present), and then move it into a const `folly::Function` using
194 * `constCastFunction`.
195 * The name of `constCastFunction` should warn you that something
196 * potentially dangerous is happening. As a matter of fact, using
197 * `std::function` always involves this potentially dangerous aspect, which
198 * is why it is not considered fully const-safe or even const-correct.
199 * However, in most of the cases you will not need the dangerous aspect at all.
200 * Either you do not require invokation of the function from a const context,
201 * in which case you do not need to use `constCastFunction` and just
202 * use the inner `folly::Function` in the example above, i.e. just use a
203 * non-const `folly::Function`. Or, you may need invokation from const, but
204 * the callable you are wrapping does not mutate its state (e.g. it is a class
205 * object and implements `operator() const`, or it is a normal,
206 * non-mutable lambda), in which case you can wrap the callable in a const
207 * `folly::Function` directly, without using `constCastFunction`.
208 * Only if you require invokation from a const context of a callable that
209 * may mutate itself when invoked you have to go through the above procedure.
210 * However, in that case what you do is potentially dangerous and requires
211 * the equivalent of a `const_cast`, hence you need to call
212 * `constCastFunction`.
214 * `folly::Function` also has two additional template paremeters:
215 * * `NTM`: if set to `folly::FunctionMoveCtor::NO_THROW`, the
216 * `folly::Function` object is guaranteed to be nothrow move constructible.
217 * The downside is that any function object that itself is
218 * not nothrow move constructible cannot be stored in-place in the
219 * `folly::Function` object and will be stored on the heap instead.
220 * * `EmbedFunctorSize`: a number of bytes that will be reserved in the
221 * `folly::Function` object to store callable objects in-place. If you
222 * wrap a callable object bigger than this in a `folly::Function` object,
223 * it will be stored on the heap and the `folly::Function` object will keep
224 * a `std::unique_ptr` to it.
229 #include <functional>
230 #include <type_traits>
234 #include <folly/ScopeGuard.h>
235 #include <folly/portability/Constexpr.h>
239 enum class FunctionMoveCtor { NO_THROW, MAY_THROW };
242 typename FunctionType,
243 FunctionMoveCtor NTM = FunctionMoveCtor::NO_THROW,
244 size_t EmbedFunctorSize = (NTM == FunctionMoveCtor::NO_THROW)
245 ? sizeof(void (*)(void))
246 : sizeof(std::function<void(void)>)>
251 // boring predeclarations and details
252 #include "Function-pre.h"
256 template <typename FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
258 : public detail::function::FunctionTypeTraits<FunctionType>::
259 template InvokeOperator<
260 Function<FunctionType, NTM, EmbedFunctorSize>>,
261 public detail::function::MaybeUnaryOrBinaryFunction<FunctionType> {
263 using Traits = detail::function::FunctionTypeTraits<FunctionType>;
265 Traits::SuitableForFunction::value,
266 "Function<FunctionType>: FunctionType must be of the "
267 "form 'R(Args...)' or 'R(Args...) const'");
269 using ThisType = Function<FunctionType, NTM, EmbedFunctorSize>;
270 using InvokeOperator = typename Traits::template InvokeOperator<ThisType>;
272 static constexpr bool hasNoExceptMoveCtor() noexcept {
273 return NTM == FunctionMoveCtor::NO_THROW;
278 Function(Function const&) = delete;
279 Function& operator=(Function const&) = delete;
282 * Default constructor. Constructs an empty Function.
284 Function() noexcept {
285 initializeEmptyExecutor();
292 kStorageSize == sizeof(*this),
293 "There is something wrong with the size of Function");
296 // construct/assign from Function
300 Function(Function&& other) noexcept(hasNoExceptMoveCtor());
302 * Move assignment operator
304 Function& operator=(Function&& rhs) noexcept(hasNoExceptMoveCtor());
307 * Construct a std::function by moving in the contents of this `Function`.
308 * Note that the returned std::function will share its state (i.e. captured
309 * data) across all copies you make of it, so be very careful when copying.
311 std::function<typename Traits::NonConstFunctionType> asStdFunction() && {
312 return detail::function::InvokeFromSharedPtr<Function>(
313 std::make_shared<Function>(std::move(*this)));
317 * Constructs a `Function` by moving from one with different template
318 * parameters with regards to const-ness, no-except-movability and internal
322 typename OtherFunctionType,
323 FunctionMoveCtor OtherNTM,
324 size_t OtherEmbedFunctorSize>
326 Function<OtherFunctionType, OtherNTM, OtherEmbedFunctorSize>&& other,
327 typename std::enable_if<std::is_same<
328 typename Traits::NonConstFunctionType,
329 typename detail::function::FunctionTypeTraits<
330 OtherFunctionType>::NonConstFunctionType>::value>::type* =
331 0) noexcept(OtherNTM == FunctionMoveCtor::NO_THROW &&
332 EmbedFunctorSize >= OtherEmbedFunctorSize);
335 * Moves a `Function` with different template parameters with regards
336 * to const-ness, no-except-movability and internal storage size into this
340 typename RhsFunctionType,
341 FunctionMoveCtor RhsNTM,
342 size_t RhsEmbedFunctorSize>
343 Function& operator=(Function<RhsFunctionType, RhsNTM, RhsEmbedFunctorSize>&&
344 rhs) noexcept(RhsNTM == FunctionMoveCtor::NO_THROW);
347 * Constructs an empty `Function`.
349 /* implicit */ Function(std::nullptr_t) noexcept : Function() {}
352 * Clears this `Function`.
354 Function& operator=(std::nullptr_t) noexcept {
356 initializeEmptyExecutor();
361 * Constructs a new `Function` from any callable object. This
362 * handles function pointers, pointers to static member functions,
363 * `std::reference_wrapper` objects, `std::function` objects, and arbitrary
364 * objects that implement `operator()` if the parameter signature
365 * matches (i.e. it returns R when called with Args...).
366 * For a `Function` with a const function type, the object must be
367 * callable from a const-reference, i.e. implement `operator() const`.
368 * For a `Function` with a non-const function type, the object will
369 * be called from a non-const reference, which means that it will execute
370 * a non-const `operator()` if it is defined, and falls back to
371 * `operator() const` otherwise
373 template <typename F>
374 /* implicit */ Function(
376 typename std::enable_if<
377 detail::function::IsCallable<F, FunctionType>::value>::type* =
378 0) noexcept(noexcept(typename std::decay<F>::
379 type(std::forward<F>(f)))) {
380 createExecutor(std::forward<F>(f));
384 * Assigns a callable object to this `Function`.
386 template <typename F>
387 typename std::enable_if<
388 detail::function::IsCallable<F, FunctionType>::value,
390 operator=(F&& f) noexcept(
391 noexcept(typename std::decay<F>::type(std::forward<F>(f)))) {
394 initializeEmptyExecutor();
396 createExecutor(std::forward<F>(f));
401 * Exchanges the callable objects of `*this` and `other`. `other` can be
402 * a Function with different settings with regard to
403 * no-except-movability and internal storage size, but must match
404 * `*this` with regards to return type and argument types.
406 template <FunctionMoveCtor OtherNTM, size_t OtherEmbedFunctorSize>
408 swap(Function<FunctionType, OtherNTM, OtherEmbedFunctorSize>& o) noexcept(
409 hasNoExceptMoveCtor() && OtherNTM == FunctionMoveCtor::NO_THROW);
412 * Returns `true` if this `Function` contains a callable, i.e. is
415 explicit operator bool() const noexcept;
418 * Returns `true` if this `Function` stores the callable on the
419 * heap. If `false` is returned, there has been no additional memory
420 * allocation and the callable is stored inside the `Function`
423 bool hasAllocatedMemory() const noexcept;
426 * Returns the `type_info` (as returned by `typeid`) of the callable stored
427 * in this `Function`. Returns `typeid(void)` if empty.
429 std::type_info const& target_type() const noexcept;
432 * Returns a pointer to the stored callable if its type matches `T`, and
433 * `nullptr` otherwise.
435 template <typename T>
436 T* target() noexcept;
439 * Returns a const-pointer to the stored callable if its type matches `T`,
440 * and `nullptr` otherwise.
442 template <typename T>
443 const T* target() const noexcept;
446 * Move out this `Function` into one with a const function type.
448 * This is a potentially dangerous operation, equivalent to a `const_cast`.
449 * This converts a `Function` with a non-const function type, i.e.
450 * one that can only be called when in the form of a non-const reference,
451 * into one that can be called in a const context. Use at your own risk!
453 Function<typename Traits::ConstFunctionType, NTM, EmbedFunctorSize>
454 castToConstFunction() && noexcept(hasNoExceptMoveCtor());
456 using SignatureType = FunctionType;
457 using ResultType = typename Traits::ResultType;
458 using ArgsTuple = typename Traits::ArgsTuple;
461 template <class, FunctionMoveCtor, size_t>
462 friend class Function;
464 friend struct detail::function::FunctionTypeTraits<FunctionType>;
467 typename detail::function::Executors<FunctionType>::ExecutorIf;
468 using EmptyExecutor =
469 typename detail::function::Executors<FunctionType>::EmptyExecutor;
470 template <typename F, typename SelectFunctionTag>
471 using FunctorPtrExecutor = typename detail::function::Executors<
472 FunctionType>::template FunctorPtrExecutor<F, SelectFunctionTag>;
473 template <typename F, typename SelectFunctionTag>
474 using FunctorExecutor = typename detail::function::Executors<
475 FunctionType>::template FunctorExecutor<F, SelectFunctionTag>;
477 template <typename T>
478 T const* access() const;
480 template <typename T>
483 void initializeEmptyExecutor() noexcept;
485 template <typename F>
486 void createExecutor(F&& f) noexcept(
487 noexcept(typename std::decay<F>::type(std::forward<F>(f))));
489 void destroyExecutor() noexcept;
491 struct MinStorageSize;
493 typename std::aligned_storage<MinStorageSize::value>::type data_;
494 static constexpr size_t kStorageSize = sizeof(data_);
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 {
505 template <typename FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
506 inline bool operator==(
508 Function<FunctionType, NTM, EmbedFunctorSize> const& f) noexcept {
512 template <typename FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
513 inline bool operator!=(
514 Function<FunctionType, NTM, EmbedFunctorSize> const& f,
515 std::nullptr_t) noexcept {
519 template <typename FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
520 inline bool operator!=(
522 Function<FunctionType, NTM, EmbedFunctorSize> const& f) noexcept {
527 * Cast a `Function` into one with a const function type.
529 * This is a potentially dangerous operation, equivalent to a `const_cast`.
530 * This converts a `Function` with a non-const function type, i.e.
531 * one that can only be called when in the form of a non-const reference,
532 * into one that can be called in a const context. Use at your own risk!
534 template <typename FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
536 typename detail::function::FunctionTypeTraits<
537 FunctionType>::ConstFunctionType,
540 constCastFunction(Function<FunctionType, NTM, EmbedFunctorSize>&&
541 from) noexcept(NTM == FunctionMoveCtor::NO_THROW) {
542 return std::move(from).castToConstFunction();
545 template <typename FunctionType, FunctionMoveCtor NOM, size_t S>
547 Function<FunctionType, NOM, S>& lhs,
548 Function<FunctionType, NOM, S>& rhs) noexcept(noexcept(lhs.swap(rhs))) {
553 typename FunctionType,
554 FunctionMoveCtor NOM1,
555 FunctionMoveCtor NOM2,
559 Function<FunctionType, NOM1, S1>& lhs,
560 Function<FunctionType, NOM2, S2>& rhs) noexcept(noexcept(lhs.swap(rhs))) {
566 #include "Function-inl.h"