• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1.. _module-pw_function:
2
3-----------
4pw_function
5-----------
6The function module provides a standard, general-purpose API for wrapping
7callable objects.
8
9.. note::
10  This module is under construction and its API is not complete.
11
12Overview
13========
14
15Basic usage
16-----------
17``pw_function`` defines the ``pw::Function`` class. A ``Function`` is a
18move-only callable wrapper constructable from any callable object. Functions
19are templated on the signature of the callable they store.
20
21Functions implement the call operator --- invoking the object will forward to
22the stored callable.
23
24.. code-block:: c++
25
26  int Add(int a, int b) { return a + b; }
27
28  // Construct a Function object from a function pointer.
29  pw::Function<int(int, int)> add_function(Add);
30
31  // Invoke the function object.
32  int result = add_function(3, 5);
33  EXPECT_EQ(result, 8);
34
35  // Construct a function from a lambda.
36  pw::Function<int(int)> negate([](int value) { return -value; });
37  EXPECT_EQ(negate(27), -27);
38
39Functions are nullable. Invoking a null function triggers a runtime assert.
40
41.. code-block:: c++
42
43  // A function intialized without a callable is implicitly null.
44  pw::Function<void()> null_function;
45
46  // Null functions may also be explicitly created or set.
47  pw::Function<void()> explicit_null_function(nullptr);
48
49  pw::Function<void()> function([]() {});  // Valid (non-null) function.
50  function = nullptr;  // Set to null, clearing the stored callable.
51
52  // Functions are comparable to nullptr.
53  if (function != nullptr) {
54    function();
55  }
56
57``pw::Function``'s default constructor is ``constexpr``, so default-constructed
58functions may be used in classes with ``constexpr`` constructors and in
59``constinit`` expressions.
60
61.. code-block:: c++
62
63  class MyClass {
64   public:
65    // Default construction of a pw::Function is constexpr.
66    constexpr MyClass() { ... }
67
68    pw::Function<void(int)> my_function;
69  };
70
71  // pw::Function and classes that use it may be constant initialized.
72  constinit MyClass instance;
73
74Storage
75-------
76By default, a ``Function`` stores its callable inline within the object. The
77inline storage size defaults to the size of two pointers, but is configurable
78through the build system. The size of a ``Function`` object is equivalent to its
79inline storage size.
80
81Attempting to construct a function from a callable larger than its inline size
82is a compile-time error.
83
84.. admonition:: Inline storage size
85
86  The default inline size of two pointers is sufficient to store most common
87  callable objects, including function pointers, simple non-capturing and
88  capturing lambdas, and lightweight custom classes.
89
90.. code-block:: c++
91
92  // The lambda is moved into the function's internal storage.
93  pw::Function<int(int, int)> subtract([](int a, int b) { return a - b; });
94
95  // Functions can be also be constructed from custom classes that implement
96  // operator(). This particular object is large (8 ints of space).
97  class MyCallable {
98   public:
99    int operator()(int value);
100
101   private:
102    int data_[8];
103  };
104
105  // Compiler error: sizeof(MyCallable) exceeds function's inline storage size.
106  pw::Function<int(int)> function((MyCallable()));
107
108..
109  For larger callables, a ``Function`` can be constructed with an external buffer
110  in which the callable should be stored. The user must ensure that the lifetime
111  of the buffer exceeds that of the function object.
112
113  .. code-block:: c++
114
115    // Initialize a function with an external 16-byte buffer in which to store its
116    // callable. The callable will be stored in the buffer regardless of whether
117    // it fits inline.
118    pw::FunctionStorage<16> storage;
119    pw::Function<int()> get_random_number([]() { return 4; }, storage);
120
121  .. admonition:: External storage
122
123    Functions which use external storage still take up the configured inline
124    storage size, which should be accounted for when storing function objects.
125
126In the future, ``pw::Function`` may support dynamic allocation of callable
127storage using the system allocator. This operation will always be explicit.
128
129API usage
130=========
131
132``pw::Function`` function parameters
133------------------------------------
134When implementing an API which takes a callback, a ``Function`` can be used in
135place of a function pointer or equivalent callable.
136
137.. code-block:: c++
138
139  // Before:
140  void DoTheThing(int arg, void (*callback)(int result));
141
142  // After. Note that it is possible to have parameter names within the function
143  // signature template for clarity.
144  void DoTheThing(int arg, const pw::Function<void(int result)>& callback);
145
146``pw::Function`` is movable, but not copyable, so APIs must accept
147``pw::Function`` objects either by const reference (``const
148pw::Function<void()>&``) or rvalue reference (``const pw::Function<void()>&&``).
149If the ``pw::Function`` simply needs to be called, it should be passed by const
150reference. If the ``pw::Function`` needs to be stored, it should be passed as an
151rvalue reference and moved into a ``pw::Function`` variable as appropriate.
152
153.. code-block:: c++
154
155  // This function calls a pw::Function but doesn't store it, so it takes a
156  // const reference.
157  void CallTheCallback(const pw::Function<void(int)>& callback) {
158    callback(123);
159  }
160
161  // This function move-assigns a pw::Function to another variable, so it takes
162  // an rvalue reference.
163  void StoreTheCallback(pw::Function<void(int)>&& callback) {
164    stored_callback_ = std::move(callback);
165  }
166
167.. admonition:: Rules of thumb for passing a ``pw::Function`` to a function
168
169   * **Pass by value**: Never.
170
171     This results in unnecessary ``pw::Function`` instances and move operations.
172   * **Pass by const reference** (``const pw::Function&``): When the
173     ``pw::Function`` is only invoked.
174
175     When a ``pw::Function`` is called or inspected, but not moved, take a const
176     reference to avoid copies and support temporaries.
177   * **Pass by rvalue reference** (``pw::Function&&``): When the
178     ``pw::Function`` is moved.
179
180     When the function takes ownership of the ``pw::Function`` object, always
181     use an rvalue reference (``pw::Function<void()>&&``) instead of a mutable
182     lvalue reference (``pw::Function<void()>&``). An rvalue reference forces
183     the caller to ``std::move`` when passing a preexisting ``pw::Function``
184     variable, which makes the transfer of ownership explicit. It is possible to
185     move-assign from an lvalue reference, but this fails to make it obvious to
186     the caller that the object is no longer valid.
187   * **Pass by non-const reference** (``pw::Function&``): Rarely, when modifying
188     a variable.
189
190     Non-const references are only necessary when modifying an existing
191     ``pw::Function`` variable. Use an rvalue reference instead if the
192     ``pw::Function`` is moved into another variable.
193
194Calling functions that use ``pw::Function``
195-------------------------------------------
196A ``pw::Function`` can be implicitly constructed from any callback object. When
197calling an API that takes a ``pw::Function``, simply pass the callable object.
198There is no need to create an intermediate ``pw::Function`` object.
199
200.. code-block:: c++
201
202  // Implicitly creates a pw::Function from a capturing lambda and calls it.
203  CallTheCallback([this](int result) { result_ = result; });
204
205  // Implicitly creates a pw::Function from a capturing lambda and stores it.
206  StoreTheCallback([this](int result) { result_ = result; });
207
208When working with an existing ``pw::Function`` variable, the variable can be
209passed directly to functions that take a const reference. If the function takes
210ownership of the ``pw::Function``, move the ``pw::Function`` variable at the
211call site.
212
213.. code-block:: c++
214
215  // Accepts the pw::Function by const reference.
216  CallTheCallback(my_function_);
217
218  // Takes ownership of the pw::Function.
219  void StoreTheCallback(std::move(my_function));
220
221Size reports
222============
223
224Function class
225--------------
226The following size report compares an API using a ``pw::Function`` to a
227traditional function pointer.
228
229.. include:: function_size
230
231Callable sizes
232--------------
233The table below demonstrates typical sizes of various callable types, which can
234be used as a reference when sizing external buffers for ``Function`` objects.
235
236.. include:: callable_size
237
238Design
239======
240``pw::Function`` is based largely on
241`fbl::Function <https://cs.opensource.google/fuchsia/fuchsia/+/main:zircon/system/ulib/fbl/include/fbl/function.h>`_
242from Fuchsia with some changes to make it more suitable for embedded
243development.
244
245Functions are movable, but not copyable. This allows them to store and manage
246callables without having to perform bookkeeping such as reference counting, and
247avoids any reliance on dynamic memory management. The result is a simpler
248implementation which is easy to conceptualize and use in an embedded context.
249
250Zephyr
251======
252To enable ``pw_function` for Zephyr add ``CONFIG_PIGWEED_FUNCTION=y`` to the
253project's configuration.
254