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