function-view.h revision 1.1.1.2 1 1.1.1.2 christos /* Copyright (C) 2017-2023 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 christos #ifndef COMMON_FUNCTION_VIEW_H
19 1.1 christos #define COMMON_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.2 christos #include "invoke-result.h"
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.2 christos typename Res2 = typename gdb::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 christos #endif
452