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