blob: 356193674e6a1fd47c528ad404efc945e2f53f4c [file] [log] [blame]
.. default-domain:: cpp
.. highlight:: sh
-------------
pw_containers
-------------
The ``pw_containers`` module provides embedded-friendly container classes.
pw::Vector
==========
The Vector class is similar to ``std::vector``, except it is backed by a
fixed-size buffer. Vectors must be declared with an explicit maximum size
(e.g. ``Vector<int, 10>``) but vectors can be used and referred to without the
max size template parameter (e.g. ``Vector<int>``).
To allow referring to a ``pw::Vector`` without an explicit maximum size, all
Vector classes inherit from the generic ``Vector<T>``, which stores the maximum
size in a variable. This allows Vectors to be used without having to know
their maximum size at compile time. It also keeps code size small since
function implementations are shared for all maximum sizes.
pw::IntrusiveList
=================
IntrusiveList provides an embedded-friendly singly-linked list implementation.
An intrusive list is a type of linked list that embeds the "next" pointer into
the list object itself. This allows the construction of a linked list without
the need to dynamically allocate list entries to point to the actual in-memory
objects. 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 and intrusive
list objects by providing a class that list elements can inherit from. This
protects the "next" pointer from being accessed by the actual item that is
stored in the linked list; only the `pw::IntrusiveList` class can modify the
list.
Usage
-----
While the API of `pw::IntrusiveList` is relatively similar to a
``std::forward_list``, there are extra steps to creating objects that can be
stored in this data structure. Objects that will be added to a
``IntrusiveList<T>`` must inherit from ``IntrusiveList<T>::Item``. When an item
is instantiated and added to a linked list, the pointer to the object is added
to the "next" pointer of whichever object is the current tail.
That means two key things:
- An instantiated IntrusiveList::Item must remain in scope for the lifetime of
the IntrusiveList it has been added to.
- A linked list item CANNOT be included in two lists, as it is part of a
preexisting list and adding it to another implicitly breaks correctness
of the first list.
.. code-block:: cpp
class Square
: public pw::containers::IntrusiveList<Square>::Item {
public:
Square(unsigned int side_length) : side_length(side_length) {}
unsigned long Area() { return side_length * side_length; }
private:
unsigned int side_length;
};
pw::containers::IntrusiveList<Square> squares;
Square small(1);
Square large(4000);
// These elements are not copied into the linked list, the original objects
// are just chained together and can be accessed via
// `IntrusiveList<Square> squares`.
squares.push_back(small);
squares.push_back(large);
{
// ERROR: When this goes out of scope, it will break the linked list.
Square different_scope = Square(5);
squares.push_back(&different_scope);
}
for (auto& square : squares) {
PW_LOG_INFO("Found a square with an area of %ul", square.Area());
}
Compatibility
=============
* C
* C++17
Dependencies
============
* ``pw_span``