xref: /aosp_15_r20/external/pigweed/pw_containers/public/pw_containers/internal/aa_tree.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include <cstddef>
17 #include <cstdint>
18 #include <functional>
19 #include <utility>
20 
21 #include "pw_assert/assert.h"
22 #include "pw_containers/internal/aa_tree_item.h"
23 #include "pw_containers/internal/aa_tree_iterator.h"
24 #include "pw_containers/internal/intrusive_item.h"
25 #include "pw_function/function.h"
26 
27 namespace pw::containers::internal {
28 
29 /// Base type for an AA tree that is devoid of template parameters.
30 ///
31 /// This generic class does not implement any functionality that requires
32 /// comparing keys, and should not be used directly. Instead, see the `AATree`
33 /// class that is templated on methods to get and compare keys.
34 class GenericAATree {
35  public:
36   using iterator = AATreeIterator<>;
37 
38   /// Constructs an empty AA tree.
39   ///
40   /// @param  unique_keys   Indicates if this tree requires unique keys or
41   ///                       allows duplicate keys.
GenericAATree(bool unique_keys)42   constexpr explicit GenericAATree(bool unique_keys)
43       : unique_keys_(unique_keys) {}
44 
45   /// Destructor.
~GenericAATree()46   ~GenericAATree() { CheckIntrusiveContainerIsEmpty(empty()); }
47 
48   // Intrusive trees cannot be copied, since each Item can only be in one tree.
49   GenericAATree(const GenericAATree&) = delete;
50   GenericAATree& operator=(const GenericAATree&) = delete;
51 
unique_keys()52   [[nodiscard]] constexpr bool unique_keys() const { return unique_keys_; }
53 
54   /// Sets the tree's root item.
55   void SetRoot(AATreeItem* item);
56 
57   // Iterators
58 
59   /// Returns a pointer to the first item, if any.
begin()60   constexpr iterator begin() noexcept {
61     return empty() ? iterator(&root_) : iterator(&root_, root_->GetLeftmost());
62   }
63 
64   /// Returns a pointer to the last item, if any.
end()65   constexpr iterator end() noexcept {
66     return empty() ? iterator(&root_)
67                    : ++(iterator(&root_, root_->GetRightmost()));
68   }
69 
70   // Capacity
71 
72   /// Returns whether the tree has zero items or not.
empty()73   [[nodiscard]] constexpr bool empty() const { return root_ == nullptr; }
74 
75   /// Returns the number of items in the tree.
76   size_t size() const;
77 
78   /// Returns how many items can be added.
79   ///
80   /// As an intrusive container, this is effectively unbounded.
max_size()81   constexpr size_t max_size() const noexcept {
82     return std::numeric_limits<ptrdiff_t>::max();
83   }
84 
85   // Modifiers
86 
87   /// Removes all items from the tree and leaves it empty.
88   ///
89   /// The items themselves are not destructed.
90   void clear();
91 
92   /// Removes an item from the tree and returns an iterator to the item after
93   /// the removed item.
94   ///
95   /// The items themselves are not destructed.
96   iterator erase_one(AATreeItem& item);
97 
98   /// Removes the items from first, inclusive, to last, exclusive from the tree
99   /// and returns an iterator to the item after the last removed item.
100   ///
101   /// The items themselves are not destructed.
102   iterator erase_range(AATreeItem& first, AATreeItem& last);
103 
104   /// Exchanges this tree's items with the `other` tree's items.
105   void swap(GenericAATree& other);
106 
107  private:
108   // The derived, templated type needs to be able to access the root element.
109   template <typename, typename>
110   friend class AATree;
111 
112   /// Root of the tree. Only null if the tree is empty.
113   AATreeItem* root_ = nullptr;
114 
115   /// Indicates whether the tree requires unique keys.
116   ///
117   /// This is a const member rather than a template parameter for 3 reasons:
118   /// 1. It is a tree field and not an item field, meaning the space overhead is
119   ///    marginal.
120   /// 2. It is only used in a single branch, i.e. when inserting an item with a
121   ///    duplicate key. Making this branch constexpr-if would only save a
122   ///    minimal amount of code size.
123   /// 3. It allows the same types of ``AATree<K,C>``, ``AATree<K,C>::Item`` and
124   ///    ``iterator<TT,T>`` to be used for both ``IntrusiveMap`` and
125   ///    ``IntrusiveMultiMap``, thereby reducing code size more significantly.
126   const bool unique_keys_;
127 };
128 
129 /// An AA tree, as described by Arne Andersson in
130 /// https://user.it.uu.se/~arneande/ps/simp.pdf. AA trees are simplified
131 /// red-black which offer almost as much performance with much simpler and
132 /// smaller code.
133 ///
134 /// The tree provides an ordered collection of keyed items, and is used to
135 /// implement ``pw::IntrusiveMap`` and ``pw::IntrusiveMultiMap``. Keys are
136 /// retrieved and compared using the functions provided via template parameters.
137 ///
138 /// @tparam   Compare     Function with the signature `bool(Key, Key) that is
139 ///                       used to order items.
140 template <typename K, typename V>
141 class AATree final : public GenericAATree {
142  public:
143   using Key = K;
144   using Compare = Function<bool(Key, Key)>;
145   using GetKey = Function<Key(const V&)>;
146   using GenericAATree::iterator;
147 
148   /// Base item type for intrusive items stored in trees.
149   ///
150   /// Unlike `IntrusiveForwardList` and `IntrusiveList`, which define distinct
151   /// nested types for their items, maps and sets share the same base item type.
152   class Item : public AATreeItem {
153    public:
154     constexpr explicit Item() = default;
155 
156    private:
157     // IntrusiveItem is used to ensure T inherits from this container's Item
158     // type. See also `CheckItemType`.
159     template <typename, typename, bool>
160     friend struct IntrusiveItem;
161     using ItemType = V;
162   };
163 
164   /// An extension of `Item` that includes storage for a key.
165   class Pair : public Item {
166    public:
Pair(Key key)167     constexpr explicit Pair(Key key) : key_(key) {}
key()168     constexpr Key key() const { return key_; }
169 
170     constexpr bool operator<(const Pair& rhs) { return key_ < rhs.key(); }
171 
172    private:
173     const Key key_;
174   };
175 
176   /// Constructs an empty AA tree.
177   ///
178   /// @param  unique_keys   Indicates if this tree requires unique keys or
179   ///                       allows duplicate keys.
AATree(bool unique_keys,Compare && compare,GetKey && get_key)180   constexpr AATree(bool unique_keys, Compare&& compare, GetKey&& get_key)
181       : GenericAATree(unique_keys),
182         compare_(std::move(compare)),
183         get_key_(std::move(get_key)) {}
184 
185   // Modifiers
186 
187   /// Attempts to add the given item to the tree.
188   ///
189   /// The item will be added if the tree does not already contain an item with
190   /// the given item's key or if the tree does not require unique keys.
191   ///
192   /// @pre      The item must not be a part of any tree.
193   ///
194   /// @returns  A pointer to the inserted item and `true`, or a pointer to the
195   ///           existing item with same key and `false`.
196   std::pair<iterator, bool> insert(AATreeItem& item);
197 
198   /// Inserts each item from `first`, inclusive, to `last`, exclusive. If the
199   /// tree does not all duplicates and an equivalent item is already in the
200   /// tree, the item is ignored.
201   template <class Iterator>
202   void insert(Iterator first, Iterator last);
203 
204   using GenericAATree::erase_one;
205   using GenericAATree::erase_range;
206 
207   /// Removes items that match the given `key`, and returns an iterator to
208   /// the item after the removed items and the number of items removed.
209   size_t erase_all(Key key);
210 
211   /// Splices items from the `other` tree into this one.
212   ///
213   /// The receiving tree's `Compare` and `GetKey` functions are used when
214   /// inserting items.
215   void merge(AATree<K, V>& other);
216 
217   // Lookup
218 
219   /// Returns the number of items in the tree with the given key.
220   ///
221   /// If the tree requires unique keys, this simply 0 or 1.
222   size_t count(Key key);
223 
224   /// Returns a pointer to an item with the given key, or null if the tree does
225   /// not contain such an item.
226   iterator find(Key key);
227 
228   /// Returns a pair of items where the first points to the item with the
229   /// smallest key that is not less than the given key, and the second points to
230   /// the item with the smallest key that is greater than the given key.
231   std::pair<iterator, iterator> equal_range(Key key);
232 
233   /// Returns the item in the tree with the smallest key that is greater than or
234   /// equal to the given key, or null if the tree is empty.
235   iterator lower_bound(Key key);
236 
237   /// Returns the item in the tree with the smallest key that is strictly
238   /// greater than the given key, or null if the tree is empty.
239   iterator upper_bound(Key key);
240 
241  private:
242   /// Inserts the given `child` in the subtree rooted by `parent` and returns
243   /// the resulting tree. If the tree does not allow duplicates and an
244   /// equivalent item is already in the tree, the tree is unchanged and the
245   /// existing item is returned via `duplicate`.
246   AATreeItem* InsertImpl(AATreeItem& parent,
247                          AATreeItem& child,
248                          AATreeItem*& duplicate);
249 
250   /// Returns the item in the subtree rooted by the given `item` with the
251   /// smallest key that is greater than or equal to the given `key`, or null if
252   /// the subtree is empty.
253   AATreeItem* GetLowerBoundImpl(AATreeItem* item, Key key);
254 
255   /// Returns the item in the subtree rooted by the given `item` with the
256   /// smallest key that is strictly greater than the given `key`, or null if the
257   /// subtree is empty.
258   AATreeItem* GetUpperBoundImpl(AATreeItem* item, Key key);
259 
260   /// Returns the key associated with a tree item.
DoGetKey(const AATreeItem & item)261   constexpr Key DoGetKey(const AATreeItem& item) {
262     return get_key_(static_cast<const V&>(item));
263   }
264 
265   Compare compare_;
266   GetKey get_key_;
267 };
268 
269 // Template method implementations.
270 
271 template <typename K, typename V>
insert(AATreeItem & item)272 std::pair<GenericAATree::iterator, bool> AATree<K, V>::insert(
273     AATreeItem& item) {
274   CheckIntrusiveItemIsUncontained(!item.IsMapped());
275   item.SetLevel(1);
276   if (empty()) {
277     SetRoot(&item);
278     return std::make_pair(iterator(&root_, &item), true);
279   }
280   AATreeItem* duplicate = nullptr;
281   SetRoot(InsertImpl(*root_, item, duplicate));
282   if (duplicate == nullptr) {
283     return std::make_pair(iterator(&root_, &item), true);
284   }
285   item.Reset();
286   return std::make_pair(iterator(&root_, duplicate), false);
287 }
288 
289 template <typename K, typename V>
InsertImpl(AATreeItem & parent,AATreeItem & child,AATreeItem * & duplicate)290 AATreeItem* AATree<K, V>::InsertImpl(AATreeItem& parent,
291                                      AATreeItem& child,
292                                      AATreeItem*& duplicate) {
293   if (compare_(DoGetKey(child), DoGetKey(parent))) {
294     AATreeItem* left = parent.left_.get();
295     left = left == nullptr ? &child : InsertImpl(*left, child, duplicate);
296     parent.SetLeft(left);
297 
298   } else if (compare_(DoGetKey(parent), DoGetKey(child)) || !unique_keys()) {
299     AATreeItem* right = parent.right_.get();
300     right = right == nullptr ? &child : InsertImpl(*right, child, duplicate);
301     parent.SetRight(right);
302 
303   } else {
304     duplicate = &parent;
305     return &parent;
306   }
307 
308   return parent.Skew()->Split();
309 }
310 
311 template <typename K, typename V>
312 template <class Iterator>
insert(Iterator first,Iterator last)313 void AATree<K, V>::insert(Iterator first, Iterator last) {
314   for (Iterator iter = first; iter != last; ++iter) {
315     if constexpr (std::is_pointer_v<
316                       typename std::iterator_traits<Iterator>::value_type>) {
317       insert(**iter);
318     } else {
319       insert(*iter);
320     }
321   }
322 }
323 
324 template <typename K, typename V>
erase_all(Key key)325 size_t AATree<K, V>::erase_all(Key key) {
326   size_t removed = 0;
327   iterator iter = lower_bound(key);
328   while (iter != end() && !compare_(key, DoGetKey(*iter))) {
329     iter = erase_one(*iter);
330     ++removed;
331   }
332   return removed;
333 }
334 
335 template <typename K, typename V>
merge(AATree<K,V> & other)336 void AATree<K, V>::merge(AATree<K, V>& other) {
337   auto iter = other.begin();
338   while (!other.empty()) {
339     AATreeItem& item = *iter;
340     iter = other.erase_one(item);
341     insert(item);
342   }
343 }
344 
345 template <typename K, typename V>
count(Key key)346 size_t AATree<K, V>::count(Key key) {
347   return std::distance(lower_bound(key), upper_bound(key));
348 }
349 
350 template <typename K, typename V>
find(Key key)351 GenericAATree::iterator AATree<K, V>::find(Key key) {
352   iterator iter = lower_bound(key);
353   if (iter == end() || compare_(key, DoGetKey(*iter))) {
354     return end();
355   }
356   return iter;
357 }
358 
359 template <typename K, typename V>
360 std::pair<GenericAATree::iterator, GenericAATree::iterator>
equal_range(Key key)361 AATree<K, V>::equal_range(Key key) {
362   return std::make_pair(lower_bound(key), upper_bound(key));
363 }
364 
365 template <typename K, typename V>
lower_bound(Key key)366 GenericAATree::iterator AATree<K, V>::lower_bound(Key key) {
367   AATreeItem* item = GetLowerBoundImpl(root_, key);
368   return item == nullptr ? end() : iterator(&root_, item);
369 }
370 
371 template <typename K, typename V>
GetLowerBoundImpl(AATreeItem * item,Key key)372 AATreeItem* AATree<K, V>::GetLowerBoundImpl(AATreeItem* item, Key key) {
373   if (item == nullptr) {
374     return nullptr;
375   }
376   // If the item's key is less than the key, go right.
377   if (compare_(DoGetKey(*item), key)) {
378     return GetLowerBoundImpl(item->right_.get(), key);
379   }
380   // Otherwise the item's key is greater than the key. Try to go left.
381   AATreeItem* left = item->left_.get();
382   if (left == nullptr) {
383     return item;
384   }
385   AATreeItem* next = GetLowerBoundImpl(left, key);
386   return next == nullptr ? item : next;
387 }
388 
389 template <typename K, typename V>
upper_bound(Key key)390 GenericAATree::iterator AATree<K, V>::upper_bound(Key key) {
391   AATreeItem* item = GetUpperBoundImpl(root_, key);
392   return item == nullptr ? end() : iterator(&root_, item);
393 }
394 
395 template <typename K, typename V>
GetUpperBoundImpl(AATreeItem * item,Key key)396 AATreeItem* AATree<K, V>::GetUpperBoundImpl(AATreeItem* item, Key key) {
397   if (item == nullptr) {
398     return nullptr;
399   }
400   // If the item's key is less than or equal to the key, go right.
401   if (!compare_(key, DoGetKey(*item))) {
402     return GetUpperBoundImpl(item->right_.get(), key);
403   }
404   // Otherwise the item's key is greater than the key. Try to go left.
405   AATreeItem* left = item->left_.get();
406   if (left == nullptr) {
407     return item;
408   }
409   AATreeItem* next = GetUpperBoundImpl(left, key);
410   return next == nullptr ? item : next;
411 }
412 
413 }  // namespace pw::containers::internal
414