.. _module-pw_function:

===========
pw_function
===========
.. pigweed-module::
   :name: pw_function

* **Familiar**. ``pw_function`` provides a standard, general-purpose API for
  wrapping callable objects that's similar to `std::function`_.
* **Optimized**. ``pw_function`` doesn't allocate (unless you want it to) and
  uses several tricks to prevent code bloat.

.. _std\:\:function: https://en.cppreference.com/w/cpp/utility/functional/function

.. code-block:: c++

   #include "pw_function/function.h"

   // pw::Function can be constructed from a function pointer...
   int _a(int a, int b) { return a + b; }
   pw::Function<int(int, int)> add(_a);
   // ... or a lambda.
   pw::Function<int(int)> square([](int num) { return num * num; });

   // pw::Callback can only be invoked once. After the first call, the target
   // function is released and destroyed, along with any resources owned by
   // that function.
   pw::Callback<void(void)> flip_table_once([](void) {
     // (╯°□°)╯︵ ┻━┻
   });

   add(5, 6);
   add = nullptr;  // pw::Function and pw::Callback are nullable
   add(7, 2);  // CRASH

   square(4);

   if (flip_table_once != nullptr) {  // Safe to call
     flip_table_once();
   } else {
     // ┬─┬ノ( º _ ºノ)
   }


.. _module-pw_function-start:

-----------
Get started
-----------
.. tab-set::

   .. tab-item:: Bazel

      Add ``@pigweed//pw_function`` to your target's ``deps``:

      .. code-block::

         cc_library("...") {
           # ...
           deps = [
             # ...
             "@pigweed//pw_function",
             # ...
           ]
         }

      This assumes that your Bazel ``WORKSPACE`` has a `repository
      <https://bazel.build/concepts/build-ref#repositories>`_ named ``@pigweed``
      that points to the upstream Pigweed repository.

   .. tab-item:: GN

      Add ``$dir_pw_function`` to your target's ``deps``:

      .. code-block::

         pw_executable("...") {
           # ...
           deps = [
             # ...
             "$dir_pw_function",
             # ...
           ]
         }

   .. tab-item:: CMake

      Link your library to ``pw_function``:

      .. code-block::

         add_library(my_lib ...)
         target_link_libraries(my_lib PUBLIC pw_function)

Use ``pw_function`` in your C++ code:

.. code-block:: c++

   #include "pw_function/function.h"

   // ...

.. _module-pw_function-guides:

------
Guides
------

Construct ``pw::Function`` from a function pointer
==================================================
:cpp:type:`pw::Function` is a move-only callable wrapper constructable from any
callable object. It's templated on the signature of the callable it stores and
implements the call operator; invoking a ``pw::Function`` object forwards to
the stored callable.

.. code-block:: c++

   int Add(int a, int b) { return a + b; }

   // Construct a Function object from a function pointer.
   pw::Function<int(int, int)> add_function(Add);

   // Invoke the function object.
   int result = add_function(3, 5);
   EXPECT_EQ(result, 8);

Construct ``pw::Function`` from a lambda
========================================
.. code-block:: c++

   // Construct a function from a lambda.
   pw::Function<int(int)> negate([](int value) { return -value; });
   EXPECT_EQ(negate(27), -27);

Create single-use functions with ``pw::Callback``
=================================================
:cpp:type:`pw::Callback` is a specialization of :cpp:type:`pw::Function` that
can only be called once. After a :cpp:type:`pw::Callback` is called, the target
function is released and destroyed, along with any resources owned by that
function. A :cpp:type:`pw::Callback` in the "already called" state
has the same state as a :cpp:type:`pw::Function` that has been assigned to
nullptr.

.. code-block:: cpp

   pw::Callback<void(void)> flip_table_once([](void) {
     // (╯°□°)╯︵ ┻━┻
   });

   flip_table_once();  // OK
   flip_table_once();  // CRASH

Nullifying functions and comparing to null
==========================================
``pw::Function`` and ``pw::Callback`` are nullable and can be compared to
``nullptr``. Invoking a null function triggers a runtime assert.

.. code-block:: c++

   // A function initialized without a callable is implicitly null.
   pw::Function<void()> null_function;

   // Null functions may also be explicitly created or set.
   pw::Function<void()> explicit_null_function(nullptr);

   pw::Function<void()> function([]() {});  // Valid (non-null) function.
   function = nullptr;  // Set to null, clearing the stored callable.

   // Functions are comparable to nullptr.
   if (function != nullptr) {
     function();
   }

``constexpr`` constructors and ``constinit`` expressions
========================================================
The default constructor for :cpp:type:`pw::Function` is ``constexpr``, so
default-constructed functions may be used in classes with ``constexpr``
constructors and in ``constinit`` expressions.

