blob: a2cb0c5479e0995cd4c52e761baa3dc66acef8bc [file] [log] [blame]
Alexei Frolov99de52d2021-05-11 19:58:01 -07001.. _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
Wyatt Heplerf5cdd932021-06-14 13:53:23 -070057``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
Alexei Frolov99de52d2021-05-11 19:58:01 -070074Storage
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
132Implementation-side
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, pw::Function<void(int result)> callback);
145
146An API can accept a function either by value or by reference. If taken by value,
147the implementation is responsible for managing the function by moving it into an
148appropriate location.
149
150.. admonition:: Value or reference?
151
152 It is preferable for APIs to take functions by value rather than by reference.
153 This provides callers of the API with a more convenient interface, as well as
154 making their lives easier by not requiring management of resources or
155 lifetimes.
156
157Caller-side
158-----------
159When calling an API which takes a function by reference, the standard pattern is
160to implicitly construct the function in place from a callable object. Simply
161pass the desired callable directly to the API.
162
163.. code-block:: c++
164
165 // Implicitly initialize a Function from a capturing lambda.
166 DoTheThing(42, [this](int result) { result_ = result; });
167
168Size reports
169============
170
171Function class
172--------------
173The following size report compares an API using a ``pw::Function`` to a
174traditional function pointer.
175
176.. include:: function_size
177
178Callable sizes
179--------------
180The table below demonstrates typical sizes of various callable types, which can
181be used as a reference when sizing external buffers for ``Function`` objects.
182
183.. include:: callable_size
184
185Design
186======
187``pw::Function`` is based largely on
188`fbl::Function <https://cs.opensource.google/fuchsia/fuchsia/+/main:zircon/system/ulib/fbl/include/fbl/function.h>`_
189from Fuchsia with some changes to make it more suitable for embedded
190development.
191
Alexei Frolovbebba902021-06-09 17:03:52 -0700192Functions are movable, but not copyable. This allows them to store and manage
Alexei Frolov99de52d2021-05-11 19:58:01 -0700193callables without having to perform bookkeeping such as reference counting, and
194avoids any reliance on dynamic memory management. The result is a simpler
195implementation which is easy to conceptualize and use in an embedded context.