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