1 1.1.1.3 christos /* Copyright (C) 2017-2024 Free Software Foundation, Inc. 2 1.1 christos 3 1.1 christos This file is part of GDB. 4 1.1 christos 5 1.1 christos This program is free software; you can redistribute it and/or modify 6 1.1 christos it under the terms of the GNU General Public License as published by 7 1.1 christos the Free Software Foundation; either version 3 of the License, or 8 1.1 christos (at your option) any later version. 9 1.1 christos 10 1.1 christos This program is distributed in the hope that it will be useful, 11 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 12 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 1.1 christos GNU General Public License for more details. 14 1.1 christos 15 1.1 christos You should have received a copy of the GNU General Public License 16 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17 1.1 christos 18 1.1.1.4 christos #ifndef GDBSUPPORT_FUNCTION_VIEW_H 19 1.1.1.4 christos #define GDBSUPPORT_FUNCTION_VIEW_H 20 1.1 christos 21 1.1 christos /* function_view is a polymorphic type-erasing wrapper class that 22 1.1 christos encapsulates a non-owning reference to arbitrary callable objects. 23 1.1 christos 24 1.1 christos A way to put it is that function_view is to std::function like 25 1.1 christos std::string_view is to std::string. While std::function stores a 26 1.1 christos type-erased callable object internally, function_view holds a 27 1.1 christos type-erased reference to an external callable object. 28 1.1 christos 29 1.1 christos This is meant to be used as callback type of a function that: 30 1.1 christos 31 1.1 christos #1 - Takes a callback as parameter. 32 1.1 christos 33 1.1 christos #2 - Wants to support arbitrary callable objects as callback type 34 1.1 christos (e.g., stateful function objects, lambda closures, free 35 1.1 christos functions). 36 1.1 christos 37 1.1 christos #3 - Does not store the callback anywhere; instead the function 38 1.1 christos just calls the callback directly or forwards it to some 39 1.1 christos other function that calls it. 40 1.1 christos 41 1.1 christos #4 - Can't be, or we don't want it to be, a template function 42 1.1 christos with the callable type as template parameter. For example, 43 1.1 christos when the callback is a parameter of a virtual member 44 1.1 christos function, or when putting the function template in a header 45 1.1 christos would expose too much implementation detail. 46 1.1 christos 47 1.1 christos Note that the C-style "function pointer" + "void *data" callback 48 1.1 christos parameter idiom fails requirement #2 above. Please don't add new 49 1.1 christos uses of that idiom. I.e., something like this wouldn't work; 50 1.1 christos 51 1.1 christos typedef bool (iterate_over_foos_cb) (foo *f, void *user_data), 52 1.1 christos void iterate_over_foos (iterate_over_foos_cb *callback, void *user_data); 53 1.1 christos 54 1.1 christos foo *find_foo_by_type (int type) 55 1.1 christos { 56 1.1 christos foo *found = nullptr; 57 1.1 christos 58 1.1 christos iterate_over_foos ([&] (foo *f, void *data) 59 1.1 christos { 60 1.1 christos if (foo->type == type) 61 1.1 christos { 62 1.1 christos found = foo; 63 1.1 christos return true; // stop iterating 64 1.1 christos } 65 1.1 christos return false; // continue iterating 66 1.1 christos }, NULL); 67 1.1 christos 68 1.1 christos return found; 69 1.1 christos } 70 1.1 christos 71 1.1 christos The above wouldn't compile, because lambdas with captures can't be 72 1.1 christos implicitly converted to a function pointer (because a capture means 73 1.1 christos some context data must be passed to the lambda somehow). 74 1.1 christos 75 1.1 christos C++11 gave us std::function as type-erased wrapper around arbitrary 76 1.1 christos callables, however, std::function is not an ideal fit for transient 77 1.1 christos callbacks such as the use case above. For this use case, which is 78 1.1 christos quite pervasive, a function_view is a better choice, because while 79 1.1 christos function_view is light and does not require any heap allocation, 80 1.1 christos std::function is a heavy-weight object with value semantics that 81 1.1 christos generally requires a heap allocation on construction/assignment of 82 1.1 christos the target callable. In addition, while it is possible to use 83 1.1 christos std::function in such a way that avoids most of the overhead by 84 1.1 christos making sure to only construct it with callables of types that fit 85 1.1 christos std::function's small object optimization, such as function 86 1.1 christos pointers and std::reference_wrapper callables, that is quite 87 1.1 christos inconvenient in practice, because restricting to free-function 88 1.1 christos callables would imply no state/capture/closure, which we need in 89 1.1 christos most cases, and std::reference_wrapper implies remembering to use 90 1.1 christos std::ref/std::cref where the callable is constructed, with the 91 1.1 christos added inconvenience that std::ref/std::cref have deleted rvalue-ref 92 1.1 christos overloads, meaning you can't use unnamed/temporary lambdas with 93 1.1 christos them. 94 1.1 christos 95 1.1 christos Note that because function_view is a non-owning view of a callable, 96 1.1 christos care must be taken to ensure that the callable outlives the 97 1.1 christos function_view that calls it. This is not really a problem for the 98 1.1 christos use case function_view is intended for, such as passing a temporary 99 1.1 christos function object / lambda to a function that accepts a callback, 100 1.1 christos because in those cases, the temporary is guaranteed to be live 101 1.1 christos until the called function returns. 102 1.1 christos 103 1.1 christos Calling a function_view with no associated target is undefined, 104 1.1 christos unlike with std::function, which throws std::bad_function_call. 105 1.1 christos This is by design, to avoid the otherwise necessary NULL check in 106 1.1 christos function_view::operator(). 107 1.1 christos 108 1.1 christos Since function_view objects are small (a pair of pointers), they 109 1.1 christos should generally be passed around by value. 110 1.1 christos 111 1.1 christos Usage: 112 1.1 christos 113 1.1 christos Given this function that accepts a callback: 114 1.1 christos 115 1.1 christos void 116 1.1 christos iterate_over_foos (gdb::function_view<void (foo *)> callback) 117 1.1 christos { 118 1.1 christos for (auto &foo : foos) 119 1.1 christos callback (&foo); 120 1.1 christos } 121 1.1 christos 122 1.1 christos you can call it like this, passing a lambda as callback: 123 1.1 christos 124 1.1 christos iterate_over_foos ([&] (foo *f) 125 1.1 christos { 126 1.1 christos process_one_foo (f); 127 1.1 christos }); 128 1.1 christos 129 1.1 christos or like this, passing a function object as callback: 130 1.1 christos 131 1.1 christos struct function_object 132 1.1 christos { 133 1.1 christos void operator() (foo *f) 134 1.1 christos { 135 1.1 christos if (s->check ()) 136 1.1 christos process_one_foo (f); 137 1.1 christos } 138 1.1 christos 139 1.1 christos // some state 140 1.1 christos state *s; 141 1.1 christos }; 142 1.1 christos 143 1.1 christos state mystate; 144 1.1 christos function_object matcher {&mystate}; 145 1.1 christos iterate_over_foos (matcher); 146 1.1 christos 147 1.1 christos or like this, passing a function pointer as callback: 148 1.1 christos 149 1.1 christos iterate_over_foos (process_one_foo); 150 1.1 christos 151 1.1.1.2 christos There's also a gdb::make_function_view function that you can use to 152 1.1.1.2 christos automatically create a function_view from a callable without having 153 1.1.1.2 christos to specify the function_view's template parameter. E.g.: 154 1.1.1.2 christos 155 1.1.1.2 christos auto lambda = [&] (int) { ... }; 156 1.1.1.2 christos auto fv = gdb::make_function_view (lambda); 157 1.1.1.2 christos 158 1.1.1.2 christos This can be useful for example when calling a template function 159 1.1.1.2 christos whose function_view parameter type depends on the function's 160 1.1.1.2 christos template parameters. In such case, you can't rely on implicit 161 1.1.1.2 christos callable->function_view conversion for the function_view argument. 162 1.1.1.2 christos You must pass a function_view argument already of the right type to 163 1.1.1.2 christos the template function. E.g., with this: 164 1.1.1.2 christos 165 1.1.1.2 christos template<typename T> 166 1.1.1.2 christos void my_function (T v, gdb::function_view<void(T)> callback = nullptr); 167 1.1.1.2 christos 168 1.1.1.2 christos this wouldn't compile: 169 1.1.1.2 christos 170 1.1.1.2 christos auto lambda = [&] (int) { ... }; 171 1.1.1.2 christos my_function (1, lambda); 172 1.1.1.2 christos 173 1.1.1.2 christos Note that this immediately dangles the temporary lambda object: 174 1.1.1.2 christos 175 1.1.1.2 christos gdb::function_view<void(int)> fv = [&] (int) { ... }; // dangles 176 1.1.1.2 christos my_function (fv); 177 1.1.1.2 christos 178 1.1.1.2 christos To avoid the dangling you'd have to use a named temporary for the 179 1.1.1.2 christos lambda: 180 1.1.1.2 christos 181 1.1.1.2 christos auto lambda = [&] (int) { ... }; 182 1.1.1.2 christos gdb::function_view<void(int)> fv = lambda; 183 1.1.1.2 christos my_function (fv); 184 1.1.1.2 christos 185 1.1.1.2 christos Using gdb::make_function_view instead automatically deduces the 186 1.1.1.2 christos function_view's full type, and, avoids worrying about dangling. For 187 1.1.1.2 christos the example above, we could write instead: 188 1.1.1.2 christos 189 1.1.1.2 christos auto lambda = [&] (int) { ... }; 190 1.1.1.2 christos my_function (1, gdb::make_function_view (lambda)); 191 1.1.1.2 christos 192 1.1 christos You can find unit tests covering the whole API in 193 1.1 christos unittests/function-view-selftests.c. */ 194 1.1 christos 195 1.1.1.3 christos #include <type_traits> 196 1.1 christos namespace gdb { 197 1.1 christos 198 1.1 christos namespace fv_detail { 199 1.1 christos /* Bits shared by all function_view instantiations that do not depend 200 1.1 christos on the template parameters. */ 201 1.1 christos 202 1.1 christos /* Storage for the erased callable. This is a union in order to be 203 1.1 christos able to save both a function object (data) pointer or a function 204 1.1 christos pointer without triggering undefined behavior. */ 205 1.1 christos union erased_callable 206 1.1 christos { 207 1.1 christos /* For function objects. */ 208 1.1 christos void *data; 209 1.1 christos 210 1.1 christos /* For function pointers. */ 211 1.1 christos void (*fn) (); 212 1.1 christos }; 213 1.1 christos 214 1.1 christos } /* namespace fv_detail */ 215 1.1 christos 216 1.1 christos /* Use partial specialization to get access to the callable's 217 1.1 christos signature. */ 218 1.1 christos template<class Signature> 219 1.1 christos struct function_view; 220 1.1 christos 221 1.1 christos template<typename Res, typename... Args> 222 1.1 christos class function_view<Res (Args...)> 223 1.1 christos { 224 1.1 christos template<typename From, typename To> 225 1.1 christos using CompatibleReturnType 226 1.1 christos = Or<std::is_void<To>, 227 1.1 christos std::is_same<From, To>, 228 1.1 christos std::is_convertible<From, To>>; 229 1.1 christos 230 1.1 christos /* True if Func can be called with Args, and either the result is 231 1.1 christos Res, convertible to Res or Res is void. */ 232 1.1 christos template<typename Callable, 233 1.1.1.3 christos typename Res2 = typename std::invoke_result<Callable &, Args...>::type> 234 1.1 christos struct IsCompatibleCallable : CompatibleReturnType<Res2, Res> 235 1.1 christos {}; 236 1.1 christos 237 1.1 christos /* True if Callable is a function_view. Used to avoid hijacking the 238 1.1 christos copy ctor. */ 239 1.1 christos template <typename Callable> 240 1.1 christos struct IsFunctionView 241 1.1 christos : std::is_same<function_view, typename std::decay<Callable>::type> 242 1.1 christos {}; 243 1.1 christos 244 1.1 christos public: 245 1.1 christos 246 1.1 christos /* NULL by default. */ 247 1.1 christos constexpr function_view () noexcept 248 1.1 christos : m_erased_callable {}, 249 1.1 christos m_invoker {} 250 1.1 christos {} 251 1.1 christos 252 1.1 christos /* Default copy/assignment is fine. */ 253 1.1 christos function_view (const function_view &) = default; 254 1.1 christos function_view &operator= (const function_view &) = default; 255 1.1 christos 256 1.1 christos /* This is the main entry point. Use SFINAE to avoid hijacking the 257 1.1 christos copy constructor and to ensure that the target type is 258 1.1 christos compatible. */ 259 1.1 christos template 260 1.1 christos <typename Callable, 261 1.1 christos typename = Requires<Not<IsFunctionView<Callable>>>, 262 1.1 christos typename = Requires<IsCompatibleCallable<Callable>>> 263 1.1 christos function_view (Callable &&callable) noexcept 264 1.1 christos { 265 1.1 christos bind (callable); 266 1.1 christos } 267 1.1 christos 268 1.1 christos /* Construct a NULL function_view. */ 269 1.1 christos constexpr function_view (std::nullptr_t) noexcept 270 1.1 christos : m_erased_callable {}, 271 1.1 christos m_invoker {} 272 1.1 christos {} 273 1.1 christos 274 1.1 christos /* Clear a function_view. */ 275 1.1 christos function_view &operator= (std::nullptr_t) noexcept 276 1.1 christos { 277 1.1 christos m_invoker = nullptr; 278 1.1 christos return *this; 279 1.1 christos } 280 1.1 christos 281 1.1 christos /* Return true if the wrapper has a target, false otherwise. Note 282 1.1 christos we check M_INVOKER instead of M_ERASED_CALLABLE because we don't 283 1.1 christos know which member of the union is active right now. */ 284 1.1 christos constexpr explicit operator bool () const noexcept 285 1.1 christos { return m_invoker != nullptr; } 286 1.1 christos 287 1.1 christos /* Call the callable. */ 288 1.1 christos Res operator () (Args... args) const 289 1.1 christos { return m_invoker (m_erased_callable, std::forward<Args> (args)...); } 290 1.1 christos 291 1.1 christos private: 292 1.1 christos 293 1.1 christos /* Bind this function_view to a compatible function object 294 1.1 christos reference. */ 295 1.1 christos template <typename Callable> 296 1.1 christos void bind (Callable &callable) noexcept 297 1.1 christos { 298 1.1 christos m_erased_callable.data = (void *) std::addressof (callable); 299 1.1 christos m_invoker = [] (fv_detail::erased_callable ecall, Args... args) 300 1.1 christos noexcept (noexcept (callable (std::forward<Args> (args)...))) -> Res 301 1.1 christos { 302 1.1 christos auto &restored_callable = *static_cast<Callable *> (ecall.data); 303 1.1 christos /* The explicit cast to Res avoids a compile error when Res is 304 1.1 christos void and the callable returns non-void. */ 305 1.1 christos return (Res) restored_callable (std::forward<Args> (args)...); 306 1.1 christos }; 307 1.1 christos } 308 1.1 christos 309 1.1 christos /* Bind this function_view to a compatible function pointer. 310 1.1 christos 311 1.1 christos Making this a separate function allows avoiding one indirection, 312 1.1 christos by storing the function pointer directly in the storage, instead 313 1.1 christos of a pointer to pointer. erased_callable is then a union in 314 1.1 christos order to avoid storing a function pointer as a data pointer here, 315 1.1 christos which would be undefined. */ 316 1.1 christos template<class Res2, typename... Args2> 317 1.1 christos void bind (Res2 (*fn) (Args2...)) noexcept 318 1.1 christos { 319 1.1 christos m_erased_callable.fn = reinterpret_cast<void (*) ()> (fn); 320 1.1 christos m_invoker = [] (fv_detail::erased_callable ecall, Args... args) 321 1.1 christos noexcept (noexcept (fn (std::forward<Args> (args)...))) -> Res 322 1.1 christos { 323 1.1 christos auto restored_fn = reinterpret_cast<Res2 (*) (Args2...)> (ecall.fn); 324 1.1 christos /* The explicit cast to Res avoids a compile error when Res is 325 1.1 christos void and the callable returns non-void. */ 326 1.1 christos return (Res) restored_fn (std::forward<Args> (args)...); 327 1.1 christos }; 328 1.1 christos } 329 1.1 christos 330 1.1 christos /* Storage for the erased callable. */ 331 1.1 christos fv_detail::erased_callable m_erased_callable; 332 1.1 christos 333 1.1 christos /* The invoker. This is set to a capture-less lambda by one of the 334 1.1 christos 'bind' overloads. The lambda restores the right type of the 335 1.1 christos callable (which is passed as first argument), and forwards the 336 1.1 christos args. */ 337 1.1 christos Res (*m_invoker) (fv_detail::erased_callable, Args...); 338 1.1 christos }; 339 1.1 christos 340 1.1 christos /* Allow comparison with NULL. Defer the work to the in-class 341 1.1 christos operator bool implementation. */ 342 1.1 christos 343 1.1 christos template<typename Res, typename... Args> 344 1.1 christos constexpr inline bool 345 1.1 christos operator== (const function_view<Res (Args...)> &f, std::nullptr_t) noexcept 346 1.1 christos { return !static_cast<bool> (f); } 347 1.1 christos 348 1.1 christos template<typename Res, typename... Args> 349 1.1 christos constexpr inline bool 350 1.1 christos operator== (std::nullptr_t, const function_view<Res (Args...)> &f) noexcept 351 1.1 christos { return !static_cast<bool> (f); } 352 1.1 christos 353 1.1 christos template<typename Res, typename... Args> 354 1.1 christos constexpr inline bool 355 1.1 christos operator!= (const function_view<Res (Args...)> &f, std::nullptr_t) noexcept 356 1.1 christos { return static_cast<bool> (f); } 357 1.1 christos 358 1.1 christos template<typename Res, typename... Args> 359 1.1 christos constexpr inline bool 360 1.1 christos operator!= (std::nullptr_t, const function_view<Res (Args...)> &f) noexcept 361 1.1 christos { return static_cast<bool> (f); } 362 1.1 christos 363 1.1.1.2 christos namespace fv_detail { 364 1.1.1.2 christos 365 1.1.1.2 christos /* Helper traits type to automatically find the right function_view 366 1.1.1.2 christos type for a callable. */ 367 1.1.1.2 christos 368 1.1.1.2 christos /* Use partial specialization to get access to the callable's 369 1.1.1.2 christos signature, for all the different callable variants. */ 370 1.1.1.2 christos 371 1.1.1.2 christos template<typename> 372 1.1.1.2 christos struct function_view_traits; 373 1.1.1.2 christos 374 1.1.1.2 christos /* Main partial specialization with plain function signature type. 375 1.1.1.2 christos All others end up redirected here. */ 376 1.1.1.2 christos template<typename Res, typename... Args> 377 1.1.1.2 christos struct function_view_traits<Res (Args...)> 378 1.1.1.2 christos { 379 1.1.1.2 christos using type = gdb::function_view<Res (Args...)>; 380 1.1.1.2 christos }; 381 1.1.1.2 christos 382 1.1.1.2 christos /* Function pointers. */ 383 1.1.1.2 christos template<typename Res, typename... Args> 384 1.1.1.2 christos struct function_view_traits<Res (*) (Args...)> 385 1.1.1.2 christos : function_view_traits<Res (Args...)> 386 1.1.1.2 christos { 387 1.1.1.2 christos }; 388 1.1.1.2 christos 389 1.1.1.2 christos /* Function references. */ 390 1.1.1.2 christos template<typename Res, typename... Args> 391 1.1.1.2 christos struct function_view_traits<Res (&) (Args...)> 392 1.1.1.2 christos : function_view_traits<Res (Args...)> 393 1.1.1.2 christos { 394 1.1.1.2 christos }; 395 1.1.1.2 christos 396 1.1.1.2 christos /* Reference to function pointers. */ 397 1.1.1.2 christos template<typename Res, typename... Args> 398 1.1.1.2 christos struct function_view_traits<Res (*&) (Args...)> 399 1.1.1.2 christos : function_view_traits<Res (Args...)> 400 1.1.1.2 christos { 401 1.1.1.2 christos }; 402 1.1.1.2 christos 403 1.1.1.2 christos /* Reference to const function pointers. */ 404 1.1.1.2 christos template<typename Res, typename... Args> 405 1.1.1.2 christos struct function_view_traits<Res (* const &) (Args...)> 406 1.1.1.2 christos : function_view_traits<Res (Args...)> 407 1.1.1.2 christos { 408 1.1.1.2 christos }; 409 1.1.1.2 christos 410 1.1.1.2 christos /* Const member functions. function_view doesn't support these, but 411 1.1.1.2 christos we need this in order to extract the type of function objects. 412 1.1.1.2 christos Lambdas pass here, after starting at the operator() case, 413 1.1.1.2 christos below. */ 414 1.1.1.2 christos template<typename Res, typename Class, typename... Args> 415 1.1.1.2 christos struct function_view_traits<Res (Class::*) (Args...) const> 416 1.1.1.2 christos : function_view_traits<Res (Args...)> 417 1.1.1.2 christos { 418 1.1.1.2 christos }; 419 1.1.1.2 christos 420 1.1.1.2 christos /* Member functions. Ditto, for function objects with non-const 421 1.1.1.2 christos operator(). */ 422 1.1.1.2 christos template<typename Res, typename Class, typename... Args> 423 1.1.1.2 christos struct function_view_traits<Res (Class::*) (Args...)> 424 1.1.1.2 christos : function_view_traits<Res (Args...)> 425 1.1.1.2 christos { 426 1.1.1.2 christos }; 427 1.1.1.2 christos 428 1.1.1.2 christos /* Function objects, lambdas, std::function, any type that defines 429 1.1.1.2 christos operator(). */ 430 1.1.1.2 christos template<typename FuncObj> 431 1.1.1.2 christos struct function_view_traits 432 1.1.1.2 christos : function_view_traits <decltype 433 1.1.1.2 christos (&std::remove_reference<FuncObj>::type::operator())> 434 1.1.1.2 christos { 435 1.1.1.2 christos }; 436 1.1.1.2 christos 437 1.1.1.2 christos } /* namespace fv_detail */ 438 1.1.1.2 christos 439 1.1.1.2 christos /* Make a function_view from a callable. Useful to automatically 440 1.1.1.2 christos deduce the function_view's template argument type. */ 441 1.1.1.2 christos template<typename Callable> 442 1.1.1.2 christos auto make_function_view (Callable &&callable) 443 1.1.1.2 christos -> typename fv_detail::function_view_traits<Callable>::type 444 1.1.1.2 christos { 445 1.1.1.2 christos using fv = typename fv_detail::function_view_traits<Callable>::type; 446 1.1.1.2 christos return fv (std::forward<Callable> (callable)); 447 1.1.1.2 christos } 448 1.1.1.2 christos 449 1.1 christos } /* namespace gdb */ 450 1.1 christos 451 1.1.1.4 christos #endif /* GDBSUPPORT_FUNCTION_VIEW_H */ 452