1 /* SPDX-FileCopyrightText: 2023 Blender Authors
3 * SPDX-License-Identifier: GPL-2.0-or-later */
10 #include "BLI_build_config.h"
11 #include "BLI_utildefines.h"
16 * A `FunctionRef<Signature>` is a non-owning reference to some callable object with a specific
17 * signature. It can be used to pass some callback to another function.
19 * A `FunctionRef` is small and cheap to copy. Therefore it should generally be passed by value.
22 * `FunctionRef<void()>` - A function without parameters and void return type.
23 * `FunctionRef<int(float)>` - A function with a float parameter and an int return value.
24 * `FunctionRef<int(int, int)>` - A function with two int parameters and an int return value.
26 * There are multiple ways to achieve that, so here is a comparison of the different approaches:
27 * 1. Pass function pointer and user data (as void *) separately:
28 * - The only method that is compatible with C interfaces.
29 * - Is cumbersome to work with in many cases, because one has to keep track of two parameters.
30 * - Not type safe at all, because of the void pointer.
31 * - It requires workarounds when one wants to pass a lambda into a function.
32 * 2. Using `std::function`:
33 * - It works well with most callables and is easy to use.
34 * - Owns the callable, so it can be returned from a function more safely than other methods.
35 * - Requires that the callable is copyable.
36 * - Requires an allocation when the callable is too large (typically > 16 bytes).
37 * 3. Using a template for the callable type:
38 * - Most efficient solution at runtime, because compiler knows the exact callable at the place
40 * - Works well with all callables.
41 * - Requires the function to be in a header file.
42 * - It's difficult to constrain the signature of the function.
43 * 4. Using `FunctionRef`:
44 * - Second most efficient solution at runtime.
45 * - It's easy to constrain the signature of the callable.
46 * - Does not require the function to be in a header file.
47 * - Works well with all callables.
48 * - It's a non-owning reference, so it *cannot* be stored safely in general.
50 * The fact that this is a non-owning reference makes `FunctionRef` very well suited for some use
51 * cases, but one has to be a bit more careful when using it to make sure that the referenced
52 * callable is not destructed.
54 * In particular, one must not construct a `FunctionRef` variable from a lambda directly as shown
55 * below. This is because the lambda object goes out of scope after the line finished executing and
56 * will be destructed. Calling the reference afterwards invokes undefined behavior.
59 * FunctionRef<int()> ref = []() { return 0; };
61 * auto f = []() { return 0; };
62 * FuntionRef<int()> ref = f;
64 * It is fine to pass a lambda directly to a function:
66 * void some_function(FunctionRef<int()> f);
67 * some_function([]() { return 0; });
72 template<typename Function
> class FunctionRef
;
74 template<typename Ret
, typename
... Params
> class FunctionRef
<Ret(Params
...)> {
77 * A function pointer that knows how to call the referenced callable with the given parameters.
79 Ret (*callback_
)(intptr_t callable
, Params
... params
) = nullptr;
82 * A pointer to the referenced callable object. This can be a C function, a lambda object or any
85 * The value does not need to be initialized because it is not used unless `callback_` is set as
86 * well, in which case it will be initialized as well.
88 * Use `intptr_t` to avoid warnings when casting to function pointers.
92 template<typename Callable
> static Ret
callback_fn(intptr_t callable
, Params
... params
)
94 return (*reinterpret_cast<Callable
*>(callable
))(std::forward
<Params
>(params
)...);
98 FunctionRef() = default;
100 FunctionRef(std::nullptr_t
) {}
103 * A `FunctionRef` itself is a callable as well. However, we don't want that this
104 * constructor is called when `Callable` is a `FunctionRef`. If we would allow this, it
105 * would be easy to accidentally create a `FunctionRef` that internally calls another
106 * `FunctionRef`. Usually, when assigning a `FunctionRef` to another, we want that both
107 * contain a reference to the same underlying callable afterwards.
109 * It is still possible to reference another `FunctionRef` by first wrapping it in
112 template<typename Callable
,
114 !std::is_same_v
<std::remove_cv_t
<std::remove_reference_t
<Callable
>>, FunctionRef
>)),
115 BLI_ENABLE_IF((std::is_invocable_r_v
<Ret
, Callable
, Params
...>))>
116 FunctionRef(Callable
&&callable
)
117 : callback_(callback_fn
<typename
std::remove_reference_t
<Callable
>>),
118 callable_(intptr_t(&callable
))
120 if constexpr (std::is_constructible_v
<bool, Callable
>) {
121 /* For some types, the compiler can be sure that the callable is always truthy. Good!
122 * Then the entire check can be optimized away. */
123 #if COMPILER_CLANG || COMPILER_GCC
124 # pragma GCC diagnostic push
125 # pragma GCC diagnostic ignored "-Waddress"
127 # pragma GCC diagnostic ignored "-Wnonnull-compare"
130 /* Make sure the #FunctionRef is falsy if the callback is falsy.
131 * That can happen when passing in null or empty std::function. */
132 const bool is_truthy
= bool(callable
);
137 #if COMPILER_CLANG || COMPILER_GCC
138 # pragma GCC diagnostic pop
144 * Call the referenced function and forward all parameters to it.
146 * This invokes undefined behavior if the `FunctionRef` does not reference a function currently.
148 Ret
operator()(Params
... params
) const
150 BLI_assert(callback_
!= nullptr);
151 return callback_(callable_
, std::forward
<Params
>(params
)...);
155 * Returns true, when the `FunctionRef` references a function currently.
156 * If this returns false, the `FunctionRef` must not be called.
158 operator bool() const
160 /* Just checking `callback_` is enough to determine if the `FunctionRef` is in a state that it
161 * can be called in. */
162 return callback_
!= nullptr;
166 } // namespace blender