C/C++ API Reference
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
30
37 public:
38 using iterator = AATreeIterator<>;
39
44 constexpr explicit GenericAATree(bool unique_keys)
45 : unique_keys_(unique_keys) {}
46
48 ~GenericAATree() { CheckIntrusiveContainerIsEmpty(empty()); }
49
50 // Intrusive trees cannot be copied, since each Item can only be in one tree.
51 GenericAATree(const GenericAATree&) = delete;
52 GenericAATree& operator=(const GenericAATree&) = delete;
53
54 [[nodiscard]] constexpr bool unique_keys() const { return unique_keys_; }
55
57 void SetRoot(AATreeItem* item);
58
59 // Iterators
60
62 constexpr iterator begin() noexcept {
63 return empty() ? iterator(&root_) : iterator(&root_, root_->GetLeftmost());
64 }
65
67 constexpr iterator end() noexcept {
68 return empty() ? iterator(&root_)
69 : ++(iterator(&root_, root_->GetRightmost()));
70 }
71
72 // Capacity
73
75 [[nodiscard]] constexpr bool empty() const { return root_ == nullptr; }
76
78 size_t size() const;
79
83 constexpr size_t max_size() const noexcept {
84 return std::numeric_limits<ptrdiff_t>::max();
85 }
86
87 // Modifiers
88
92 void clear();
93
98 iterator erase_one(AATreeItem& item);
99
104 iterator erase_range(AATreeItem& first, AATreeItem& last);
105
111 iterator erase_range(iterator first, iterator last);
112
114 void swap(GenericAATree& other);
115
116 private:
117 // The derived, templated type needs to be able to access the root element.
118 template <typename>
119 friend class KeyedAATree;
120
122 AATreeItem* root_ = nullptr;
123
135 const bool unique_keys_;
136};
137
147template <typename K>
149 public:
150 using Key = K;
151 using Compare = Function<bool(Key, Key)>;
152 using GetKey = Function<Key(const AATreeItem&)>;
153 using GenericAATree::iterator;
154
159 constexpr explicit KeyedAATree(bool unique_keys,
160 Compare&& compare,
161 GetKey&& get_key)
162 : GenericAATree(unique_keys),
163 compare_(std::move(compare)),
164 get_key_(std::move(get_key)) {}
165
166 // Modifiers
167
168 void SetCompare(Compare&& compare) { compare_ = std::move(compare); }
169 void SetGetKey(GetKey&& get_key) { get_key_ = std::move(get_key); }
170
180 std::pair<iterator, bool> insert(AATreeItem& item);
181
185 template <class Iterator>
186 void insert(Iterator first, Iterator last);
187
190
193 size_t erase_all(Key key);
194
199 void merge(KeyedAATree<K>& other);
200
201 // Lookup
202
206 size_t count(Key key);
207
210 iterator find(Key key);
211
215 std::pair<iterator, iterator> equal_range(Key key);
216
219 iterator lower_bound(Key key);
220
223 iterator upper_bound(Key key);
224
225 private:
230 AATreeItem* InsertImpl(AATreeItem& parent,
231 AATreeItem& child,
232 AATreeItem*& duplicate);
233
237 AATreeItem* GetLowerBoundImpl(AATreeItem* item, Key key);
238
242 AATreeItem* GetUpperBoundImpl(AATreeItem* item, Key key);
243
244 Compare compare_;
245 GetKey get_key_;
246};
247
259template <typename K, typename V>
260class AATree final : public KeyedAATree<K> {
261 public:
262 using Base = KeyedAATree<K>;
263 using Key = typename Base::Key;
264 using Compare = typename Base::Compare;
265 using GetKey = Function<Key(const V&)>;
266
271 class Item : public AATreeItem {
272 public:
273 constexpr explicit Item() = default;
274
275 private:
276 // IntrusiveItem is used to ensure T inherits from this container's Item
277 // type. See also `CheckItemType`.
278 template <typename, typename, bool>
279 friend struct IntrusiveItem;
280 using ItemType = V;
281 };
282
284 class Pair : public Item {
285 public:
286 constexpr explicit Pair(Key key) : key_(key) {}
287 constexpr Key key() const { return key_; }
288
289 constexpr bool operator<(const Pair& rhs) { return key_ < rhs.key(); }
290
291 private:
292 const Key key_;
293 };
294
299 constexpr AATree(bool unique_keys, Compare&& compare, GetKey&& get_key)
300 : KeyedAATree<Key>(unique_keys,
301 std::move(compare),
302 std::move([this](const AATreeItem& item) -> Key {
303 return get_key_(static_cast<const V&>(item));
304 })),
305 get_key_(std::move(get_key)) {}
306
307 GetKey get_key_;
308};
309
310// Template method implementations.
311
312template <typename K>
313std::pair<GenericAATree::iterator, bool> KeyedAATree<K>::insert(
314 AATreeItem& item) {
315 CheckIntrusiveItemIsUncontained(!item.IsMapped());
316 item.SetLevel(1);
317 if (empty()) {
318 SetRoot(&item);
319 return std::make_pair(iterator(&root_, &item), true);
320 }
321 AATreeItem* duplicate = nullptr;
322 SetRoot(InsertImpl(*root_, item, duplicate));
323 if (duplicate == nullptr) {
324 return std::make_pair(iterator(&root_, &item), true);
325 }
326 item.Reset();
327 return std::make_pair(iterator(&root_, duplicate), false);
328}
329
330template <typename K>
331AATreeItem* KeyedAATree<K>::InsertImpl(AATreeItem& parent,
332 AATreeItem& child,
333 AATreeItem*& duplicate) {
334 if (compare_(get_key_(child), get_key_(parent))) {
335 AATreeItem* left = parent.left_.get();
336 left = left == nullptr ? &child : InsertImpl(*left, child, duplicate);
337 parent.SetLeft(left);
338
339 } else if (compare_(get_key_(parent), get_key_(child)) || !unique_keys()) {
340 AATreeItem* right = parent.right_.get();
341 right = right == nullptr ? &child : InsertImpl(*right, child, duplicate);
342 parent.SetRight(right);
343
344 } else {
345 duplicate = &parent;
346 return &parent;
347 }
348
349 return parent.Skew()->Split();
350}
351
352template <typename K>
353template <class Iterator>
354void KeyedAATree<K>::insert(Iterator first, Iterator last) {
355 for (Iterator iter = first; iter != last; ++iter) {
356 if constexpr (std::is_pointer_v<
357 typename std::iterator_traits<Iterator>::value_type>) {
358 insert(**iter);
359 } else {
360 insert(*iter);
361 }
362 }
363}
364
365template <typename K>
367 size_t removed = 0;
368 iterator iter = lower_bound(key);
369 while (iter != end() && !compare_(key, get_key_(*iter))) {
370 iter = erase_one(*iter);
371 ++removed;
372 }
373 return removed;
374}
375
376template <typename K>
378 auto iter = other.begin();
379 while (!other.empty()) {
380 AATreeItem& item = *iter;
381 iter = other.erase_one(item);
382 insert(item);
383 }
384}
385
386template <typename K>
387size_t KeyedAATree<K>::count(Key key) {
388 return std::distance(lower_bound(key), upper_bound(key));
389}
390
391template <typename K>
392GenericAATree::iterator KeyedAATree<K>::find(Key key) {
393 iterator iter = lower_bound(key);
394 if (iter == end() || compare_(key, get_key_(*iter))) {
395 return end();
396 }
397 return iter;
398}
399
400template <typename K>
401std::pair<GenericAATree::iterator, GenericAATree::iterator>
403 return std::make_pair(lower_bound(key), upper_bound(key));
404}
405
406template <typename K>
407GenericAATree::iterator KeyedAATree<K>::lower_bound(Key key) {
408 AATreeItem* item = GetLowerBoundImpl(root_, key);
409 return item == nullptr ? end() : iterator(&root_, item);
410}
411
412template <typename K>
413AATreeItem* KeyedAATree<K>::GetLowerBoundImpl(AATreeItem* item, Key key) {
414 if (item == nullptr) {
415 return nullptr;
416 }
417 // If the item's key is less than the key, go right.
418 if (compare_(get_key_(*item), key)) {
419 return GetLowerBoundImpl(item->right_.get(), key);
420 }
421 // Otherwise the item's key is greater than the key. Try to go left.
422 AATreeItem* left = item->left_.get();
423 if (left == nullptr) {
424 return item;
425 }
426 AATreeItem* next = GetLowerBoundImpl(left, key);
427 return next == nullptr ? item : next;
428}
429
430template <typename K>
431GenericAATree::iterator KeyedAATree<K>::upper_bound(Key key) {
432 AATreeItem* item = GetUpperBoundImpl(root_, key);
433 return item == nullptr ? end() : iterator(&root_, item);
434}
435
436template <typename K>
437AATreeItem* KeyedAATree<K>::GetUpperBoundImpl(AATreeItem* item, Key key) {
438 if (item == nullptr) {
439 return nullptr;
440 }
441 // If the item's key is less than or equal to the key, go right.
442 if (!compare_(key, get_key_(*item))) {
443 return GetUpperBoundImpl(item->right_.get(), key);
444 }
445 // Otherwise the item's key is greater than the key. Try to go left.
446 AATreeItem* left = item->left_.get();
447 if (left == nullptr) {
448 return item;
449 }
450 AATreeItem* next = GetUpperBoundImpl(left, key);
451 return next == nullptr ? item : next;
452}
453
454} // namespace pw::containers::internal
An extension of Item that includes storage for a key.
Definition: aa_tree.h:284
Definition: aa_tree.h:260
Definition: aa_tree.h:148
iterator erase_one(AATreeItem &item)
iterator erase_range(AATreeItem &first, AATreeItem &last)
iterator lower_bound(Key key)
Definition: aa_tree.h:407
constexpr iterator begin() noexcept
Returns a pointer to the first item, if any.
Definition: aa_tree.h:62
constexpr size_t max_size() const noexcept
Definition: aa_tree.h:83
std::pair< iterator, iterator > equal_range(Key key)
Definition: aa_tree.h:402
iterator upper_bound(Key key)
Definition: aa_tree.h:431
void insert(Iterator first, Iterator last)
Definition: aa_tree.h:354
void merge(KeyedAATree< K > &other)
Definition: aa_tree.h:377
iterator find(Key key)
Definition: aa_tree.h:392
std::pair< iterator, bool > insert(AATreeItem &item)
Definition: aa_tree.h:313
iterator erase_one(AATreeItem &item)
iterator erase_range(iterator first, iterator last)
size_t erase_all(Key key)
Definition: aa_tree.h:366
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:48
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:75
constexpr GenericAATree(bool unique_keys)
Definition: aa_tree.h:44
constexpr KeyedAATree(bool unique_keys, Compare &&compare, GetKey &&get_key)
Definition: aa_tree.h:159
size_t count(Key key)
Definition: aa_tree.h:387
constexpr AATree(bool unique_keys, Compare &&compare, GetKey &&get_key)
Definition: aa_tree.h:299
constexpr iterator end() noexcept
Returns a pointer to the last item, if any.
Definition: aa_tree.h:67
fit::function_impl< function_internal::config::kInlineCallableSize, !function_internal::config::kEnableDynamicAllocation, FunctionType, PW_FUNCTION_DEFAULT_ALLOCATOR_TYPE > Function
Definition: function.h:73