1*6881a400Schristos /* Copyright (C) 2017-2023 Free Software Foundation, Inc. 27d62b00eSchristos 37d62b00eSchristos This file is part of GDB. 47d62b00eSchristos 57d62b00eSchristos This program is free software; you can redistribute it and/or modify 67d62b00eSchristos it under the terms of the GNU General Public License as published by 77d62b00eSchristos the Free Software Foundation; either version 3 of the License, or 87d62b00eSchristos (at your option) any later version. 97d62b00eSchristos 107d62b00eSchristos This program is distributed in the hope that it will be useful, 117d62b00eSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 127d62b00eSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 137d62b00eSchristos GNU General Public License for more details. 147d62b00eSchristos 157d62b00eSchristos You should have received a copy of the GNU General Public License 167d62b00eSchristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 177d62b00eSchristos 187d62b00eSchristos #ifndef COMMON_FUNCTION_VIEW_H 197d62b00eSchristos #define COMMON_FUNCTION_VIEW_H 207d62b00eSchristos 217d62b00eSchristos /* function_view is a polymorphic type-erasing wrapper class that 227d62b00eSchristos encapsulates a non-owning reference to arbitrary callable objects. 237d62b00eSchristos 247d62b00eSchristos A way to put it is that function_view is to std::function like 257d62b00eSchristos std::string_view is to std::string. While std::function stores a 267d62b00eSchristos type-erased callable object internally, function_view holds a 277d62b00eSchristos type-erased reference to an external callable object. 287d62b00eSchristos 297d62b00eSchristos This is meant to be used as callback type of a function that: 307d62b00eSchristos 317d62b00eSchristos #1 - Takes a callback as parameter. 327d62b00eSchristos 337d62b00eSchristos #2 - Wants to support arbitrary callable objects as callback type 347d62b00eSchristos (e.g., stateful function objects, lambda closures, free 357d62b00eSchristos functions). 367d62b00eSchristos 377d62b00eSchristos #3 - Does not store the callback anywhere; instead the function 387d62b00eSchristos just calls the callback directly or forwards it to some 397d62b00eSchristos other function that calls it. 407d62b00eSchristos 417d62b00eSchristos #4 - Can't be, or we don't want it to be, a template function 427d62b00eSchristos with the callable type as template parameter. For example, 437d62b00eSchristos when the callback is a parameter of a virtual member 447d62b00eSchristos function, or when putting the function template in a header 457d62b00eSchristos would expose too much implementation detail. 467d62b00eSchristos 477d62b00eSchristos Note that the C-style "function pointer" + "void *data" callback 487d62b00eSchristos parameter idiom fails requirement #2 above. Please don't add new 497d62b00eSchristos uses of that idiom. I.e., something like this wouldn't work; 507d62b00eSchristos 517d62b00eSchristos typedef bool (iterate_over_foos_cb) (foo *f, void *user_data), 527d62b00eSchristos void iterate_over_foos (iterate_over_foos_cb *callback, void *user_data); 537d62b00eSchristos 547d62b00eSchristos foo *find_foo_by_type (int type) 557d62b00eSchristos { 567d62b00eSchristos foo *found = nullptr; 577d62b00eSchristos 587d62b00eSchristos iterate_over_foos ([&] (foo *f, void *data) 597d62b00eSchristos { 607d62b00eSchristos if (foo->type == type) 617d62b00eSchristos { 627d62b00eSchristos found = foo; 637d62b00eSchristos return true; // stop iterating 647d62b00eSchristos } 657d62b00eSchristos return false; // continue iterating 667d62b00eSchristos }, NULL); 677d62b00eSchristos 687d62b00eSchristos return found; 697d62b00eSchristos } 707d62b00eSchristos 717d62b00eSchristos The above wouldn't compile, because lambdas with captures can't be 727d62b00eSchristos implicitly converted to a function pointer (because a capture means 737d62b00eSchristos some context data must be passed to the lambda somehow). 747d62b00eSchristos 757d62b00eSchristos C++11 gave us std::function as type-erased wrapper around arbitrary 767d62b00eSchristos callables, however, std::function is not an ideal fit for transient 777d62b00eSchristos callbacks such as the use case above. For this use case, which is 787d62b00eSchristos quite pervasive, a function_view is a better choice, because while 797d62b00eSchristos function_view is light and does not require any heap allocation, 807d62b00eSchristos std::function is a heavy-weight object with value semantics that 817d62b00eSchristos generally requires a heap allocation on construction/assignment of 827d62b00eSchristos the target callable. In addition, while it is possible to use 837d62b00eSchristos std::function in such a way that avoids most of the overhead by 847d62b00eSchristos making sure to only construct it with callables of types that fit 857d62b00eSchristos std::function's small object optimization, such as function 867d62b00eSchristos pointers and std::reference_wrapper callables, that is quite 877d62b00eSchristos inconvenient in practice, because restricting to free-function 887d62b00eSchristos callables would imply no state/capture/closure, which we need in 897d62b00eSchristos most cases, and std::reference_wrapper implies remembering to use 907d62b00eSchristos std::ref/std::cref where the callable is constructed, with the 917d62b00eSchristos added inconvenience that std::ref/std::cref have deleted rvalue-ref 927d62b00eSchristos overloads, meaning you can't use unnamed/temporary lambdas with 937d62b00eSchristos them. 947d62b00eSchristos 957d62b00eSchristos Note that because function_view is a non-owning view of a callable, 967d62b00eSchristos care must be taken to ensure that the callable outlives the 977d62b00eSchristos function_view that calls it. This is not really a problem for the 987d62b00eSchristos use case function_view is intended for, such as passing a temporary 997d62b00eSchristos function object / lambda to a function that accepts a callback, 1007d62b00eSchristos because in those cases, the temporary is guaranteed to be live 1017d62b00eSchristos until the called function returns. 1027d62b00eSchristos 1037d62b00eSchristos Calling a function_view with no associated target is undefined, 1047d62b00eSchristos unlike with std::function, which throws std::bad_function_call. 1057d62b00eSchristos This is by design, to avoid the otherwise necessary NULL check in 1067d62b00eSchristos function_view::operator(). 1077d62b00eSchristos 1087d62b00eSchristos Since function_view objects are small (a pair of pointers), they 1097d62b00eSchristos should generally be passed around by value. 1107d62b00eSchristos 1117d62b00eSchristos Usage: 1127d62b00eSchristos 1137d62b00eSchristos Given this function that accepts a callback: 1147d62b00eSchristos 1157d62b00eSchristos void 1167d62b00eSchristos iterate_over_foos (gdb::function_view<void (foo *)> callback) 1177d62b00eSchristos { 1187d62b00eSchristos for (auto &foo : foos) 1197d62b00eSchristos callback (&foo); 1207d62b00eSchristos } 1217d62b00eSchristos 1227d62b00eSchristos you can call it like this, passing a lambda as callback: 1237d62b00eSchristos 1247d62b00eSchristos iterate_over_foos ([&] (foo *f) 1257d62b00eSchristos { 1267d62b00eSchristos process_one_foo (f); 1277d62b00eSchristos }); 1287d62b00eSchristos 1297d62b00eSchristos or like this, passing a function object as callback: 1307d62b00eSchristos 1317d62b00eSchristos struct function_object 1327d62b00eSchristos { 1337d62b00eSchristos void operator() (foo *f) 1347d62b00eSchristos { 1357d62b00eSchristos if (s->check ()) 1367d62b00eSchristos process_one_foo (f); 1377d62b00eSchristos } 1387d62b00eSchristos 1397d62b00eSchristos // some state 1407d62b00eSchristos state *s; 1417d62b00eSchristos }; 1427d62b00eSchristos 1437d62b00eSchristos state mystate; 1447d62b00eSchristos function_object matcher {&mystate}; 1457d62b00eSchristos iterate_over_foos (matcher); 1467d62b00eSchristos 1477d62b00eSchristos or like this, passing a function pointer as callback: 1487d62b00eSchristos 1497d62b00eSchristos iterate_over_foos (process_one_foo); 1507d62b00eSchristos 151*6881a400Schristos There's also a gdb::make_function_view function that you can use to 152*6881a400Schristos automatically create a function_view from a callable without having 153*6881a400Schristos to specify the function_view's template parameter. E.g.: 154*6881a400Schristos 155*6881a400Schristos auto lambda = [&] (int) { ... }; 156*6881a400Schristos auto fv = gdb::make_function_view (lambda); 157*6881a400Schristos 158*6881a400Schristos This can be useful for example when calling a template function 159*6881a400Schristos whose function_view parameter type depends on the function's 160*6881a400Schristos template parameters. In such case, you can't rely on implicit 161*6881a400Schristos callable->function_view conversion for the function_view argument. 162*6881a400Schristos You must pass a function_view argument already of the right type to 163*6881a400Schristos the template function. E.g., with this: 164*6881a400Schristos 165*6881a400Schristos template<typename T> 166*6881a400Schristos void my_function (T v, gdb::function_view<void(T)> callback = nullptr); 167*6881a400Schristos 168*6881a400Schristos this wouldn't compile: 169*6881a400Schristos 170*6881a400Schristos auto lambda = [&] (int) { ... }; 171*6881a400Schristos my_function (1, lambda); 172*6881a400Schristos 173*6881a400Schristos Note that this immediately dangles the temporary lambda object: 174*6881a400Schristos 175*6881a400Schristos gdb::function_view<void(int)> fv = [&] (int) { ... }; // dangles 176*6881a400Schristos my_function (fv); 177*6881a400Schristos 178*6881a400Schristos To avoid the dangling you'd have to use a named temporary for the 179*6881a400Schristos lambda: 180*6881a400Schristos 181*6881a400Schristos auto lambda = [&] (int) { ... }; 182*6881a400Schristos gdb::function_view<void(int)> fv = lambda; 183*6881a400Schristos my_function (fv); 184*6881a400Schristos 185*6881a400Schristos Using gdb::make_function_view instead automatically deduces the 186*6881a400Schristos function_view's full type, and, avoids worrying about dangling. For 187*6881a400Schristos the example above, we could write instead: 188*6881a400Schristos 189*6881a400Schristos auto lambda = [&] (int) { ... }; 190*6881a400Schristos my_function (1, gdb::make_function_view (lambda)); 191*6881a400Schristos 1927d62b00eSchristos You can find unit tests covering the whole API in 1937d62b00eSchristos unittests/function-view-selftests.c. */ 1947d62b00eSchristos 195*6881a400Schristos #include "invoke-result.h" 1967d62b00eSchristos namespace gdb { 1977d62b00eSchristos 1987d62b00eSchristos namespace fv_detail { 1997d62b00eSchristos /* Bits shared by all function_view instantiations that do not depend 2007d62b00eSchristos on the template parameters. */ 2017d62b00eSchristos 2027d62b00eSchristos /* Storage for the erased callable. This is a union in order to be 2037d62b00eSchristos able to save both a function object (data) pointer or a function 2047d62b00eSchristos pointer without triggering undefined behavior. */ 2057d62b00eSchristos union erased_callable 2067d62b00eSchristos { 2077d62b00eSchristos /* For function objects. */ 2087d62b00eSchristos void *data; 2097d62b00eSchristos 2107d62b00eSchristos /* For function pointers. */ 2117d62b00eSchristos void (*fn) (); 2127d62b00eSchristos }; 2137d62b00eSchristos 2147d62b00eSchristos } /* namespace fv_detail */ 2157d62b00eSchristos 2167d62b00eSchristos /* Use partial specialization to get access to the callable's 2177d62b00eSchristos signature. */ 2187d62b00eSchristos template<class Signature> 2197d62b00eSchristos struct function_view; 2207d62b00eSchristos 2217d62b00eSchristos template<typename Res, typename... Args> 2227d62b00eSchristos class function_view<Res (Args...)> 2237d62b00eSchristos { 2247d62b00eSchristos template<typename From, typename To> 2257d62b00eSchristos using CompatibleReturnType 2267d62b00eSchristos = Or<std::is_void<To>, 2277d62b00eSchristos std::is_same<From, To>, 2287d62b00eSchristos std::is_convertible<From, To>>; 2297d62b00eSchristos 2307d62b00eSchristos /* True if Func can be called with Args, and either the result is 2317d62b00eSchristos Res, convertible to Res or Res is void. */ 2327d62b00eSchristos template<typename Callable, 233*6881a400Schristos typename Res2 = typename gdb::invoke_result<Callable &, Args...>::type> 2347d62b00eSchristos struct IsCompatibleCallable : CompatibleReturnType<Res2, Res> 2357d62b00eSchristos {}; 2367d62b00eSchristos 2377d62b00eSchristos /* True if Callable is a function_view. Used to avoid hijacking the 2387d62b00eSchristos copy ctor. */ 2397d62b00eSchristos template <typename Callable> 2407d62b00eSchristos struct IsFunctionView 2417d62b00eSchristos : std::is_same<function_view, typename std::decay<Callable>::type> 2427d62b00eSchristos {}; 2437d62b00eSchristos 2447d62b00eSchristos public: 2457d62b00eSchristos 2467d62b00eSchristos /* NULL by default. */ 2477d62b00eSchristos constexpr function_view () noexcept 2487d62b00eSchristos : m_erased_callable {}, 2497d62b00eSchristos m_invoker {} 2507d62b00eSchristos {} 2517d62b00eSchristos 2527d62b00eSchristos /* Default copy/assignment is fine. */ 2537d62b00eSchristos function_view (const function_view &) = default; 2547d62b00eSchristos function_view &operator= (const function_view &) = default; 2557d62b00eSchristos 2567d62b00eSchristos /* This is the main entry point. Use SFINAE to avoid hijacking the 2577d62b00eSchristos copy constructor and to ensure that the target type is 2587d62b00eSchristos compatible. */ 2597d62b00eSchristos template 2607d62b00eSchristos <typename Callable, 2617d62b00eSchristos typename = Requires<Not<IsFunctionView<Callable>>>, 2627d62b00eSchristos typename = Requires<IsCompatibleCallable<Callable>>> 2637d62b00eSchristos function_view (Callable &&callable) noexcept 2647d62b00eSchristos { 2657d62b00eSchristos bind (callable); 2667d62b00eSchristos } 2677d62b00eSchristos 2687d62b00eSchristos /* Construct a NULL function_view. */ 2697d62b00eSchristos constexpr function_view (std::nullptr_t) noexcept 2707d62b00eSchristos : m_erased_callable {}, 2717d62b00eSchristos m_invoker {} 2727d62b00eSchristos {} 2737d62b00eSchristos 2747d62b00eSchristos /* Clear a function_view. */ 2757d62b00eSchristos function_view &operator= (std::nullptr_t) noexcept 2767d62b00eSchristos { 2777d62b00eSchristos m_invoker = nullptr; 2787d62b00eSchristos return *this; 2797d62b00eSchristos } 2807d62b00eSchristos 2817d62b00eSchristos /* Return true if the wrapper has a target, false otherwise. Note 2827d62b00eSchristos we check M_INVOKER instead of M_ERASED_CALLABLE because we don't 2837d62b00eSchristos know which member of the union is active right now. */ 2847d62b00eSchristos constexpr explicit operator bool () const noexcept 2857d62b00eSchristos { return m_invoker != nullptr; } 2867d62b00eSchristos 2877d62b00eSchristos /* Call the callable. */ 2887d62b00eSchristos Res operator () (Args... args) const 2897d62b00eSchristos { return m_invoker (m_erased_callable, std::forward<Args> (args)...); } 2907d62b00eSchristos 2917d62b00eSchristos private: 2927d62b00eSchristos 2937d62b00eSchristos /* Bind this function_view to a compatible function object 2947d62b00eSchristos reference. */ 2957d62b00eSchristos template <typename Callable> 2967d62b00eSchristos void bind (Callable &callable) noexcept 2977d62b00eSchristos { 2987d62b00eSchristos m_erased_callable.data = (void *) std::addressof (callable); 2997d62b00eSchristos m_invoker = [] (fv_detail::erased_callable ecall, Args... args) 3007d62b00eSchristos noexcept (noexcept (callable (std::forward<Args> (args)...))) -> Res 3017d62b00eSchristos { 3027d62b00eSchristos auto &restored_callable = *static_cast<Callable *> (ecall.data); 3037d62b00eSchristos /* The explicit cast to Res avoids a compile error when Res is 3047d62b00eSchristos void and the callable returns non-void. */ 3057d62b00eSchristos return (Res) restored_callable (std::forward<Args> (args)...); 3067d62b00eSchristos }; 3077d62b00eSchristos } 3087d62b00eSchristos 3097d62b00eSchristos /* Bind this function_view to a compatible function pointer. 3107d62b00eSchristos 3117d62b00eSchristos Making this a separate function allows avoiding one indirection, 3127d62b00eSchristos by storing the function pointer directly in the storage, instead 3137d62b00eSchristos of a pointer to pointer. erased_callable is then a union in 3147d62b00eSchristos order to avoid storing a function pointer as a data pointer here, 3157d62b00eSchristos which would be undefined. */ 3167d62b00eSchristos template<class Res2, typename... Args2> 3177d62b00eSchristos void bind (Res2 (*fn) (Args2...)) noexcept 3187d62b00eSchristos { 3197d62b00eSchristos m_erased_callable.fn = reinterpret_cast<void (*) ()> (fn); 3207d62b00eSchristos m_invoker = [] (fv_detail::erased_callable ecall, Args... args) 3217d62b00eSchristos noexcept (noexcept (fn (std::forward<Args> (args)...))) -> Res 3227d62b00eSchristos { 3237d62b00eSchristos auto restored_fn = reinterpret_cast<Res2 (*) (Args2...)> (ecall.fn); 3247d62b00eSchristos /* The explicit cast to Res avoids a compile error when Res is 3257d62b00eSchristos void and the callable returns non-void. */ 3267d62b00eSchristos return (Res) restored_fn (std::forward<Args> (args)...); 3277d62b00eSchristos }; 3287d62b00eSchristos } 3297d62b00eSchristos 3307d62b00eSchristos /* Storage for the erased callable. */ 3317d62b00eSchristos fv_detail::erased_callable m_erased_callable; 3327d62b00eSchristos 3337d62b00eSchristos /* The invoker. This is set to a capture-less lambda by one of the 3347d62b00eSchristos 'bind' overloads. The lambda restores the right type of the 3357d62b00eSchristos callable (which is passed as first argument), and forwards the 3367d62b00eSchristos args. */ 3377d62b00eSchristos Res (*m_invoker) (fv_detail::erased_callable, Args...); 3387d62b00eSchristos }; 3397d62b00eSchristos 3407d62b00eSchristos /* Allow comparison with NULL. Defer the work to the in-class 3417d62b00eSchristos operator bool implementation. */ 3427d62b00eSchristos 3437d62b00eSchristos template<typename Res, typename... Args> 3447d62b00eSchristos constexpr inline bool 3457d62b00eSchristos operator== (const function_view<Res (Args...)> &f, std::nullptr_t) noexcept 3467d62b00eSchristos { return !static_cast<bool> (f); } 3477d62b00eSchristos 3487d62b00eSchristos template<typename Res, typename... Args> 3497d62b00eSchristos constexpr inline bool 3507d62b00eSchristos operator== (std::nullptr_t, const function_view<Res (Args...)> &f) noexcept 3517d62b00eSchristos { return !static_cast<bool> (f); } 3527d62b00eSchristos 3537d62b00eSchristos template<typename Res, typename... Args> 3547d62b00eSchristos constexpr inline bool 3557d62b00eSchristos operator!= (const function_view<Res (Args...)> &f, std::nullptr_t) noexcept 3567d62b00eSchristos { return static_cast<bool> (f); } 3577d62b00eSchristos 3587d62b00eSchristos template<typename Res, typename... Args> 3597d62b00eSchristos constexpr inline bool 3607d62b00eSchristos operator!= (std::nullptr_t, const function_view<Res (Args...)> &f) noexcept 3617d62b00eSchristos { return static_cast<bool> (f); } 3627d62b00eSchristos 363*6881a400Schristos namespace fv_detail { 364*6881a400Schristos 365*6881a400Schristos /* Helper traits type to automatically find the right function_view 366*6881a400Schristos type for a callable. */ 367*6881a400Schristos 368*6881a400Schristos /* Use partial specialization to get access to the callable's 369*6881a400Schristos signature, for all the different callable variants. */ 370*6881a400Schristos 371*6881a400Schristos template<typename> 372*6881a400Schristos struct function_view_traits; 373*6881a400Schristos 374*6881a400Schristos /* Main partial specialization with plain function signature type. 375*6881a400Schristos All others end up redirected here. */ 376*6881a400Schristos template<typename Res, typename... Args> 377*6881a400Schristos struct function_view_traits<Res (Args...)> 378*6881a400Schristos { 379*6881a400Schristos using type = gdb::function_view<Res (Args...)>; 380*6881a400Schristos }; 381*6881a400Schristos 382*6881a400Schristos /* Function pointers. */ 383*6881a400Schristos template<typename Res, typename... Args> 384*6881a400Schristos struct function_view_traits<Res (*) (Args...)> 385*6881a400Schristos : function_view_traits<Res (Args...)> 386*6881a400Schristos { 387*6881a400Schristos }; 388*6881a400Schristos 389*6881a400Schristos /* Function references. */ 390*6881a400Schristos template<typename Res, typename... Args> 391*6881a400Schristos struct function_view_traits<Res (&) (Args...)> 392*6881a400Schristos : function_view_traits<Res (Args...)> 393*6881a400Schristos { 394*6881a400Schristos }; 395*6881a400Schristos 396*6881a400Schristos /* Reference to function pointers. */ 397*6881a400Schristos template<typename Res, typename... Args> 398*6881a400Schristos struct function_view_traits<Res (*&) (Args...)> 399*6881a400Schristos : function_view_traits<Res (Args...)> 400*6881a400Schristos { 401*6881a400Schristos }; 402*6881a400Schristos 403*6881a400Schristos /* Reference to const function pointers. */ 404*6881a400Schristos template<typename Res, typename... Args> 405*6881a400Schristos struct function_view_traits<Res (* const &) (Args...)> 406*6881a400Schristos : function_view_traits<Res (Args...)> 407*6881a400Schristos { 408*6881a400Schristos }; 409*6881a400Schristos 410*6881a400Schristos /* Const member functions. function_view doesn't support these, but 411*6881a400Schristos we need this in order to extract the type of function objects. 412*6881a400Schristos Lambdas pass here, after starting at the operator() case, 413*6881a400Schristos below. */ 414*6881a400Schristos template<typename Res, typename Class, typename... Args> 415*6881a400Schristos struct function_view_traits<Res (Class::*) (Args...) const> 416*6881a400Schristos : function_view_traits<Res (Args...)> 417*6881a400Schristos { 418*6881a400Schristos }; 419*6881a400Schristos 420*6881a400Schristos /* Member functions. Ditto, for function objects with non-const 421*6881a400Schristos operator(). */ 422*6881a400Schristos template<typename Res, typename Class, typename... Args> 423*6881a400Schristos struct function_view_traits<Res (Class::*) (Args...)> 424*6881a400Schristos : function_view_traits<Res (Args...)> 425*6881a400Schristos { 426*6881a400Schristos }; 427*6881a400Schristos 428*6881a400Schristos /* Function objects, lambdas, std::function, any type that defines 429*6881a400Schristos operator(). */ 430*6881a400Schristos template<typename FuncObj> 431*6881a400Schristos struct function_view_traits 432*6881a400Schristos : function_view_traits <decltype 433*6881a400Schristos (&std::remove_reference<FuncObj>::type::operator())> 434*6881a400Schristos { 435*6881a400Schristos }; 436*6881a400Schristos 437*6881a400Schristos } /* namespace fv_detail */ 438*6881a400Schristos 439*6881a400Schristos /* Make a function_view from a callable. Useful to automatically 440*6881a400Schristos deduce the function_view's template argument type. */ 441*6881a400Schristos template<typename Callable> 442*6881a400Schristos auto make_function_view (Callable &&callable) 443*6881a400Schristos -> typename fv_detail::function_view_traits<Callable>::type 444*6881a400Schristos { 445*6881a400Schristos using fv = typename fv_detail::function_view_traits<Callable>::type; 446*6881a400Schristos return fv (std::forward<Callable> (callable)); 447*6881a400Schristos } 448*6881a400Schristos 4497d62b00eSchristos } /* namespace gdb */ 4507d62b00eSchristos 4517d62b00eSchristos #endif 452