|  | /* Copyright (C) 2017-2023 Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of GDB. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | #ifndef COMMON_FUNCTION_VIEW_H | 
|  | #define COMMON_FUNCTION_VIEW_H | 
|  |  | 
|  | /* function_view is a polymorphic type-erasing wrapper class that | 
|  | encapsulates a non-owning reference to arbitrary callable objects. | 
|  |  | 
|  | A way to put it is that function_view is to std::function like | 
|  | std::string_view is to std::string.  While std::function stores a | 
|  | type-erased callable object internally, function_view holds a | 
|  | type-erased reference to an external callable object. | 
|  |  | 
|  | This is meant to be used as callback type of a function that: | 
|  |  | 
|  | #1 - Takes a callback as parameter. | 
|  |  | 
|  | #2 - Wants to support arbitrary callable objects as callback type | 
|  | (e.g., stateful function objects, lambda closures, free | 
|  | functions). | 
|  |  | 
|  | #3 - Does not store the callback anywhere; instead the function | 
|  | just calls the callback directly or forwards it to some | 
|  | other function that calls it. | 
|  |  | 
|  | #4 - Can't be, or we don't want it to be, a template function | 
|  | with the callable type as template parameter.  For example, | 
|  | when the callback is a parameter of a virtual member | 
|  | function, or when putting the function template in a header | 
|  | would expose too much implementation detail. | 
|  |  | 
|  | Note that the C-style "function pointer" + "void *data" callback | 
|  | parameter idiom fails requirement #2 above.  Please don't add new | 
|  | uses of that idiom.  I.e., something like this wouldn't work; | 
|  |  | 
|  | typedef bool (iterate_over_foos_cb) (foo *f, void *user_data), | 
|  | void iterate_over_foos (iterate_over_foos_cb *callback, void *user_data); | 
|  |  | 
|  | foo *find_foo_by_type (int type) | 
|  | { | 
|  | foo *found = nullptr; | 
|  |  | 
|  | iterate_over_foos ([&] (foo *f, void *data) | 
|  | { | 
|  | if (foo->type == type) | 
|  | { | 
|  | found = foo; | 
|  | return true; // stop iterating | 
|  | } | 
|  | return false; // continue iterating | 
|  | }, NULL); | 
|  |  | 
|  | return found; | 
|  | } | 
|  |  | 
|  | The above wouldn't compile, because lambdas with captures can't be | 
|  | implicitly converted to a function pointer (because a capture means | 
|  | some context data must be passed to the lambda somehow). | 
|  |  | 
|  | C++11 gave us std::function as type-erased wrapper around arbitrary | 
|  | callables, however, std::function is not an ideal fit for transient | 
|  | callbacks such as the use case above.  For this use case, which is | 
|  | quite pervasive, a function_view is a better choice, because while | 
|  | function_view is light and does not require any heap allocation, | 
|  | std::function is a heavy-weight object with value semantics that | 
|  | generally requires a heap allocation on construction/assignment of | 
|  | the target callable.  In addition, while it is possible to use | 
|  | std::function in such a way that avoids most of the overhead by | 
|  | making sure to only construct it with callables of types that fit | 
|  | std::function's small object optimization, such as function | 
|  | pointers and std::reference_wrapper callables, that is quite | 
|  | inconvenient in practice, because restricting to free-function | 
|  | callables would imply no state/capture/closure, which we need in | 
|  | most cases, and std::reference_wrapper implies remembering to use | 
|  | std::ref/std::cref where the callable is constructed, with the | 
|  | added inconvenience that std::ref/std::cref have deleted rvalue-ref | 
|  | overloads, meaning you can't use unnamed/temporary lambdas with | 
|  | them. | 
|  |  | 
|  | Note that because function_view is a non-owning view of a callable, | 
|  | care must be taken to ensure that the callable outlives the | 
|  | function_view that calls it.  This is not really a problem for the | 
|  | use case function_view is intended for, such as passing a temporary | 
|  | function object / lambda to a function that accepts a callback, | 
|  | because in those cases, the temporary is guaranteed to be live | 
|  | until the called function returns. | 
|  |  | 
|  | Calling a function_view with no associated target is undefined, | 
|  | unlike with std::function, which throws std::bad_function_call. | 
|  | This is by design, to avoid the otherwise necessary NULL check in | 
|  | function_view::operator(). | 
|  |  | 
|  | Since function_view objects are small (a pair of pointers), they | 
|  | should generally be passed around by value. | 
|  |  | 
|  | Usage: | 
|  |  | 
|  | Given this function that accepts a callback: | 
|  |  | 
|  | void | 
|  | iterate_over_foos (gdb::function_view<void (foo *)> callback) | 
|  | { | 
|  | for (auto &foo : foos) | 
|  | callback (&foo); | 
|  | } | 
|  |  | 
|  | you can call it like this, passing a lambda as callback: | 
|  |  | 
|  | iterate_over_foos ([&] (foo *f) | 
|  | { | 
|  | process_one_foo (f); | 
|  | }); | 
|  |  | 
|  | or like this, passing a function object as callback: | 
|  |  | 
|  | struct function_object | 
|  | { | 
|  | void operator() (foo *f) | 
|  | { | 
|  | if (s->check ()) | 
|  | process_one_foo (f); | 
|  | } | 
|  |  | 
|  | // some state | 
|  | state *s; | 
|  | }; | 
|  |  | 
|  | state mystate; | 
|  | function_object matcher {&mystate}; | 
|  | iterate_over_foos (matcher); | 
|  |  | 
|  | or like this, passing a function pointer as callback: | 
|  |  | 
|  | iterate_over_foos (process_one_foo); | 
|  |  | 
|  | There's also a gdb::make_function_view function that you can use to | 
|  | automatically create a function_view from a callable without having | 
|  | to specify the function_view's template parameter.  E.g.: | 
|  |  | 
|  | auto lambda = [&] (int) { ... }; | 
|  | auto fv = gdb::make_function_view (lambda); | 
|  |  | 
|  | This can be useful for example when calling a template function | 
|  | whose function_view parameter type depends on the function's | 
|  | template parameters.  In such case, you can't rely on implicit | 
|  | callable->function_view conversion for the function_view argument. | 
|  | You must pass a function_view argument already of the right type to | 
|  | the template function.  E.g., with this: | 
|  |  | 
|  | template<typename T> | 
|  | void my_function (T v, gdb::function_view<void(T)> callback = nullptr); | 
|  |  | 
|  | this wouldn't compile: | 
|  |  | 
|  | auto lambda = [&] (int) { ... }; | 
|  | my_function (1, lambda); | 
|  |  | 
|  | Note that this immediately dangles the temporary lambda object: | 
|  |  | 
|  | gdb::function_view<void(int)> fv = [&] (int) { ... };  // dangles | 
|  | my_function (fv); | 
|  |  | 
|  | To avoid the dangling you'd have to use a named temporary for the | 
|  | lambda: | 
|  |  | 
|  | auto lambda = [&] (int) { ... }; | 
|  | gdb::function_view<void(int)> fv = lambda; | 
|  | my_function (fv); | 
|  |  | 
|  | Using gdb::make_function_view instead automatically deduces the | 
|  | function_view's full type, and, avoids worrying about dangling.  For | 
|  | the example above, we could write instead: | 
|  |  | 
|  | auto lambda = [&] (int) { ... }; | 
|  | my_function (1, gdb::make_function_view (lambda)); | 
|  |  | 
|  | You can find unit tests covering the whole API in | 
|  | unittests/function-view-selftests.c.  */ | 
|  |  | 
|  | #include <type_traits> | 
|  | namespace gdb { | 
|  |  | 
|  | namespace fv_detail { | 
|  | /* Bits shared by all function_view instantiations that do not depend | 
|  | on the template parameters.  */ | 
|  |  | 
|  | /* Storage for the erased callable.  This is a union in order to be | 
|  | able to save both a function object (data) pointer or a function | 
|  | pointer without triggering undefined behavior.  */ | 
|  | union erased_callable | 
|  | { | 
|  | /* For function objects.  */ | 
|  | void *data; | 
|  |  | 
|  | /* For function pointers.  */ | 
|  | void (*fn) (); | 
|  | }; | 
|  |  | 
|  | } /* namespace fv_detail */ | 
|  |  | 
|  | /* Use partial specialization to get access to the callable's | 
|  | signature. */ | 
|  | template<class Signature> | 
|  | struct function_view; | 
|  |  | 
|  | template<typename Res, typename... Args> | 
|  | class function_view<Res (Args...)> | 
|  | { | 
|  | template<typename From, typename To> | 
|  | using CompatibleReturnType | 
|  | = Or<std::is_void<To>, | 
|  | std::is_same<From, To>, | 
|  | std::is_convertible<From, To>>; | 
|  |  | 
|  | /* True if Func can be called with Args, and either the result is | 
|  | Res, convertible to Res or Res is void.  */ | 
|  | template<typename Callable, | 
|  | typename Res2 = typename std::invoke_result<Callable &, Args...>::type> | 
|  | struct IsCompatibleCallable : CompatibleReturnType<Res2, Res> | 
|  | {}; | 
|  |  | 
|  | /* True if Callable is a function_view.  Used to avoid hijacking the | 
|  | copy ctor.  */ | 
|  | template <typename Callable> | 
|  | struct IsFunctionView | 
|  | : std::is_same<function_view, typename std::decay<Callable>::type> | 
|  | {}; | 
|  |  | 
|  | public: | 
|  |  | 
|  | /* NULL by default.  */ | 
|  | constexpr function_view () noexcept | 
|  | : m_erased_callable {}, | 
|  | m_invoker {} | 
|  | {} | 
|  |  | 
|  | /* Default copy/assignment is fine.  */ | 
|  | function_view (const function_view &) = default; | 
|  | function_view &operator= (const function_view &) = default; | 
|  |  | 
|  | /* This is the main entry point.  Use SFINAE to avoid hijacking the | 
|  | copy constructor and to ensure that the target type is | 
|  | compatible.  */ | 
|  | template | 
|  | <typename Callable, | 
|  | typename = Requires<Not<IsFunctionView<Callable>>>, | 
|  | typename = Requires<IsCompatibleCallable<Callable>>> | 
|  | function_view (Callable &&callable) noexcept | 
|  | { | 
|  | bind (callable); | 
|  | } | 
|  |  | 
|  | /* Construct a NULL function_view.  */ | 
|  | constexpr function_view (std::nullptr_t) noexcept | 
|  | : m_erased_callable {}, | 
|  | m_invoker {} | 
|  | {} | 
|  |  | 
|  | /* Clear a function_view.  */ | 
|  | function_view &operator= (std::nullptr_t) noexcept | 
|  | { | 
|  | m_invoker = nullptr; | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | /* Return true if the wrapper has a target, false otherwise.  Note | 
|  | we check M_INVOKER instead of M_ERASED_CALLABLE because we don't | 
|  | know which member of the union is active right now.  */ | 
|  | constexpr explicit operator bool () const noexcept | 
|  | { return m_invoker != nullptr; } | 
|  |  | 
|  | /* Call the callable.  */ | 
|  | Res operator () (Args... args) const | 
|  | { return m_invoker (m_erased_callable, std::forward<Args> (args)...); } | 
|  |  | 
|  | private: | 
|  |  | 
|  | /* Bind this function_view to a compatible function object | 
|  | reference.  */ | 
|  | template <typename Callable> | 
|  | void bind (Callable &callable) noexcept | 
|  | { | 
|  | m_erased_callable.data = (void *) std::addressof (callable); | 
|  | m_invoker = [] (fv_detail::erased_callable ecall, Args... args) | 
|  | noexcept (noexcept (callable (std::forward<Args> (args)...))) -> Res | 
|  | { | 
|  | auto &restored_callable = *static_cast<Callable *> (ecall.data); | 
|  | /* The explicit cast to Res avoids a compile error when Res is | 
|  | void and the callable returns non-void.  */ | 
|  | return (Res) restored_callable (std::forward<Args> (args)...); | 
|  | }; | 
|  | } | 
|  |  | 
|  | /* Bind this function_view to a compatible function pointer. | 
|  |  | 
|  | Making this a separate function allows avoiding one indirection, | 
|  | by storing the function pointer directly in the storage, instead | 
|  | of a pointer to pointer.  erased_callable is then a union in | 
|  | order to avoid storing a function pointer as a data pointer here, | 
|  | which would be undefined.  */ | 
|  | template<class Res2, typename... Args2> | 
|  | void bind (Res2 (*fn) (Args2...)) noexcept | 
|  | { | 
|  | m_erased_callable.fn = reinterpret_cast<void (*) ()> (fn); | 
|  | m_invoker = [] (fv_detail::erased_callable ecall, Args... args) | 
|  | noexcept (noexcept (fn (std::forward<Args> (args)...))) -> Res | 
|  | { | 
|  | auto restored_fn = reinterpret_cast<Res2 (*) (Args2...)> (ecall.fn); | 
|  | /* The explicit cast to Res avoids a compile error when Res is | 
|  | void and the callable returns non-void.  */ | 
|  | return (Res) restored_fn (std::forward<Args> (args)...); | 
|  | }; | 
|  | } | 
|  |  | 
|  | /* Storage for the erased callable.  */ | 
|  | fv_detail::erased_callable m_erased_callable; | 
|  |  | 
|  | /* The invoker.  This is set to a capture-less lambda by one of the | 
|  | 'bind' overloads.  The lambda restores the right type of the | 
|  | callable (which is passed as first argument), and forwards the | 
|  | args.  */ | 
|  | Res (*m_invoker) (fv_detail::erased_callable, Args...); | 
|  | }; | 
|  |  | 
|  | /* Allow comparison with NULL.  Defer the work to the in-class | 
|  | operator bool implementation.  */ | 
|  |  | 
|  | template<typename Res, typename... Args> | 
|  | constexpr inline bool | 
|  | operator== (const function_view<Res (Args...)> &f, std::nullptr_t) noexcept | 
|  | { return !static_cast<bool> (f); } | 
|  |  | 
|  | template<typename Res, typename... Args> | 
|  | constexpr inline bool | 
|  | operator== (std::nullptr_t, const function_view<Res (Args...)> &f) noexcept | 
|  | { return !static_cast<bool> (f); } | 
|  |  | 
|  | template<typename Res, typename... Args> | 
|  | constexpr inline bool | 
|  | operator!= (const function_view<Res (Args...)> &f, std::nullptr_t) noexcept | 
|  | { return static_cast<bool> (f); } | 
|  |  | 
|  | template<typename Res, typename... Args> | 
|  | constexpr inline bool | 
|  | operator!= (std::nullptr_t, const function_view<Res (Args...)> &f) noexcept | 
|  | { return static_cast<bool> (f); } | 
|  |  | 
|  | namespace fv_detail { | 
|  |  | 
|  | /* Helper traits type to automatically find the right function_view | 
|  | type for a callable.  */ | 
|  |  | 
|  | /* Use partial specialization to get access to the callable's | 
|  | signature, for all the different callable variants.  */ | 
|  |  | 
|  | template<typename> | 
|  | struct function_view_traits; | 
|  |  | 
|  | /* Main partial specialization with plain function signature type. | 
|  | All others end up redirected here.  */ | 
|  | template<typename Res, typename... Args> | 
|  | struct function_view_traits<Res (Args...)> | 
|  | { | 
|  | using type = gdb::function_view<Res (Args...)>; | 
|  | }; | 
|  |  | 
|  | /* Function pointers.  */ | 
|  | template<typename Res, typename... Args> | 
|  | struct function_view_traits<Res (*) (Args...)> | 
|  | : function_view_traits<Res (Args...)> | 
|  | { | 
|  | }; | 
|  |  | 
|  | /* Function references.  */ | 
|  | template<typename Res, typename... Args> | 
|  | struct function_view_traits<Res (&) (Args...)> | 
|  | : function_view_traits<Res (Args...)> | 
|  | { | 
|  | }; | 
|  |  | 
|  | /* Reference to function pointers.  */ | 
|  | template<typename Res, typename... Args> | 
|  | struct function_view_traits<Res (*&) (Args...)> | 
|  | : function_view_traits<Res (Args...)> | 
|  | { | 
|  | }; | 
|  |  | 
|  | /* Reference to const function pointers.  */ | 
|  | template<typename Res, typename... Args> | 
|  | struct function_view_traits<Res (* const &) (Args...)> | 
|  | : function_view_traits<Res (Args...)> | 
|  | { | 
|  | }; | 
|  |  | 
|  | /* Const member functions.  function_view doesn't support these, but | 
|  | we need this in order to extract the type of function objects. | 
|  | Lambdas pass here, after starting at the operator() case, | 
|  | below.  */ | 
|  | template<typename Res, typename Class, typename... Args> | 
|  | struct function_view_traits<Res (Class::*) (Args...) const> | 
|  | : function_view_traits<Res (Args...)> | 
|  | { | 
|  | }; | 
|  |  | 
|  | /* Member functions.  Ditto, for function objects with non-const | 
|  | operator().  */ | 
|  | template<typename Res, typename Class, typename... Args> | 
|  | struct function_view_traits<Res (Class::*) (Args...)> | 
|  | : function_view_traits<Res (Args...)> | 
|  | { | 
|  | }; | 
|  |  | 
|  | /* Function objects, lambdas, std::function, any type that defines | 
|  | operator().  */ | 
|  | template<typename FuncObj> | 
|  | struct function_view_traits | 
|  | : function_view_traits <decltype | 
|  | (&std::remove_reference<FuncObj>::type::operator())> | 
|  | { | 
|  | }; | 
|  |  | 
|  | } /* namespace fv_detail */ | 
|  |  | 
|  | /* Make a function_view from a callable.  Useful to automatically | 
|  | deduce the function_view's template argument type.  */ | 
|  | template<typename Callable> | 
|  | auto make_function_view (Callable &&callable) | 
|  | -> typename fv_detail::function_view_traits<Callable>::type | 
|  | { | 
|  | using fv = typename fv_detail::function_view_traits<Callable>::type; | 
|  | return fv (std::forward<Callable> (callable)); | 
|  | } | 
|  |  | 
|  | } /* namespace gdb */ | 
|  |  | 
|  | #endif |