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