Blender V5.0
BLI_function_ref.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
7#include <type_traits>
8#include <utility>
9
10#include "BLI_build_config.h"
11#include "BLI_utildefines.h"
12
69
70namespace blender {
71
72template<typename Function> class FunctionRef;
73
74template<typename Ret, typename... Params> class FunctionRef<Ret(Params...)> {
75 private:
79 Ret (*callback_)(intptr_t callable, Params... params) = nullptr;
80
90 intptr_t callable_;
91
92 template<typename Callable> static Ret callback_fn(intptr_t callable, Params... params)
93 {
94 return (*reinterpret_cast<Callable *>(callable))(std::forward<Params>(params)...);
95 }
96
97 public:
98 FunctionRef() = default;
99
100 FunctionRef(std::nullptr_t) {}
101
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))
119 {
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;
136 }
137#if COMPILER_CLANG || COMPILER_GCC
138# pragma GCC diagnostic pop
139#endif
140 }
141 }
142
148 Ret operator()(Params... params) const
149 {
150 BLI_assert(callback_ != nullptr);
151 return callback_(callable_, std::forward<Params>(params)...);
152 }
153
158 operator bool() const
159 {
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;
163 }
164};
165
166} // namespace blender
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_ENABLE_IF(condition)
Ret operator()(Params... params) const
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]