.. code-block:: c++

   class MyClass {
    public:
     // Default construction of a pw::Function is constexpr.
     constexpr MyClass() { ... }

     pw::Function<void(int)> my_function;
   };

   // pw::Function and classes that use it may be constant initialized.
   constinit MyClass instance;

``pw::Function`` as a function parameter
========================================
When implementing an API which uses callbacks, ``pw::Function`` can be used in
place of a function pointer or equivalent callable.

.. code-block:: c++

   // Before:
   void DoTheThing(int arg, void (*callback)(int result));

   // After:
   void DoTheThing(int arg, const pw::Function<void(int result)>& callback);
   // Note the parameter name within the function signature template for clarity.

.. _module-pw_function-move-semantics:

Move semantics
==============
:cpp:type:`pw::Function` is movable, but not copyable, so APIs must accept
:cpp:type:`pw::Function` objects either by const reference (``const
pw::Function<void()>&``) or rvalue reference (``const pw::Function<void()>&&``).
If the :cpp:type:`pw::Function` simply needs to be called, it should be passed
by const reference. If the :cpp:type:`pw::Function` needs to be stored, it
should be passed as an rvalue reference and moved into a
:cpp:type:`pw::Function` variable as appropriate.

.. code-block:: c++

   // This function calls a pw::Function but doesn't store it, so it takes a
   // const reference.
   void CallTheCallback(const pw::Function<void(int)>& callback) {
     callback(123);
   }

   // This function move-assigns a pw::Function to another variable, so it takes
   // an rvalue reference.
   void StoreTheCallback(pw::Function<void(int)>&& callback) {
     stored_callback_ = std::move(callback);
   }

.. admonition:: Rules of thumb for passing a :cpp:type:`pw::Function` to a function

   * **Pass by value**: Never.
     This results in unnecessary :cpp:type:`pw::Function` instances and move
     operations.

   * **Pass by const reference** (``const pw::Function&``): When the
     :cpp:type:`pw::Function` is only invoked.

     When a :cpp:type:`pw::Function` is called or inspected, but not moved, take
     a const reference to avoid copies and support temporaries.

   * **Pass by rvalue reference** (``pw::Function&&``): When the
     :cpp:type:`pw::Function` is moved.

     When the function takes ownership of the :cpp:type:`pw::Function` object,
     always use an rvalue reference (``pw::Function<void()>&&``) instead of a
     mutable lvalue reference (``pw::Function<void()>&``). An rvalue reference
     forces the caller to ``std::move`` when passing a preexisting
     :cpp:type:`pw::Function` variable, which makes the transfer of ownership
     explicit. It is possible to move-assign from an lvalue reference, but this
     fails to make it obvious to the caller that the object is no longer valid.

   * **Pass by non-const reference** (``pw::Function&``): Rarely, when modifying
     a variable.

     Non-const references are only necessary when modifying an existing
     :cpp:type:`pw::Function` variable. Use an rvalue reference instead if the
     :cpp:type:`pw::Function` is moved into another variable.

Calling functions that use ``pw::Function``
===========================================
A :cpp:type:`pw::Function` can be implicitly constructed from any callback
object. When calling an API that takes a :cpp:type:`pw::Function`, simply pass
the callable object.  There is no need to create an intermediate
:cpp:type:`pw::Function` object.

.. code-block:: c++

   // Implicitly creates a pw::Function from a capturing lambda and calls it.
   CallTheCallback([this](int result) { result_ = result; });

   // Implicitly creates a pw::Function from a capturing lambda and stores it.
   StoreTheCallback([this](int result) { result_ = result; });

When working with an existing :cpp:type:`pw::Function` variable, the variable
can be passed directly to functions that take a const reference. If the function
takes ownership of the :cpp:type:`pw::Function`, move the
:cpp:type:`pw::Function` variable at the call site.

.. code-block:: c++

   // Accepts the pw::Function by const reference.
   CallTheCallback(my_function_);

   // Takes ownership of the pw::Function.
   void StoreTheCallback(std::move(my_function));

Managing inline storage size
============================
By default, ``pw::Function`` stores its callable inline within the object. The
inline storage size defaults to the size of one pointer, but is configurable
through the build system.

:cpp:type:`pw::InlineFunction` is similar to ``pw::Function``,
but is always inlined. That is, even if dynamic allocation is enabled for
``pw::Function``, ``pw::InlineFunction`` will fail to compile if
the callable is larger than the inline storage size.

Attempting to construct a function from a callable larger than its inline size
is a compile-time error unless dynamic allocation is enabled.

.. admonition:: Inline storage size

   The default inline size of one pointer is sufficient to store most common
   callable objects, including function pointers, simple non-capturing and
   capturing lambdas, and lightweight custom classes.

