Cleanup: Subdiv: Remove common_ prefix
[blender.git] / source / blender / blenlib / BLI_function_ref.hh
blob95f60fae55450edfb119f4e3db9ea892ce1d97ab
1 /* SPDX-FileCopyrightText: 2023 Blender Authors
3 * SPDX-License-Identifier: GPL-2.0-or-later */
5 #pragma once
7 #include <type_traits>
8 #include <utility>
10 #include "BLI_build_config.h"
11 #include "BLI_utildefines.h"
13 /** \file
14 * \ingroup bli
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.
21 * Example signatures:
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
39 * where it is called.
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.
58 * Don't:
59 * FunctionRef<int()> ref = []() { return 0; };
60 * Do:
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; });
70 namespace blender {
72 template<typename Function> class FunctionRef;
74 template<typename Ret, typename... Params> class FunctionRef<Ret(Params...)> {
75 private:
76 /**
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;
81 /**
82 * A pointer to the referenced callable object. This can be a C function, a lambda object or any
83 * other callable.
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.
90 intptr_t callable_;
92 template<typename Callable> static Ret callback_fn(intptr_t callable, Params... params)
94 return (*reinterpret_cast<Callable *>(callable))(std::forward<Params>(params)...);
97 public:
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
110 * another lambda.
112 template<typename Callable,
113 BLI_ENABLE_IF((
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"
126 # if COMPILER_GCC
127 # pragma GCC diagnostic ignored "-Wnonnull-compare"
128 # endif
129 #endif
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);
133 if (!is_truthy) {
134 callback_ = nullptr;
135 callable_ = 0;
137 #if COMPILER_CLANG || COMPILER_GCC
138 # pragma GCC diagnostic pop
139 #endif
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