• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1.. _module-pw_function:
2
3===========
4pw_function
5===========
6.. pigweed-module::
7   :name: pw_function
8
9* **Familiar**. ``pw_function`` provides a standard, general-purpose API for
10  wrapping callable objects that's similar to `std::function`_.
11* **Optimized**. ``pw_function`` doesn't allocate (unless you want it to) and
12  uses several tricks to prevent code bloat.
13
14.. _std\:\:function: https://en.cppreference.com/w/cpp/utility/functional/function
15
16.. code-block:: c++
17
18   #include "pw_function/function.h"
19
20   // pw::Function can be constructed from a function pointer...
21   int _a(int a, int b) { return a + b; }
22   pw::Function<int(int, int)> add(_a);
23   // ... or a lambda.
24   pw::Function<int(int)> square([](int num) { return num * num; });
25
26   // pw::Callback can only be invoked once. After the first call, the target
27   // function is released and destroyed, along with any resources owned by
28   // that function.
29   pw::Callback<void(void)> flip_table_once([](void) {
30     // (╯°□°)╯︵ ┻━┻
31   });
32
33   add(5, 6);
34   add = nullptr;  // pw::Function and pw::Callback are nullable
35   add(7, 2);  // CRASH
36
37   square(4);
38
39   if (flip_table_once != nullptr) {  // Safe to call
40     flip_table_once();
41   } else {
42     // ┬─┬ノ( º _ ºノ)
43   }
44
45
46.. _module-pw_function-start:
47
48-----------
49Get started
50-----------
51.. tab-set::
52
53   .. tab-item:: Bazel
54
55      Add ``@pigweed//pw_function`` to your target's ``deps``:
56
57      .. code-block::
58
59         cc_library("...") {
60           # ...
61           deps = [
62             # ...
63             "@pigweed//pw_function",
64             # ...
65           ]
66         }
67
68      This assumes that your Bazel ``WORKSPACE`` has a `repository
69      <https://bazel.build/concepts/build-ref#repositories>`_ named ``@pigweed``
70      that points to the upstream Pigweed repository.
71
72   .. tab-item:: GN
73
74      Add ``$dir_pw_function`` to your target's ``deps``:
75
76      .. code-block::
77
78         pw_executable("...") {
79           # ...
80           deps = [
81             # ...
82             "$dir_pw_function",
83             # ...
84           ]
85         }
86
87   .. tab-item:: CMake
88
89      Link your library to ``pw_function``:
90
91      .. code-block::
92
93         add_library(my_lib ...)
94         target_link_libraries(my_lib PUBLIC pw_function)
95
96Use ``pw_function`` in your C++ code:
97
98.. code-block:: c++
99
100   #include "pw_function/function.h"
101
102   // ...
103
104.. _module-pw_function-guides:
105
106------
107Guides
108------
109
110Construct ``pw::Function`` from a function pointer
111==================================================
112:cpp:type:`pw::Function` is a move-only callable wrapper constructable from any
113callable object. It's templated on the signature of the callable it stores and
114implements the call operator; invoking a ``pw::Function`` object forwards to
115the stored callable.
116
117.. code-block:: c++
118
119   int Add(int a, int b) { return a + b; }
120
121   // Construct a Function object from a function pointer.
122   pw::Function<int(int, int)> add_function(Add);
123
124   // Invoke the function object.
125   int result = add_function(3, 5);
126   EXPECT_EQ(result, 8);
127
128Construct ``pw::Function`` from a lambda
129========================================
130.. code-block:: c++
131
132   // Construct a function from a lambda.
133   pw::Function<int(int)> negate([](int value) { return -value; });
134   EXPECT_EQ(negate(27), -27);
135
136Create single-use functions with ``pw::Callback``
137=================================================
138:cpp:type:`pw::Callback` is a specialization of :cpp:type:`pw::Function` that
139can only be called once. After a :cpp:type:`pw::Callback` is called, the target
140function is released and destroyed, along with any resources owned by that
141function. A :cpp:type:`pw::Callback` in the "already called" state
142has the same state as a :cpp:type:`pw::Function` that has been assigned to
143nullptr.
144
145.. code-block:: cpp
146
147   pw::Callback<void(void)> flip_table_once([](void) {
148     // (╯°□°)╯︵ ┻━┻
149   });
150
151   flip_table_once();  // OK
152   flip_table_once();  // CRASH
153
154Nullifying functions and comparing to null
155==========================================
156``pw::Function`` and ``pw::Callback`` are nullable and can be compared to
157``nullptr``. Invoking a null function triggers a runtime assert.
158
159.. code-block:: c++
160
161   // A function initialized without a callable is implicitly null.
162   pw::Function<void()> null_function;
163
164   // Null functions may also be explicitly created or set.
165   pw::Function<void()> explicit_null_function(nullptr);
166
167   pw::Function<void()> function([]() {});  // Valid (non-null) function.
168   function = nullptr;  // Set to null, clearing the stored callable.
169
170   // Functions are comparable to nullptr.
171   if (function != nullptr) {
172     function();
173   }
174
175``constexpr`` constructors and ``constinit`` expressions
176========================================================
177The default constructor for :cpp:type:`pw::Function` is ``constexpr``, so
178default-constructed functions may be used in classes with ``constexpr``
179constructors and in ``constinit`` expressions.
180
181.. code-block:: c++
182
183   class MyClass {
184    public:
185     // Default construction of a pw::Function is constexpr.
186     constexpr MyClass() { ... }
187
188     pw::Function<void(int)> my_function;
189   };
190
191   // pw::Function and classes that use it may be constant initialized.
192   constinit MyClass instance;
193
194``pw::Function`` as a function parameter
195========================================
196When implementing an API which uses callbacks, ``pw::Function`` can be used in
197place of a function pointer or equivalent callable.
198
199.. code-block:: c++
200
201   // Before:
202   void DoTheThing(int arg, void (*callback)(int result));
203
204   // After:
205   void DoTheThing(int arg, const pw::Function<void(int result)>& callback);
206   // Note the parameter name within the function signature template for clarity.
207
208.. _module-pw_function-move-semantics:
209
210Move semantics
211==============
212:cpp:type:`pw::Function` is movable, but not copyable, so APIs must accept
213:cpp:type:`pw::Function` objects either by const reference (``const
214pw::Function<void()>&``) or rvalue reference (``const pw::Function<void()>&&``).
215If the :cpp:type:`pw::Function` simply needs to be called, it should be passed
216by const reference. If the :cpp:type:`pw::Function` needs to be stored, it
217should be passed as an rvalue reference and moved into a
218:cpp:type:`pw::Function` variable as appropriate.
219
220.. code-block:: c++
221
222   // This function calls a pw::Function but doesn't store it, so it takes a
223   // const reference.
224   void CallTheCallback(const pw::Function<void(int)>& callback) {
225     callback(123);
226   }
227
228   // This function move-assigns a pw::Function to another variable, so it takes
229   // an rvalue reference.
230   void StoreTheCallback(pw::Function<void(int)>&& callback) {
231     stored_callback_ = std::move(callback);
232   }
233
234.. admonition:: Rules of thumb for passing a :cpp:type:`pw::Function` to a function
235
236   * **Pass by value**: Never.
237     This results in unnecessary :cpp:type:`pw::Function` instances and move
238     operations.
239
240   * **Pass by const reference** (``const pw::Function&``): When the
241     :cpp:type:`pw::Function` is only invoked.
242
243     When a :cpp:type:`pw::Function` is called or inspected, but not moved, take
244     a const reference to avoid copies and support temporaries.
245
246   * **Pass by rvalue reference** (``pw::Function&&``): When the
247     :cpp:type:`pw::Function` is moved.
248
249     When the function takes ownership of the :cpp:type:`pw::Function` object,
250     always use an rvalue reference (``pw::Function<void()>&&``) instead of a
251     mutable lvalue reference (``pw::Function<void()>&``). An rvalue reference
252     forces the caller to ``std::move`` when passing a preexisting
253     :cpp:type:`pw::Function` variable, which makes the transfer of ownership
254     explicit. It is possible to move-assign from an lvalue reference, but this
255     fails to make it obvious to the caller that the object is no longer valid.
256
257   * **Pass by non-const reference** (``pw::Function&``): Rarely, when modifying
258     a variable.
259
260     Non-const references are only necessary when modifying an existing
261     :cpp:type:`pw::Function` variable. Use an rvalue reference instead if the
262     :cpp:type:`pw::Function` is moved into another variable.
263
264Calling functions that use ``pw::Function``
265===========================================
266A :cpp:type:`pw::Function` can be implicitly constructed from any callback
267object. When calling an API that takes a :cpp:type:`pw::Function`, simply pass
268the callable object.  There is no need to create an intermediate
269:cpp:type:`pw::Function` object.
270
271.. code-block:: c++
272
273   // Implicitly creates a pw::Function from a capturing lambda and calls it.
274   CallTheCallback([this](int result) { result_ = result; });
275
276   // Implicitly creates a pw::Function from a capturing lambda and stores it.
277   StoreTheCallback([this](int result) { result_ = result; });
278
279When working with an existing :cpp:type:`pw::Function` variable, the variable
280can be passed directly to functions that take a const reference. If the function
281takes ownership of the :cpp:type:`pw::Function`, move the
282:cpp:type:`pw::Function` variable at the call site.
283
284.. code-block:: c++
285
286   // Accepts the pw::Function by const reference.
287   CallTheCallback(my_function_);
288
289   // Takes ownership of the pw::Function.
290   void StoreTheCallback(std::move(my_function));
291
292Managing inline storage size
293============================
294By default, ``pw::Function`` stores its callable inline within the object. The
295inline storage size defaults to the size of one pointer, but is configurable
296through the build system.
297
298:cpp:type:`pw::InlineFunction` is similar to ``pw::Function``,
299but is always inlined. That is, even if dynamic allocation is enabled for
300``pw::Function``, ``pw::InlineFunction`` will fail to compile if
301the callable is larger than the inline storage size.
302
303Attempting to construct a function from a callable larger than its inline size
304is a compile-time error unless dynamic allocation is enabled.
305
306.. admonition:: Inline storage size
307
308   The default inline size of one pointer is sufficient to store most common
309   callable objects, including function pointers, simple non-capturing and
310   capturing lambdas, and lightweight custom classes.
311
312.. code-block:: c++
313
314   // The lambda is moved into the function's internal storage.
315   pw::Function<int(int, int)> subtract([](int a, int b) { return a - b; });
316
317   // Functions can be also be constructed from custom classes that implement
318   // operator(). This particular object is large (8 ints of space).
319   class MyCallable {
320    public:
321     int operator()(int value);
322
323    private:
324     int data_[8];
325   };
326
327   // Compiler error: sizeof(MyCallable) exceeds function's inline storage size.
328   pw::Function<int(int)> function((MyCallable()));
329
330Dynamic allocation
331==================
332You can configure the inline allocation size of ``pw::Function`` and whether it
333dynamically allocates, but it applies to all uses of ``pw::Function``.
334
335As mentioned in :ref:`module-pw_function-design`, ``pw::Function`` is an alias
336of Fuchsia's ``fit::function``. ``fit::function`` allows you to specify the
337inline (static) allocation size and whether to dynamically allocate if the
338callable target doesn't inline. If you want to use a function class with
339different attributes, you can interact with ``fit::function`` directly but note
340that the resulting functions may not be interchangeable, i.e. callables for one
341might not fit in the other.
342
343When ``PW_FUNCTION_ENABLE_DYNAMIC_ALLOCATION`` is enabled, a ``pw::Function``
344will use dynamic allocation to store callables that exceed the inline size.
345An :ref:`allocator <module-pw_allocator>` type can be optionally supplied as a
346template argument. The default allocator type can also be changed by overriding
347``PW_FUNCTION_DEFAULT_ALLOCATOR_TYPE`` (the ``value_type`` of the allocator
348is irrelevant, since it must support rebinding). When dynamic allocation is
349enabled but a compile-time check for the inlining is still required,
350``pw::InlineFunction`` can be used.
351
352.. warning::
353
354   If ``PW_FUNCTION_ENABLE_DYNAMIC_ALLOCATION`` is enabled then attempts to
355   cast from :cpp:type:`pw::InlineFunction` to a regular
356   :cpp:type:`pw::Function` will **ALWAYS** allocate memory.
357
358Invoking ``pw::Function`` from a C-style API
359============================================
360.. _trampoline layers: https://en.wikipedia.org/wiki/Trampoline_(computing)
361
362One use case for invoking ``pw_function`` from a C-style API is to automate the
363generation of `trampoline layers`_. See
364:cpp:type:`pw::function::GetFunctionPointer()`.
365
366.. _module-pw_function-reference:
367
368-------------
369API reference
370-------------
371
372``pw::Function``
373================
374.. doxygentypedef:: pw::Function
375
376``pw::InlineFunction``
377======================
378.. doxygentypedef:: pw::InlineFunction
379
380``pw::Callback``
381================
382.. doxygentypedef:: pw::Callback
383
384``pw::InlineCallback``
385======================
386.. doxygentypedef:: pw::InlineCallback
387
388``pw::bind_member()``
389=====================
390.. doxygenfunction:: pw::bind_member
391
392``pw::function::GetFunctionPointer()``
393======================================
394.. doxygenfile:: pw_function/pointer.h
395   :sections: detaileddescription
396.. doxygenfunction:: GetFunctionPointer()
397.. doxygenfunction:: GetFunctionPointer(const FunctionType&)
398
399``pw::function::GetFunctionPointerContextFirst()``
400==================================================
401.. doxygenfunction:: GetFunctionPointerContextFirst()
402.. doxygenfunction:: GetFunctionPointerContextFirst(const FunctionType&)
403
404``pw::ScopeGuard``
405==================
406.. doxygenclass:: pw::ScopeGuard
407   :members:
408
409.. _module-pw_function-design:
410
411------
412Design
413------
414``pw::Function`` is an alias of Fuchsia's ``fit::function_impl`` and
415``pw::Callback`` is an alias of Fuchsia's ``fit::callback_impl``. See the
416following links for more information about Fuchsia's implementations:
417
418* `//third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/function.h <https://cs.opensource.google/pigweed/pigweed/+/main:third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/function.h>`_
419* `fit::function <https://fuchsia.googlesource.com/fuchsia/+/HEAD/sdk/lib/fit/#fit_function>`_
420
421.. _module-pw_function-non-literal:
422
423Why ``pw::Function`` is not a literal
424=====================================
425The default constructor for ``pw::Function`` is ``constexpr`` but
426``pw::Function`` is not a literal type. Instances can be declared ``constinit``
427but can't be used in ``constexpr`` contexts. There are a few reasons for this:
428
429* ``pw::Function`` supports wrapping any callable type, and the wrapped type
430  might not be a literal type.
431* ``pw::Function`` stores inline callables in a bytes array, which is not
432  ``constexpr``-friendly.
433* ``pw::Function`` optionally uses dynamic allocation, which doesn't work in
434  ``constexpr`` contexts (at least before C++20).
435
436------------
437Size reports
438------------
439
440Comparing ``pw::Function`` to a traditional function pointer
441============================================================
442The following size report compares an API using a :cpp:type:`pw::Function` to a
443traditional function pointer.
444
445.. include:: function_size
446
447Typical sizes of various callable types
448=======================================
449The table below demonstrates typical sizes of various callable types, which can
450be used as a reference when sizing external buffers for ``pw::Function``
451objects.
452
453.. include:: callable_size
454