blob: aa3d6e7648b0ac07fcdbc3ee3161eff68e84046f [file] [log] [blame]
Wyatt Heplerf9fb90f2020-09-30 18:59:33 -07001.. _module-pw_containers:
Wyatt Hepler3c4e5de2020-03-03 14:37:52 -08002
3-------------
4pw_containers
5-------------
Armando Montanez0054a9b2020-03-13 13:06:24 -07006The ``pw_containers`` module provides embedded-friendly container classes.
Wyatt Hepler3c4e5de2020-03-03 14:37:52 -08007
Armando Montanez516022c2020-05-14 09:12:19 -07008pw::Vector
9==========
10The Vector class is similar to ``std::vector``, except it is backed by a
Wyatt Hepler3c4e5de2020-03-03 14:37:52 -080011fixed-size buffer. Vectors must be declared with an explicit maximum size
12(e.g. ``Vector<int, 10>``) but vectors can be used and referred to without the
13max size template parameter (e.g. ``Vector<int>``).
14
15To allow referring to a ``pw::Vector`` without an explicit maximum size, all
16Vector classes inherit from the generic ``Vector<T>``, which stores the maximum
17size in a variable. This allows Vectors to be used without having to know
18their maximum size at compile time. It also keeps code size small since
19function implementations are shared for all maximum sizes.
20
Armando Montanez516022c2020-05-14 09:12:19 -070021pw::IntrusiveList
22=================
Wyatt Heplerb6884d72021-06-11 09:23:52 -070023IntrusiveList provides an embedded-friendly singly-linked intrusive list
24implementation. An intrusive list is a type of linked list that embeds the
25"next" pointer into the list object itself. This allows the construction of a
26linked list without the need to dynamically allocate list entries.
Armando Montanez516022c2020-05-14 09:12:19 -070027
Wyatt Heplerb6884d72021-06-11 09:23:52 -070028In C, an intrusive list can be made by manually including the "next" pointer as
29a member of the object's struct. ``pw::IntrusiveList`` uses C++ features to
30simplify the process of creating an intrusive list. ``pw::IntrusiveList``
31provides a class that list elements can inherit from. This protects the "next"
32pointer from being accessed by the item class, so only the ``pw::IntrusiveList``
33class can modify the list.
Kevin Zengb0bb8492021-01-11 21:32:24 -080034
Armando Montanez516022c2020-05-14 09:12:19 -070035Usage
36-----
Wyatt Heplerb6884d72021-06-11 09:23:52 -070037While the API of ``pw::IntrusiveList`` is similar to a ``std::forward_list``,
38there are extra steps to creating objects that can be stored in this data
39structure. Objects that will be added to a ``IntrusiveList<T>`` must inherit
40from ``IntrusiveList<T>::Item``. They can inherit directly from it or inherit
41from it through another base class. When an item is instantiated and added to a
42linked list, the pointer to the object is added to the "next" pointer of
43whichever object is the current tail.
Armando Montanez516022c2020-05-14 09:12:19 -070044
45That means two key things:
46
Wyatt Heplerb6884d72021-06-11 09:23:52 -070047 - An instantiated ``IntrusiveList<T>::Item`` must remain in scope for the
48 lifetime of the ``IntrusiveList`` it has been added to.
49 - A linked list item CANNOT be included in two lists. Attempting to do so
50 results in an assert failure.
Armando Montanez516022c2020-05-14 09:12:19 -070051
52.. code-block:: cpp
53
54 class Square
Prashanth Swaminathan65731872021-02-11 08:51:08 -080055 : public pw::IntrusiveList<Square>::Item {
Armando Montanez516022c2020-05-14 09:12:19 -070056 public:
57 Square(unsigned int side_length) : side_length(side_length) {}
58 unsigned long Area() { return side_length * side_length; }
59
60 private:
61 unsigned int side_length;
62 };
63
Prashanth Swaminathan65731872021-02-11 08:51:08 -080064 pw::IntrusiveList<Square> squares;
Armando Montanez516022c2020-05-14 09:12:19 -070065
66 Square small(1);
67 Square large(4000);
68 // These elements are not copied into the linked list, the original objects
69 // are just chained together and can be accessed via
70 // `IntrusiveList<Square> squares`.
71 squares.push_back(small);
72 squares.push_back(large);
73
74 {
Wyatt Heplerb6884d72021-06-11 09:23:52 -070075 // When different_scope goes out of scope, it removes itself from the list.
Armando Montanez516022c2020-05-14 09:12:19 -070076 Square different_scope = Square(5);
77 squares.push_back(&different_scope);
78 }
79
Wyatt Heplerb6884d72021-06-11 09:23:52 -070080 for (const auto& square : squares) {
81 PW_LOG_INFO("Found a square with an area of %lu", square.Area());
Armando Montanez516022c2020-05-14 09:12:19 -070082 }
83
Wyatt Heplerb6884d72021-06-11 09:23:52 -070084pw::containers::FlatMap
85=======================
86FlatMap provides a simple, fixed-size associative array with lookup by key or
87value. ``pw::containers::FlatMap`` contains the same methods and features for
88looking up data as std::map. However, there are no methods that modify the
89underlying data. The underlying array in ``pw::containers::FlatMap`` does not
90need to be sorted. During construction, ``pw::containers::FlatMap`` will
91perform a constexpr insertion sort.
Armando Montanez516022c2020-05-14 09:12:19 -070092
Wyatt Hepler100a1602021-10-05 14:02:02 -070093pw::containers::FilteredView
94============================
95``pw::containers::FilteredView`` provides a view of a container that only
96contains elements that match the specified filter. This class is similar to
97C++20's `std::ranges::filter_view
98<https://en.cppreference.com/w/cpp/ranges/filter_view>`_.
99
100To create a ``FilteredView``, pass a container and a filter object, which may be
101a lambda or class that implements ``operator()`` for the container's value type.
102
103.. code-block:: cpp
104
105 std::array<int, 99> kNumbers = {3, 1, 4, 1, ...};
106
107 for (int even : FilteredView(kNumbers, [](int n) { return n % 2 == 0; })) {
108 PW_LOG_INFO("This number is even: %d", even);
109 }
110
Wyatt Heplerbfb98872021-10-07 21:16:24 -0700111pw::containers::WrappedIterator
112===============================
113``pw::containers::WrappedIterator`` is a class that makes it easy to wrap an
114existing iterator type. It reduces boilerplate by providing ``operator++``,
115``operator--``, ``operator==``, ``operator!=``, and the standard iterator
116aliases (``difference_type``, ``value_type``, etc.). It does not provide the
117dereference operator; that must be supplied by a derived class.
118
119To use it, create a class that derives from ``WrappedIterator`` and define
120``operator*()`` and ``operator->()`` as appropriate. The new iterator might
121apply a transformation to or access a member of the values provided by the
122original iterator. The following example defines an iterator that multiplies the
123values in an array by 2.
124
125.. code-block:: cpp
126
127 // Divides values in a std::array by two.
128 class DoubleIterator
129 : public pw::containers::WrappedIterator<DoubleIterator, const int*, int> {
130 public:
131 constexpr DoubleIterator(const int* it) : WrappedIterator(it) {}
132
133 int operator*() const { return value() * 2; }
134
135 // Don't define operator-> since this iterator returns by value.
136 };
137
138 constexpr std::array<int, 6> kArray{0, 1, 2, 3, 4, 5};
139
140 void SomeFunction {
141 for (DoubleIterator it(kArray.begin()); it != DoubleIterator(kArray.end()); ++it) {
142 // The iterator yields 0, 2, 4, 6, 8, 10 instead of the original values.
143 }
144 };
145
146``WrappedIterator`` may be used in concert with ``FilteredView`` to create a
147view that iterates over a matching values in a container and applies a
148transformation to the values. For example, it could be used with
149``FilteredView`` to filter a list of packets and yield only one field from the
150packet.
151
152The combination of ``FilteredView`` and ``WrappedIterator`` provides some basic
153functional programming features similar to (though much more cumbersome than)
154`generator expressions <https://www.python.org/dev/peps/pep-0289/>`_ (or `filter
155<https://docs.python.org/3/library/functions.html#filter>`_/`map
156<https://docs.python.org/3/library/functions.html#map>`_) in Python or streams
157in Java 8. ``WrappedIterator`` and ``FilteredView`` require no memory
158allocation, which is helpful when memory is too constrained to process the items
159into a new container.
160
Wyatt Heplerfff3c7c2021-08-17 18:15:10 -0700161pw::containers::to_array
162========================
163``pw::containers::to_array`` is a C++14-compatible implementation of C++20's
164`std::to_array <https://en.cppreference.com/w/cpp/container/array/to_array>`_.
165It converts a C array to a ``std::array``.
166
Wyatt Hepler3c4e5de2020-03-03 14:37:52 -0800167Compatibility
168=============
Wyatt Hepler3c4e5de2020-03-03 14:37:52 -0800169* C++17
170
171Dependencies
172============
Armando Montanez0054a9b2020-03-13 13:06:24 -0700173* ``pw_span``