Wyatt Hepler | f9fb90f | 2020-09-30 18:59:33 -0700 | [diff] [blame] | 1 | .. _module-pw_containers: |
Wyatt Hepler | 3c4e5de | 2020-03-03 14:37:52 -0800 | [diff] [blame] | 2 | |
| 3 | ------------- |
| 4 | pw_containers |
| 5 | ------------- |
Armando Montanez | 0054a9b | 2020-03-13 13:06:24 -0700 | [diff] [blame] | 6 | The ``pw_containers`` module provides embedded-friendly container classes. |
Wyatt Hepler | 3c4e5de | 2020-03-03 14:37:52 -0800 | [diff] [blame] | 7 | |
Armando Montanez | 516022c | 2020-05-14 09:12:19 -0700 | [diff] [blame] | 8 | pw::Vector |
| 9 | ========== |
| 10 | The Vector class is similar to ``std::vector``, except it is backed by a |
Wyatt Hepler | 3c4e5de | 2020-03-03 14:37:52 -0800 | [diff] [blame] | 11 | fixed-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 |
| 13 | max size template parameter (e.g. ``Vector<int>``). |
| 14 | |
| 15 | To allow referring to a ``pw::Vector`` without an explicit maximum size, all |
| 16 | Vector classes inherit from the generic ``Vector<T>``, which stores the maximum |
| 17 | size in a variable. This allows Vectors to be used without having to know |
| 18 | their maximum size at compile time. It also keeps code size small since |
| 19 | function implementations are shared for all maximum sizes. |
| 20 | |
Armando Montanez | 516022c | 2020-05-14 09:12:19 -0700 | [diff] [blame] | 21 | |
| 22 | pw::IntrusiveList |
| 23 | ================= |
| 24 | IntrusiveList provides an embedded-friendly singly-linked list implementation. |
| 25 | An intrusive list is a type of linked list that embeds the "next" pointer into |
| 26 | the list object itself. This allows the construction of a linked list without |
| 27 | the need to dynamically allocate list entries to point to the actual in-memory |
| 28 | objects. In C, an intrusive list can be made by manually including the "next" |
| 29 | pointer as a member of the object's struct. `pw::IntrusiveList` uses C++ |
| 30 | features to simplify the process of creating an intrusive list and intrusive |
| 31 | list objects by providing a class that list elements can inherit from. This |
| 32 | protects the "next" pointer from being accessed by the actual item that is |
| 33 | stored in the linked list; only the `pw::IntrusiveList` class can modify the |
| 34 | list. |
| 35 | |
| 36 | |
Kevin Zeng | b0bb849 | 2021-01-11 21:32:24 -0800 | [diff] [blame] | 37 | pw::containers::FlatMap |
| 38 | ======================= |
| 39 | FlatMap provides a simple, fixed-size associative array with lookup by key or |
| 40 | value. ``pw::containers::FlatMap`` contains the same methods and features for |
| 41 | looking up data as std::map. However, there are no methods that modify the |
| 42 | underlying data. The underlying array in ``pw::containers::FlatMap`` does not |
| 43 | need to be sorted. During construction, ``pw::containers::FlatMap`` will |
| 44 | perform a constexpr insertion sort. |
| 45 | |
| 46 | |
Armando Montanez | 516022c | 2020-05-14 09:12:19 -0700 | [diff] [blame] | 47 | Usage |
| 48 | ----- |
| 49 | While the API of `pw::IntrusiveList` is relatively similar to a |
| 50 | ``std::forward_list``, there are extra steps to creating objects that can be |
| 51 | stored in this data structure. Objects that will be added to a |
| 52 | ``IntrusiveList<T>`` must inherit from ``IntrusiveList<T>::Item``. When an item |
| 53 | is instantiated and added to a linked list, the pointer to the object is added |
| 54 | to the "next" pointer of whichever object is the current tail. |
| 55 | |
| 56 | |
| 57 | That means two key things: |
| 58 | |
| 59 | - An instantiated IntrusiveList::Item must remain in scope for the lifetime of |
| 60 | the IntrusiveList it has been added to. |
| 61 | - A linked list item CANNOT be included in two lists, as it is part of a |
| 62 | preexisting list and adding it to another implicitly breaks correctness |
| 63 | of the first list. |
| 64 | |
| 65 | .. code-block:: cpp |
| 66 | |
| 67 | class Square |
Prashanth Swaminathan | 6573187 | 2021-02-11 08:51:08 -0800 | [diff] [blame] | 68 | : public pw::IntrusiveList<Square>::Item { |
Armando Montanez | 516022c | 2020-05-14 09:12:19 -0700 | [diff] [blame] | 69 | public: |
| 70 | Square(unsigned int side_length) : side_length(side_length) {} |
| 71 | unsigned long Area() { return side_length * side_length; } |
| 72 | |
| 73 | private: |
| 74 | unsigned int side_length; |
| 75 | }; |
| 76 | |
Prashanth Swaminathan | 6573187 | 2021-02-11 08:51:08 -0800 | [diff] [blame] | 77 | pw::IntrusiveList<Square> squares; |
Armando Montanez | 516022c | 2020-05-14 09:12:19 -0700 | [diff] [blame] | 78 | |
| 79 | Square small(1); |
| 80 | Square large(4000); |
| 81 | // These elements are not copied into the linked list, the original objects |
| 82 | // are just chained together and can be accessed via |
| 83 | // `IntrusiveList<Square> squares`. |
| 84 | squares.push_back(small); |
| 85 | squares.push_back(large); |
| 86 | |
| 87 | { |
| 88 | // ERROR: When this goes out of scope, it will break the linked list. |
| 89 | Square different_scope = Square(5); |
| 90 | squares.push_back(&different_scope); |
| 91 | } |
| 92 | |
| 93 | for (auto& square : squares) { |
| 94 | PW_LOG_INFO("Found a square with an area of %ul", square.Area()); |
| 95 | } |
| 96 | |
| 97 | |
Wyatt Hepler | 3c4e5de | 2020-03-03 14:37:52 -0800 | [diff] [blame] | 98 | Compatibility |
| 99 | ============= |
| 100 | * C |
| 101 | * C++17 |
| 102 | |
| 103 | Dependencies |
| 104 | ============ |
Armando Montanez | 0054a9b | 2020-03-13 13:06:24 -0700 | [diff] [blame] | 105 | * ``pw_span`` |