1*5ba1f45fSchristos /* Copyright (C) 2017-2024 Free Software Foundation, Inc. 28dffb485Schristos 38dffb485Schristos This file is part of GDB. 48dffb485Schristos 58dffb485Schristos This program is free software; you can redistribute it and/or modify 68dffb485Schristos it under the terms of the GNU General Public License as published by 78dffb485Schristos the Free Software Foundation; either version 3 of the License, or 88dffb485Schristos (at your option) any later version. 98dffb485Schristos 108dffb485Schristos This program is distributed in the hope that it will be useful, 118dffb485Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 128dffb485Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 138dffb485Schristos GNU General Public License for more details. 148dffb485Schristos 158dffb485Schristos You should have received a copy of the GNU General Public License 168dffb485Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 178dffb485Schristos 188dffb485Schristos #ifndef COMMON_FUNCTION_VIEW_H 198dffb485Schristos #define COMMON_FUNCTION_VIEW_H 208dffb485Schristos 218dffb485Schristos /* function_view is a polymorphic type-erasing wrapper class that 228dffb485Schristos encapsulates a non-owning reference to arbitrary callable objects. 238dffb485Schristos 248dffb485Schristos A way to put it is that function_view is to std::function like 258dffb485Schristos std::string_view is to std::string. While std::function stores a 268dffb485Schristos type-erased callable object internally, function_view holds a 278dffb485Schristos type-erased reference to an external callable object. 288dffb485Schristos 298dffb485Schristos This is meant to be used as callback type of a function that: 308dffb485Schristos 318dffb485Schristos #1 - Takes a callback as parameter. 328dffb485Schristos 338dffb485Schristos #2 - Wants to support arbitrary callable objects as callback type 348dffb485Schristos (e.g., stateful function objects, lambda closures, free 358dffb485Schristos functions). 368dffb485Schristos 378dffb485Schristos #3 - Does not store the callback anywhere; instead the function 388dffb485Schristos just calls the callback directly or forwards it to some 398dffb485Schristos other function that calls it. 408dffb485Schristos 418dffb485Schristos #4 - Can't be, or we don't want it to be, a template function 428dffb485Schristos with the callable type as template parameter. For example, 438dffb485Schristos when the callback is a parameter of a virtual member 448dffb485Schristos function, or when putting the function template in a header 458dffb485Schristos would expose too much implementation detail. 468dffb485Schristos 478dffb485Schristos Note that the C-style "function pointer" + "void *data" callback 488dffb485Schristos parameter idiom fails requirement #2 above. Please don't add new 498dffb485Schristos uses of that idiom. I.e., something like this wouldn't work; 508dffb485Schristos 518dffb485Schristos typedef bool (iterate_over_foos_cb) (foo *f, void *user_data), 528dffb485Schristos void iterate_over_foos (iterate_over_foos_cb *callback, void *user_data); 538dffb485Schristos 548dffb485Schristos foo *find_foo_by_type (int type) 558dffb485Schristos { 568dffb485Schristos foo *found = nullptr; 578dffb485Schristos 588dffb485Schristos iterate_over_foos ([&] (foo *f, void *data) 598dffb485Schristos { 608dffb485Schristos if (foo->type == type) 618dffb485Schristos { 628dffb485Schristos found = foo; 638dffb485Schristos return true; // stop iterating 648dffb485Schristos } 658dffb485Schristos return false; // continue iterating 668dffb485Schristos }, NULL); 678dffb485Schristos 688dffb485Schristos return found; 698dffb485Schristos } 708dffb485Schristos 718dffb485Schristos The above wouldn't compile, because lambdas with captures can't be 728dffb485Schristos implicitly converted to a function pointer (because a capture means 738dffb485Schristos some context data must be passed to the lambda somehow). 748dffb485Schristos 758dffb485Schristos C++11 gave us std::function as type-erased wrapper around arbitrary 768dffb485Schristos callables, however, std::function is not an ideal fit for transient 778dffb485Schristos callbacks such as the use case above. For this use case, which is 788dffb485Schristos quite pervasive, a function_view is a better choice, because while 798dffb485Schristos function_view is light and does not require any heap allocation, 808dffb485Schristos std::function is a heavy-weight object with value semantics that 818dffb485Schristos generally requires a heap allocation on construction/assignment of 828dffb485Schristos the target callable. In addition, while it is possible to use 838dffb485Schristos std::function in such a way that avoids most of the overhead by 848dffb485Schristos making sure to only construct it with callables of types that fit 858dffb485Schristos std::function's small object optimization, such as function 868dffb485Schristos pointers and std::reference_wrapper callables, that is quite 878dffb485Schristos inconvenient in practice, because restricting to free-function 888dffb485Schristos callables would imply no state/capture/closure, which we need in 898dffb485Schristos most cases, and std::reference_wrapper implies remembering to use 908dffb485Schristos std::ref/std::cref where the callable is constructed, with the 918dffb485Schristos added inconvenience that std::ref/std::cref have deleted rvalue-ref 928dffb485Schristos overloads, meaning you can't use unnamed/temporary lambdas with 938dffb485Schristos them. 948dffb485Schristos 958dffb485Schristos Note that because function_view is a non-owning view of a callable, 968dffb485Schristos care must be taken to ensure that the callable outlives the 978dffb485Schristos function_view that calls it. This is not really a problem for the 988dffb485Schristos use case function_view is intended for, such as passing a temporary 998dffb485Schristos function object / lambda to a function that accepts a callback, 1008dffb485Schristos because in those cases, the temporary is guaranteed to be live 1018dffb485Schristos until the called function returns. 1028dffb485Schristos 1038dffb485Schristos Calling a function_view with no associated target is undefined, 1048dffb485Schristos unlike with std::function, which throws std::bad_function_call. 1058dffb485Schristos This is by design, to avoid the otherwise necessary NULL check in 1068dffb485Schristos function_view::operator(). 1078dffb485Schristos 1088dffb485Schristos Since function_view objects are small (a pair of pointers), they 1098dffb485Schristos should generally be passed around by value. 1108dffb485Schristos 1118dffb485Schristos Usage: 1128dffb485Schristos 1138dffb485Schristos Given this function that accepts a callback: 1148dffb485Schristos 1158dffb485Schristos void 1168dffb485Schristos iterate_over_foos (gdb::function_view<void (foo *)> callback) 1178dffb485Schristos { 1188dffb485Schristos for (auto &foo : foos) 1198dffb485Schristos callback (&foo); 1208dffb485Schristos } 1218dffb485Schristos 1228dffb485Schristos you can call it like this, passing a lambda as callback: 1238dffb485Schristos 1248dffb485Schristos iterate_over_foos ([&] (foo *f) 1258dffb485Schristos { 1268dffb485Schristos process_one_foo (f); 1278dffb485Schristos }); 1288dffb485Schristos 1298dffb485Schristos or like this, passing a function object as callback: 1308dffb485Schristos 1318dffb485Schristos struct function_object 1328dffb485Schristos { 1338dffb485Schristos void operator() (foo *f) 1348dffb485Schristos { 1358dffb485Schristos if (s->check ()) 1368dffb485Schristos process_one_foo (f); 1378dffb485Schristos } 1388dffb485Schristos 1398dffb485Schristos // some state 1408dffb485Schristos state *s; 1418dffb485Schristos }; 1428dffb485Schristos 1438dffb485Schristos state mystate; 1448dffb485Schristos function_object matcher {&mystate}; 1458dffb485Schristos iterate_over_foos (matcher); 1468dffb485Schristos 1478dffb485Schristos or like this, passing a function pointer as callback: 1488dffb485Schristos 1498dffb485Schristos iterate_over_foos (process_one_foo); 1508dffb485Schristos 1514b169a6bSchristos There's also a gdb::make_function_view function that you can use to 1524b169a6bSchristos automatically create a function_view from a callable without having 1534b169a6bSchristos to specify the function_view's template parameter. E.g.: 1544b169a6bSchristos 1554b169a6bSchristos auto lambda = [&] (int) { ... }; 1564b169a6bSchristos auto fv = gdb::make_function_view (lambda); 1574b169a6bSchristos 1584b169a6bSchristos This can be useful for example when calling a template function 1594b169a6bSchristos whose function_view parameter type depends on the function's 1604b169a6bSchristos template parameters. In such case, you can't rely on implicit 1614b169a6bSchristos callable->function_view conversion for the function_view argument. 1624b169a6bSchristos You must pass a function_view argument already of the right type to 1634b169a6bSchristos the template function. E.g., with this: 1644b169a6bSchristos 1654b169a6bSchristos template<typename T> 1664b169a6bSchristos void my_function (T v, gdb::function_view<void(T)> callback = nullptr); 1674b169a6bSchristos 1684b169a6bSchristos this wouldn't compile: 1694b169a6bSchristos 1704b169a6bSchristos auto lambda = [&] (int) { ... }; 1714b169a6bSchristos my_function (1, lambda); 1724b169a6bSchristos 1734b169a6bSchristos Note that this immediately dangles the temporary lambda object: 1744b169a6bSchristos 1754b169a6bSchristos gdb::function_view<void(int)> fv = [&] (int) { ... }; // dangles 1764b169a6bSchristos my_function (fv); 1774b169a6bSchristos 1784b169a6bSchristos To avoid the dangling you'd have to use a named temporary for the 1794b169a6bSchristos lambda: 1804b169a6bSchristos 1814b169a6bSchristos auto lambda = [&] (int) { ... }; 1824b169a6bSchristos gdb::function_view<void(int)> fv = lambda; 1834b169a6bSchristos my_function (fv); 1844b169a6bSchristos 1854b169a6bSchristos Using gdb::make_function_view instead automatically deduces the 1864b169a6bSchristos function_view's full type, and, avoids worrying about dangling. For 1874b169a6bSchristos the example above, we could write instead: 1884b169a6bSchristos 1894b169a6bSchristos auto lambda = [&] (int) { ... }; 1904b169a6bSchristos my_function (1, gdb::make_function_view (lambda)); 1914b169a6bSchristos 1928dffb485Schristos You can find unit tests covering the whole API in 1938dffb485Schristos unittests/function-view-selftests.c. */ 1948dffb485Schristos 195*5ba1f45fSchristos #include <type_traits> 1968dffb485Schristos namespace gdb { 1978dffb485Schristos 1988dffb485Schristos namespace fv_detail { 1998dffb485Schristos /* Bits shared by all function_view instantiations that do not depend 2008dffb485Schristos on the template parameters. */ 2018dffb485Schristos 2028dffb485Schristos /* Storage for the erased callable. This is a union in order to be 2038dffb485Schristos able to save both a function object (data) pointer or a function 2048dffb485Schristos pointer without triggering undefined behavior. */ 2058dffb485Schristos union erased_callable 2068dffb485Schristos { 2078dffb485Schristos /* For function objects. */ 2088dffb485Schristos void *data; 2098dffb485Schristos 2108dffb485Schristos /* For function pointers. */ 2118dffb485Schristos void (*fn) (); 2128dffb485Schristos }; 2138dffb485Schristos 2148dffb485Schristos } /* namespace fv_detail */ 2158dffb485Schristos 2168dffb485Schristos /* Use partial specialization to get access to the callable's 2178dffb485Schristos signature. */ 2188dffb485Schristos template<class Signature> 2198dffb485Schristos struct function_view; 2208dffb485Schristos 2218dffb485Schristos template<typename Res, typename... Args> 2228dffb485Schristos class function_view<Res (Args...)> 2238dffb485Schristos { 2248dffb485Schristos template<typename From, typename To> 2258dffb485Schristos using CompatibleReturnType 2268dffb485Schristos = Or<std::is_void<To>, 2278dffb485Schristos std::is_same<From, To>, 2288dffb485Schristos std::is_convertible<From, To>>; 2298dffb485Schristos 2308dffb485Schristos /* True if Func can be called with Args, and either the result is 2318dffb485Schristos Res, convertible to Res or Res is void. */ 2328dffb485Schristos template<typename Callable, 233*5ba1f45fSchristos typename Res2 = typename std::invoke_result<Callable &, Args...>::type> 2348dffb485Schristos struct IsCompatibleCallable : CompatibleReturnType<Res2, Res> 2358dffb485Schristos {}; 2368dffb485Schristos 2378dffb485Schristos /* True if Callable is a function_view. Used to avoid hijacking the 2388dffb485Schristos copy ctor. */ 2398dffb485Schristos template <typename Callable> 2408dffb485Schristos struct IsFunctionView 2418dffb485Schristos : std::is_same<function_view, typename std::decay<Callable>::type> 2428dffb485Schristos {}; 2438dffb485Schristos 2448dffb485Schristos public: 2458dffb485Schristos 2468dffb485Schristos /* NULL by default. */ 2478dffb485Schristos constexpr function_view () noexcept 2488dffb485Schristos : m_erased_callable {}, 2498dffb485Schristos m_invoker {} 2508dffb485Schristos {} 2518dffb485Schristos 2528dffb485Schristos /* Default copy/assignment is fine. */ 2538dffb485Schristos function_view (const function_view &) = default; 2548dffb485Schristos function_view &operator= (const function_view &) = default; 2558dffb485Schristos 2568dffb485Schristos /* This is the main entry point. Use SFINAE to avoid hijacking the 2578dffb485Schristos copy constructor and to ensure that the target type is 2588dffb485Schristos compatible. */ 2598dffb485Schristos template 2608dffb485Schristos <typename Callable, 2618dffb485Schristos typename = Requires<Not<IsFunctionView<Callable>>>, 2628dffb485Schristos typename = Requires<IsCompatibleCallable<Callable>>> 2638dffb485Schristos function_view (Callable &&callable) noexcept 2648dffb485Schristos { 2658dffb485Schristos bind (callable); 2668dffb485Schristos } 2678dffb485Schristos 2688dffb485Schristos /* Construct a NULL function_view. */ 2698dffb485Schristos constexpr function_view (std::nullptr_t) noexcept 2708dffb485Schristos : m_erased_callable {}, 2718dffb485Schristos m_invoker {} 2728dffb485Schristos {} 2738dffb485Schristos 2748dffb485Schristos /* Clear a function_view. */ 2758dffb485Schristos function_view &operator= (std::nullptr_t) noexcept 2768dffb485Schristos { 2778dffb485Schristos m_invoker = nullptr; 2788dffb485Schristos return *this; 2798dffb485Schristos } 2808dffb485Schristos 2818dffb485Schristos /* Return true if the wrapper has a target, false otherwise. Note 2828dffb485Schristos we check M_INVOKER instead of M_ERASED_CALLABLE because we don't 2838dffb485Schristos know which member of the union is active right now. */ 2848dffb485Schristos constexpr explicit operator bool () const noexcept 2858dffb485Schristos { return m_invoker != nullptr; } 2868dffb485Schristos 2878dffb485Schristos /* Call the callable. */ 2888dffb485Schristos Res operator () (Args... args) const 2898dffb485Schristos { return m_invoker (m_erased_callable, std::forward<Args> (args)...); } 2908dffb485Schristos 2918dffb485Schristos private: 2928dffb485Schristos 2938dffb485Schristos /* Bind this function_view to a compatible function object 2948dffb485Schristos reference. */ 2958dffb485Schristos template <typename Callable> 2968dffb485Schristos void bind (Callable &callable) noexcept 2978dffb485Schristos { 2988dffb485Schristos m_erased_callable.data = (void *) std::addressof (callable); 2998dffb485Schristos m_invoker = [] (fv_detail::erased_callable ecall, Args... args) 3008dffb485Schristos noexcept (noexcept (callable (std::forward<Args> (args)...))) -> Res 3018dffb485Schristos { 3028dffb485Schristos auto &restored_callable = *static_cast<Callable *> (ecall.data); 3038dffb485Schristos /* The explicit cast to Res avoids a compile error when Res is 3048dffb485Schristos void and the callable returns non-void. */ 3058dffb485Schristos return (Res) restored_callable (std::forward<Args> (args)...); 3068dffb485Schristos }; 3078dffb485Schristos } 3088dffb485Schristos 3098dffb485Schristos /* Bind this function_view to a compatible function pointer. 3108dffb485Schristos 3118dffb485Schristos Making this a separate function allows avoiding one indirection, 3128dffb485Schristos by storing the function pointer directly in the storage, instead 3138dffb485Schristos of a pointer to pointer. erased_callable is then a union in 3148dffb485Schristos order to avoid storing a function pointer as a data pointer here, 3158dffb485Schristos which would be undefined. */ 3168dffb485Schristos template<class Res2, typename... Args2> 3178dffb485Schristos void bind (Res2 (*fn) (Args2...)) noexcept 3188dffb485Schristos { 3198dffb485Schristos m_erased_callable.fn = reinterpret_cast<void (*) ()> (fn); 3208dffb485Schristos m_invoker = [] (fv_detail::erased_callable ecall, Args... args) 3218dffb485Schristos noexcept (noexcept (fn (std::forward<Args> (args)...))) -> Res 3228dffb485Schristos { 3238dffb485Schristos auto restored_fn = reinterpret_cast<Res2 (*) (Args2...)> (ecall.fn); 3248dffb485Schristos /* The explicit cast to Res avoids a compile error when Res is 3258dffb485Schristos void and the callable returns non-void. */ 3268dffb485Schristos return (Res) restored_fn (std::forward<Args> (args)...); 3278dffb485Schristos }; 3288dffb485Schristos } 3298dffb485Schristos 3308dffb485Schristos /* Storage for the erased callable. */ 3318dffb485Schristos fv_detail::erased_callable m_erased_callable; 3328dffb485Schristos 3338dffb485Schristos /* The invoker. This is set to a capture-less lambda by one of the 3348dffb485Schristos 'bind' overloads. The lambda restores the right type of the 3358dffb485Schristos callable (which is passed as first argument), and forwards the 3368dffb485Schristos args. */ 3378dffb485Schristos Res (*m_invoker) (fv_detail::erased_callable, Args...); 3388dffb485Schristos }; 3398dffb485Schristos 3408dffb485Schristos /* Allow comparison with NULL. Defer the work to the in-class 3418dffb485Schristos operator bool implementation. */ 3428dffb485Schristos 3438dffb485Schristos template<typename Res, typename... Args> 3448dffb485Schristos constexpr inline bool 3458dffb485Schristos operator== (const function_view<Res (Args...)> &f, std::nullptr_t) noexcept 3468dffb485Schristos { return !static_cast<bool> (f); } 3478dffb485Schristos 3488dffb485Schristos template<typename Res, typename... Args> 3498dffb485Schristos constexpr inline bool 3508dffb485Schristos operator== (std::nullptr_t, const function_view<Res (Args...)> &f) noexcept 3518dffb485Schristos { return !static_cast<bool> (f); } 3528dffb485Schristos 3538dffb485Schristos template<typename Res, typename... Args> 3548dffb485Schristos constexpr inline bool 3558dffb485Schristos operator!= (const function_view<Res (Args...)> &f, std::nullptr_t) noexcept 3568dffb485Schristos { return static_cast<bool> (f); } 3578dffb485Schristos 3588dffb485Schristos template<typename Res, typename... Args> 3598dffb485Schristos constexpr inline bool 3608dffb485Schristos operator!= (std::nullptr_t, const function_view<Res (Args...)> &f) noexcept 3618dffb485Schristos { return static_cast<bool> (f); } 3628dffb485Schristos 3634b169a6bSchristos namespace fv_detail { 3644b169a6bSchristos 3654b169a6bSchristos /* Helper traits type to automatically find the right function_view 3664b169a6bSchristos type for a callable. */ 3674b169a6bSchristos 3684b169a6bSchristos /* Use partial specialization to get access to the callable's 3694b169a6bSchristos signature, for all the different callable variants. */ 3704b169a6bSchristos 3714b169a6bSchristos template<typename> 3724b169a6bSchristos struct function_view_traits; 3734b169a6bSchristos 3744b169a6bSchristos /* Main partial specialization with plain function signature type. 3754b169a6bSchristos All others end up redirected here. */ 3764b169a6bSchristos template<typename Res, typename... Args> 3774b169a6bSchristos struct function_view_traits<Res (Args...)> 3784b169a6bSchristos { 3794b169a6bSchristos using type = gdb::function_view<Res (Args...)>; 3804b169a6bSchristos }; 3814b169a6bSchristos 3824b169a6bSchristos /* Function pointers. */ 3834b169a6bSchristos template<typename Res, typename... Args> 3844b169a6bSchristos struct function_view_traits<Res (*) (Args...)> 3854b169a6bSchristos : function_view_traits<Res (Args...)> 3864b169a6bSchristos { 3874b169a6bSchristos }; 3884b169a6bSchristos 3894b169a6bSchristos /* Function references. */ 3904b169a6bSchristos template<typename Res, typename... Args> 3914b169a6bSchristos struct function_view_traits<Res (&) (Args...)> 3924b169a6bSchristos : function_view_traits<Res (Args...)> 3934b169a6bSchristos { 3944b169a6bSchristos }; 3954b169a6bSchristos 3964b169a6bSchristos /* Reference to function pointers. */ 3974b169a6bSchristos template<typename Res, typename... Args> 3984b169a6bSchristos struct function_view_traits<Res (*&) (Args...)> 3994b169a6bSchristos : function_view_traits<Res (Args...)> 4004b169a6bSchristos { 4014b169a6bSchristos }; 4024b169a6bSchristos 4034b169a6bSchristos /* Reference to const function pointers. */ 4044b169a6bSchristos template<typename Res, typename... Args> 4054b169a6bSchristos struct function_view_traits<Res (* const &) (Args...)> 4064b169a6bSchristos : function_view_traits<Res (Args...)> 4074b169a6bSchristos { 4084b169a6bSchristos }; 4094b169a6bSchristos 4104b169a6bSchristos /* Const member functions. function_view doesn't support these, but 4114b169a6bSchristos we need this in order to extract the type of function objects. 4124b169a6bSchristos Lambdas pass here, after starting at the operator() case, 4134b169a6bSchristos below. */ 4144b169a6bSchristos template<typename Res, typename Class, typename... Args> 4154b169a6bSchristos struct function_view_traits<Res (Class::*) (Args...) const> 4164b169a6bSchristos : function_view_traits<Res (Args...)> 4174b169a6bSchristos { 4184b169a6bSchristos }; 4194b169a6bSchristos 4204b169a6bSchristos /* Member functions. Ditto, for function objects with non-const 4214b169a6bSchristos operator(). */ 4224b169a6bSchristos template<typename Res, typename Class, typename... Args> 4234b169a6bSchristos struct function_view_traits<Res (Class::*) (Args...)> 4244b169a6bSchristos : function_view_traits<Res (Args...)> 4254b169a6bSchristos { 4264b169a6bSchristos }; 4274b169a6bSchristos 4284b169a6bSchristos /* Function objects, lambdas, std::function, any type that defines 4294b169a6bSchristos operator(). */ 4304b169a6bSchristos template<typename FuncObj> 4314b169a6bSchristos struct function_view_traits 4324b169a6bSchristos : function_view_traits <decltype 4334b169a6bSchristos (&std::remove_reference<FuncObj>::type::operator())> 4344b169a6bSchristos { 4354b169a6bSchristos }; 4364b169a6bSchristos 4374b169a6bSchristos } /* namespace fv_detail */ 4384b169a6bSchristos 4394b169a6bSchristos /* Make a function_view from a callable. Useful to automatically 4404b169a6bSchristos deduce the function_view's template argument type. */ 4414b169a6bSchristos template<typename Callable> 4424b169a6bSchristos auto make_function_view (Callable &&callable) 4434b169a6bSchristos -> typename fv_detail::function_view_traits<Callable>::type 4444b169a6bSchristos { 4454b169a6bSchristos using fv = typename fv_detail::function_view_traits<Callable>::type; 4464b169a6bSchristos return fv (std::forward<Callable> (callable)); 4474b169a6bSchristos } 4484b169a6bSchristos 4498dffb485Schristos } /* namespace gdb */ 4508dffb485Schristos 4518dffb485Schristos #endif 452