.. code-block:: c++

   // The lambda is moved into the function's internal storage.
   pw::Function<int(int, int)> subtract([](int a, int b) { return a - b; });

   // Functions can be also be constructed from custom classes that implement
   // operator(). This particular object is large (8 ints of space).
   class MyCallable {
    public:
     int operator()(int value);

    private:
     int data_[8];
   };

   // Compiler error: sizeof(MyCallable) exceeds function's inline storage size.
   pw::Function<int(int)> function((MyCallable()));

Dynamic allocation
==================
You can configure the inline allocation size of ``pw::Function`` and whether it
dynamically allocates, but it applies to all uses of ``pw::Function``.

As mentioned in :ref:`module-pw_function-design`, ``pw::Function`` is an alias
of Fuchsia's ``fit::function``. ``fit::function`` allows you to specify the
inline (static) allocation size and whether to dynamically allocate if the
callable target doesn't inline. If you want to use a function class with
different attributes, you can interact with ``fit::function`` directly but note
that the resulting functions may not be interchangeable, i.e. callables for one
might not fit in the other.

When ``PW_FUNCTION_ENABLE_DYNAMIC_ALLOCATION`` is enabled, a ``pw::Function``
will use dynamic allocation to store callables that exceed the inline size.
An :ref:`allocator <module-pw_allocator>` type can be optionally supplied as a
template argument. The default allocator type can also be changed by overriding
``PW_FUNCTION_DEFAULT_ALLOCATOR_TYPE`` (the ``value_type`` of the allocator
is irrelevant, since it must support rebinding). When dynamic allocation is
enabled but a compile-time check for the inlining is still required,
``pw::InlineFunction`` can be used.

.. warning::

   If ``PW_FUNCTION_ENABLE_DYNAMIC_ALLOCATION`` is enabled then attempts to
   cast from :cpp:type:`pw::InlineFunction` to a regular
   :cpp:type:`pw::Function` will **ALWAYS** allocate memory.

Invoking ``pw::Function`` from a C-style API
============================================
.. _trampoline layers: https://en.wikipedia.org/wiki/Trampoline_(computing)

One use case for invoking ``pw_function`` from a C-style API is to automate the
generation of `trampoline layers`_. See
:cpp:type:`pw::function::GetFunctionPointer()`.

.. _module-pw_function-reference:

-------------
API reference
-------------

``pw::Function``
================
.. doxygentypedef:: pw::Function

``pw::InlineFunction``
======================
.. doxygentypedef:: pw::InlineFunction

``pw::Callback``
================
.. doxygentypedef:: pw::Callback

``pw::InlineCallback``
======================
.. doxygentypedef:: pw::InlineCallback

``pw::bind_member()``
=====================
.. doxygenfunction:: pw::bind_member

``pw::function::GetFunctionPointer()``
======================================
.. doxygenfile:: pw_function/pointer.h
   :sections: detaileddescription
.. doxygenfunction:: GetFunctionPointer()
.. doxygenfunction:: GetFunctionPointer(const FunctionType&)

``pw::function::GetFunctionPointerContextFirst()``
==================================================
.. doxygenfunction:: GetFunctionPointerContextFirst()
.. doxygenfunction:: GetFunctionPointerContextFirst(const FunctionType&)

``pw::ScopeGuard``
==================
.. doxygenclass:: pw::ScopeGuard
   :members:

.. _module-pw_function-design:

------
Design
------
``pw::Function`` is an alias of Fuchsia's ``fit::function_impl`` and
``pw::Callback`` is an alias of Fuchsia's ``fit::callback_impl``. See the
following links for more information about Fuchsia's implementations:

* `//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>`_
* `fit::function <https://fuchsia.googlesource.com/fuchsia/+/HEAD/sdk/lib/fit/#fit_function>`_

.. _module-pw_function-non-literal:

Why ``pw::Function`` is not a literal
=====================================
The default constructor for ``pw::Function`` is ``constexpr`` but
``pw::Function`` is not a literal type. Instances can be declared ``constinit``
but can't be used in ``constexpr`` contexts. There are a few reasons for this:

* ``pw::Function`` supports wrapping any callable type, and the wrapped type
  might not be a literal type.
* ``pw::Function`` stores inline callables in a bytes array, which is not
  ``constexpr``-friendly.
* ``pw::Function`` optionally uses dynamic allocation, which doesn't work in
  ``constexpr`` contexts (at least before C++20).

------------
Size reports
------------

Comparing ``pw::Function`` to a traditional function pointer
============================================================
The following size report compares an API using a :cpp:type:`pw::Function` to a
traditional function pointer.

.. include:: function_size

Typical sizes of various callable types
=======================================
The table below demonstrates typical sizes of various callable types, which can
be used as a reference when sizing external buffers for ``pw::Function``
objects.

.. include:: callable_size
