• 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.. literalinclude:: function_test.cc
313   :language: cpp
314   :start-after: [pw_function-inline-storage-example]
315   :end-before: [pw_function-inline-storage-example]
316
317.. _module-pw_function-dynamic-allocation:
318
319Dynamic allocation
320==================
321You can configure the inline allocation size of :cpp:class:`pw::Function` and
322whether it dynamically allocates, but it applies to all uses of
323``pw::Function``. If dynamic allocation is required, use
324:cpp:class:`pw::DynamicFunction`. Note that using multiple variations of
325:cpp:class:`pw::Function` increases code size, and conversions between them may
326not be efficient or possible in all cases.
327
328As mentioned in :ref:`module-pw_function-design`, ``pw::Function`` is an alias
329of Fuchsia's ``fit::function``. ``fit::function`` allows you to specify the
330inline (static) allocation size and whether to dynamically allocate if the
331callable target doesn't inline. If you want to use a function class with
332different attributes, you can interact with ``fit::function`` directly but note
333that the resulting functions may not be interchangeable, i.e. callables for one
334might not fit in the other.
335
336When ``PW_FUNCTION_ENABLE_DYNAMIC_ALLOCATION`` is enabled, a ``pw::Function``
337will use dynamic allocation to store callables that exceed the inline size.
338An :ref:`allocator <module-pw_allocator>` type can be optionally supplied as a
339template argument. The default allocator type can also be changed by overriding
340``PW_FUNCTION_DEFAULT_ALLOCATOR_TYPE`` (the ``value_type`` of the allocator
341is irrelevant, since it must support rebinding). When dynamic allocation is
342enabled but a compile-time check for the inlining is still required,
343``pw::InlineFunction`` can be used.
344
345.. warning::
346
347   If ``PW_FUNCTION_ENABLE_DYNAMIC_ALLOCATION`` is enabled then attempts to
348   cast from :cpp:type:`pw::InlineFunction` to a regular
349   :cpp:type:`pw::Function` will **ALWAYS** allocate memory.
350
351.. note::
352
353   When building Pigweed itself for host platforms, we enable dynamic
354   allocation.  This is required for some modules that use ``pw::Function``,
355   like :ref:`module-pw_bluetooth_sapphire`.  But it is *not* the default for
356   downstream projects because it introduces a difference between host and
357   non-host builds. This difference has the potential to cause breakages if
358   code is built for host first, and then later ported to device.
359
360Invoking ``pw::Function`` from a C-style API
361============================================
362When invoking a :cpp:class:`pw::Function` from a C-style API, a `trampoline
363layer <https://en.wikipedia.org/wiki/Trampoline_(computing)>`_ may be necessary.
364Use :cpp:type:`pw::function::GetFunctionPointer()` to generate a trampoline
365layer for a :cpp:class:`pw::Function` automatically.
366
367.. _module-pw_function-reference:
368
369-------------
370API reference
371-------------
372.. doxygengroup:: pw_function
373   :content-only:
374
375``pw::function::GetFunctionPointer()``
376======================================
377.. doxygenfile:: pw_function/pointer.h
378   :sections: detaileddescription
379.. doxygenfunction:: GetFunctionPointer()
380.. doxygenfunction:: GetFunctionPointer(const FunctionType&)
381
382``pw::function::GetFunctionPointerContextFirst()``
383==================================================
384.. doxygenfunction:: GetFunctionPointerContextFirst()
385.. doxygenfunction:: GetFunctionPointerContextFirst(const FunctionType&)
386
387``pw::ScopeGuard``
388==================
389.. doxygenclass:: pw::ScopeGuard
390   :members:
391
392.. _module-pw_function-design:
393
394------
395Design
396------
397``pw::Function`` is an alias of Fuchsia's ``fit::function_impl`` and
398``pw::Callback`` is an alias of Fuchsia's ``fit::callback_impl``. See the
399following links for more information about Fuchsia's implementations:
400
401* `//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>`_
402* `fit::function <https://fuchsia.googlesource.com/fuchsia/+/HEAD/sdk/lib/fit/#fit_function>`_
403
404.. _module-pw_function-non-literal:
405
406Why ``pw::Function`` is not a literal
407=====================================
408The default constructor for ``pw::Function`` is ``constexpr`` but
409``pw::Function`` is not a literal type. Instances can be declared ``constinit``
410but can't be used in ``constexpr`` contexts. There are a few reasons for this:
411
412* ``pw::Function`` supports wrapping any callable type, and the wrapped type
413  might not be a literal type.
414* ``pw::Function`` stores inline callables in a bytes array, which is not
415  ``constexpr``-friendly.
416* ``pw::Function`` optionally uses dynamic allocation, which doesn't work in
417  ``constexpr`` contexts (at least before C++20).
418
419------------
420Size reports
421------------
422
423Comparing ``pw::Function`` to a traditional function pointer
424============================================================
425The following size report compares an API using a :cpp:type:`pw::Function` to a
426traditional function pointer.
427
428.. TODO: b/388905812 - Re-enable the size report.
429.. .. include:: function_size
430.. include:: ../size_report_notice
431
432Typical sizes of various callable types
433=======================================
434The table below demonstrates typical sizes of various callable types, which can
435be used as a reference when sizing external buffers for ``pw::Function``
436objects.
437
438.. TODO: b/388905812 - Re-enable the size report.
439.. .. include:: callable_size
440.. include:: ../size_report_notice
441