Pigweed
C/C++ API Reference
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
aa_tree.h
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
27namespace pw::containers::internal {
28
35 public:
36 using iterator = AATreeIterator<>;
37
42 constexpr explicit GenericAATree(bool unique_keys)
43 : unique_keys_(unique_keys) {}
44
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
52 [[nodiscard]] constexpr bool unique_keys() const { return unique_keys_; }
53
55 void SetRoot(AATreeItem* item);
56
57 // Iterators
58
60 constexpr iterator begin() noexcept {
61 return empty() ? iterator(&root_) : iterator(&root_, root_->GetLeftmost());
62 }
63
65 constexpr iterator end() noexcept {
66 return empty() ? iterator(&root_)
67 : ++(iterator(&root_, root_->GetRightmost()));
68 }
69
70 // Capacity
71
73 [[nodiscard]] constexpr bool empty() const { return root_ == nullptr; }
74
76 size_t size() const;
77
81 constexpr size_t max_size() const noexcept {
82 return std::numeric_limits<ptrdiff_t>::max();
83 }
84
85 // Modifiers
86
90 void clear();
91
96 iterator erase_one(AATreeItem& item);
97
102 iterator erase_range(AATreeItem& first, AATreeItem& last);
103
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>
110 friend class KeyedAATree;
111
113 AATreeItem* root_ = nullptr;
114
126 const bool unique_keys_;
127};
128
138template <typename K>
140 public:
141 using Key = K;
142 using Compare = Function<bool(Key, Key)>;
143 using GetKey = Function<Key(const AATreeItem&)>;
144 using GenericAATree::iterator;
145
150 constexpr explicit KeyedAATree(bool unique_keys,
151 Compare&& compare,
152 GetKey&& get_key)
153 : GenericAATree(unique_keys),
154 compare_(std::move(compare)),
155 get_key_(std::move(get_key)) {}
156
157 // Modifiers
158
159 void SetCompare(Compare&& compare) { compare_ = std::move(compare); }
160 void SetGetKey(GetKey&& get_key) { get_key_ = std::move(get_key); }
161
171 std::pair<iterator, bool> insert(AATreeItem& item);
172
176 template <class Iterator>
177 void insert(Iterator first, Iterator last);
178
181
184 size_t erase_all(Key key);
185
190 void merge(KeyedAATree<K>& other);
191
192 // Lookup
193
197 size_t count(Key key);
198
201 iterator find(Key key);
202
206 std::pair<iterator, iterator> equal_range(Key key);
207
210 iterator lower_bound(Key key);
211
214 iterator upper_bound(Key key);
215
216 private:
221 AATreeItem* InsertImpl(AATreeItem& parent,
222 AATreeItem& child,
223 AATreeItem*& duplicate);
224
228 AATreeItem* GetLowerBoundImpl(AATreeItem* item, Key key);
229
233 AATreeItem* GetUpperBoundImpl(AATreeItem* item, Key key);
234
235 Compare compare_;
236 GetKey get_key_;
237};
238
250template <typename K, typename V>
251class AATree final : public KeyedAATree<K> {
252 public:
253 using Base = KeyedAATree<K>;
254 using Key = typename Base::Key;
255 using Compare = typename Base::Compare;
256 using GetKey = Function<Key(const V&)>;
257
262 class Item : public AATreeItem {
263 public:
264 constexpr explicit Item() = default;
265
266 private:
267 // IntrusiveItem is used to ensure T inherits from this container's Item
268 // type. See also `CheckItemType`.
269 template <typename, typename, bool>
270 friend struct IntrusiveItem;
271 using ItemType = V;
272 };
273
275 class Pair : public Item {
276 public:
277 constexpr explicit Pair(Key key) : key_(key) {}
278 constexpr Key key() const { return key_; }
279
280 constexpr bool operator<(const Pair& rhs) { return key_ < rhs.key(); }
281
282 private:
283 const Key key_;
284 };
285
290 constexpr AATree(bool unique_keys, Compare&& compare, GetKey&& get_key)
291 : KeyedAATree<Key>(unique_keys,
292 std::move(compare),
293 std::move([this](const AATreeItem& item) -> Key {
294 return get_key_(static_cast<const V&>(item));
295 })),
296 get_key_(std::move(get_key)) {}
297
298 GetKey get_key_;
299};
300
301// Template method implementations.
302
303template <typename K>
304std::pair<GenericAATree::iterator, bool> KeyedAATree<K>::insert(
305 AATreeItem& item) {
306 CheckIntrusiveItemIsUncontained(!item.IsMapped());
307 item.SetLevel(1);
308 if (empty()) {
309 SetRoot(&item);
310 return std::make_pair(iterator(&root_, &item), true);
311 }
312 AATreeItem* duplicate = nullptr;
313 SetRoot(InsertImpl(*root_, item, duplicate));
314 if (duplicate == nullptr) {
315 return std::make_pair(iterator(&root_, &item), true);
316 }
317 item.Reset();
318 return std::make_pair(iterator(&root_, duplicate), false);
319}
320
321template <typename K>
322AATreeItem* KeyedAATree<K>::InsertImpl(AATreeItem& parent,
323 AATreeItem& child,
324 AATreeItem*& duplicate) {
325 if (compare_(get_key_(child), get_key_(parent))) {
326 AATreeItem* left = parent.left_.get();
327 left = left == nullptr ? &child : InsertImpl(*left, child, duplicate);
328 parent.SetLeft(left);
329
330 } else if (compare_(get_key_(parent), get_key_(child)) || !unique_keys()) {
331 AATreeItem* right = parent.right_.get();
332 right = right == nullptr ? &child : InsertImpl(*right, child, duplicate);
333 parent.SetRight(right);
334
335 } else {
336 duplicate = &parent;
337 return &parent;
338 }
339
340 return parent.Skew()->Split();
341}
342
343template <typename K>
344template <class Iterator>
345void KeyedAATree<K>::insert(Iterator first, Iterator last) {
346 for (Iterator iter = first; iter != last; ++iter) {
347 if constexpr (std::is_pointer_v<
348 typename std::iterator_traits<Iterator>::value_type>) {
349 insert(**iter);
350 } else {
351 insert(*iter);
352 }
353 }
354}
355
356template <typename K>
358 size_t removed = 0;
359 iterator iter = lower_bound(key);
360 while (iter != end() && !compare_(key, get_key_(*iter))) {
361 iter = erase_one(*iter);
362 ++removed;
363 }
364 return removed;
365}
366
367template <typename K>
369 auto iter = other.begin();
370 while (!other.empty()) {
371 AATreeItem& item = *iter;
372 iter = other.erase_one(item);
373 insert(item);
374 }
375}
376
377template <typename K>
378size_t KeyedAATree<K>::count(Key key) {
379 return std::distance(lower_bound(key), upper_bound(key));
380}
381
382template <typename K>
383GenericAATree::iterator KeyedAATree<K>::find(Key key) {
384 iterator iter = lower_bound(key);
385 if (iter == end() || compare_(key, get_key_(*iter))) {
386 return end();
387 }
388 return iter;
389}
390
391template <typename K>
392std::pair<GenericAATree::iterator, GenericAATree::iterator>
394 return std::make_pair(lower_bound(key), upper_bound(key));
395}
396
397template <typename K>
398GenericAATree::iterator KeyedAATree<K>::lower_bound(Key key) {
399 AATreeItem* item = GetLowerBoundImpl(root_, key);
400 return item == nullptr ? end() : iterator(&root_, item);
401}
402
403template <typename K>
404AATreeItem* KeyedAATree<K>::GetLowerBoundImpl(AATreeItem* item, Key key) {
405 if (item == nullptr) {
406 return nullptr;
407 }
408 // If the item's key is less than the key, go right.
409 if (compare_(get_key_(*item), key)) {
410 return GetLowerBoundImpl(item->right_.get(), key);
411 }
412 // Otherwise the item's key is greater than the key. Try to go left.
413 AATreeItem* left = item->left_.get();
414 if (left == nullptr) {
415 return item;
416 }
417 AATreeItem* next = GetLowerBoundImpl(left, key);
418 return next == nullptr ? item : next;
419}
420
421template <typename K>
422GenericAATree::iterator KeyedAATree<K>::upper_bound(Key key) {
423 AATreeItem* item = GetUpperBoundImpl(root_, key);
424 return item == nullptr ? end() : iterator(&root_, item);
425}
426
427template <typename K>
428AATreeItem* KeyedAATree<K>::GetUpperBoundImpl(AATreeItem* item, Key key) {
429 if (item == nullptr) {
430 return nullptr;
431 }
432 // If the item's key is less than or equal to the key, go right.
433 if (!compare_(key, get_key_(*item))) {
434 return GetUpperBoundImpl(item->right_.get(), key);
435 }
436 // Otherwise the item's key is greater than the key. Try to go left.
437 AATreeItem* left = item->left_.get();
438 if (left == nullptr) {
439 return item;
440 }
441 AATreeItem* next = GetUpperBoundImpl(left, key);
442 return next == nullptr ? item : next;
443}
444
445} // namespace pw::containers::internal
An extension of Item that includes storage for a key.
Definition: aa_tree.h:275
Definition: aa_tree.h:251
constexpr AATree(bool unique_keys, Compare &&compare, GetKey &&get_key)
Definition: aa_tree.h:290
iterator erase_range(AATreeItem &first, AATreeItem &last)
constexpr iterator begin() noexcept
Returns a pointer to the first item, if any.
Definition: aa_tree.h:60
constexpr size_t max_size() const noexcept
Definition: aa_tree.h:81
iterator erase_one(AATreeItem &item)
void swap(GenericAATree &other)
Exchanges this tree's items with the other tree's items.
size_t size() const
Returns the number of items in the tree.
~GenericAATree()
Destructor.
Definition: aa_tree.h:46
void SetRoot(AATreeItem *item)
Sets the tree's root item.
constexpr bool empty() const
Returns whether the tree has zero items or not.
Definition: aa_tree.h:73
constexpr GenericAATree(bool unique_keys)
Definition: aa_tree.h:42
constexpr iterator end() noexcept
Returns a pointer to the last item, if any.
Definition: aa_tree.h:65
Definition: aa_tree.h:139
iterator lower_bound(Key key)
Definition: aa_tree.h:398
std::pair< iterator, iterator > equal_range(Key key)
Definition: aa_tree.h:393
iterator upper_bound(Key key)
Definition: aa_tree.h:422
void insert(Iterator first, Iterator last)
Definition: aa_tree.h:345
void merge(KeyedAATree< K > &other)
Definition: aa_tree.h:368
iterator find(Key key)
Definition: aa_tree.h:383
std::pair< iterator, bool > insert(AATreeItem &item)
Definition: aa_tree.h:304
iterator erase_one(AATreeItem &item)
size_t erase_all(Key key)
Definition: aa_tree.h:357
constexpr KeyedAATree(bool unique_keys, Compare &&compare, GetKey &&get_key)
Definition: aa_tree.h:150
size_t count(Key key)
Definition: aa_tree.h:378
fit::function_impl< function_internal::config::kInlineCallableSize, !function_internal::config::kEnableDynamicAllocation, FunctionType, PW_FUNCTION_DEFAULT_ALLOCATOR_TYPE > Function
Definition: function.h:74