blob: 60c8a85e9916f64655c0945c6178a348a2b52d2b [file]
.. _module-pw_containers-lists:
=====
Lists
=====
.. pigweed-module-subpage::
:name: pw_containers
A linked list is an ordered collection of items in which each item is associated
with pointers to one or more of its adjacent items. Pigweed provides intrusive
lists, meaning the pointers are stored within the items themselves. This allows
an arbitrary number of items to be added to a list without requiring additional
memory beyond that of the items themselves.
.. _module-pw_containers-intrusive_list:
-----------------
pw::IntrusiveList
-----------------
:cc:`pw::IntrusiveList` provides an embedded-friendly, double-linked,
intrusive list implementation. An intrusive list is a type of linked list that
embeds list metadata, such as a "next" pointer, into the list object itself.
This allows the construction of a linked list without the need to dynamically
allocate list entries.
This class is similar to ``std::list<T>``, except that the type of items to be
added must derive from ``pw::IntrusiveList<T>::Item``.
In C, an intrusive list can be made by manually including the "next" pointer as
a member of the object's struct. ``pw::IntrusiveList`` uses C++ features to
simplify the process of creating an intrusive list. It provides classes that
list elements can inherit from, protecting the list metadata from being accessed
by the item class.
.. note::
Originally, ``pw::IntrusiveList<T>`` was implemented as a singly linked list.
To facilitate migration to ``pw::IntrusiveForwardList<T>::Item``, this
original implementation can still be temporarily used by enabling the
``PW_CONTAINERS_USE_LEGACY_INTRUSIVE_LIST`` module configuration option.
See also :ref:`module-pw_containers-multiple_containers`.
.. _module-pw_containers-intrusive_list-example:
Example
=======
.. literalinclude:: examples/intrusive_list.cc
:language: cpp
:linenos:
:start-after: [pw_containers-intrusive_list]
:end-before: [pw_containers-intrusive_list]
If you need to add this item to containers of more than one type, see
:ref:`module-pw_containers-multiple_containers`,
------------------------
pw::IntrusiveForwardList
------------------------
:cc:`pw::IntrusiveForwardList` provides an embedded-friendly, singly linked,
intrusive list implementation. It is very similar to
:ref:`module-pw_containers-intrusive_list`, except that it is singly rather than
doubly linked.
This class is similar to ``std::forward_list<T>``. Items to be added must derive
from ``pw::IntrusiveForwardList<T>::Item``.
See also :ref:`module-pw_containers-multiple_containers`.
Example
=======
.. literalinclude:: examples/intrusive_forward_list.cc
:language: cpp
:linenos:
:start-after: [pw_containers-intrusive_forward_list]
:end-before: [pw_containers-intrusive_forward_list]
If you need to add this item to containers of more than one type, see
:ref:`module-pw_containers-multiple_containers`,
------------------
pw::IntrusiveQueue
------------------
:cc:`pw::IntrusiveQueue` provides an embedded-friendly, singly linked, intrusive
queue implementation. It wrapper around :cc:`pw::IntrusiveForwardList` that
tracks the tail element, allowing for ``O(1)`` ``push_back()`` operations. Note
that like a standard queue, it does not support ``pop_back()`` since doing so
would require an ``O(n)`` traversal to update the tail pointer.
This class is most similar to ``std::deque<T>``. It offers ``push_back()``,
``push_front()``, and ``pop_front()``, but not ``pop_back()``. Because it is an
intrusive list, its elements must derive from ``pw::IntrusiveQueue<T>::Item``.
-------------
API reference
-------------
Moved: :cc:`pw_containers_lists`
Performance considerations
==========================
Items only include pointers to the next item. To reach previous items, the list
maintains a cycle of items so that the first item can be reached from the last.
This structure means certain operations have linear complexity in terms of the
number of items in the list, i.e. they are "O(n)":
- Removing an item from a list using
``pw::IntrusiveForwardList<T>::remove(const T&)``.
- Getting the list size using ``pw::IntrusiveForwardList<T>::size()``.
When using a ``pw::IntrusiveForwardList<T>`` in a performance-critical section
or with many items, authors should prefer to avoid these methods. For example,
it may be preferable to create items that together with their storage outlive
the list.
Notably, ``pw::IntrusiveForwardList<T>::end()`` is constant complexity (i.e.
"O(1)"). As a result iterating over a list does not incur an additional penalty.
.. _module-pw_containers-intrusivelist-size-report:
Size reports
------------
The tables below illustrate the following scenarios:
* Scenarios related to ``IntrusiveList``:
* The memory and code size cost incurred by a adding a single
``IntrusiveList``.
* The memory and code size cost incurred by adding another ``IntrusiveList``
with a different type. As ``IntrusiveList`` is templated on type, this
results in additional code being generated.
* Scenarios related to ``IntrusiveForwardList``:
* The memory and code size cost incurred by a adding a single
``IntrusiveForwardList``.
* The memory and code size cost incurred by adding another
``IntrusiveForwardList`` with a different type. As ``IntrusiveForwardList``
is templated on type, this results in additional code being generated.
* The memory and code size cost incurred by a adding both an ``IntrusiveList``
and an ``IntrusiveForwardList`` of the same type. These types reuse code, so
the combined sum is less than the sum of its parts.
.. include:: lists_size_report