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
107 void swap(GenericAATree& other);
108
109 private:
110 // The derived, templated type needs to be able to access the root element.
111 template <typename>
112 friend class KeyedAATree;
113
115 AATreeItem* root_ = nullptr;
116
128 const bool unique_keys_;
129};
130
140template <typename K>
142 public:
143 using Key = K;
144 using Compare = Function<bool(Key, Key)>;
145 using GetKey = Function<Key(const AATreeItem&)>;
146 using GenericAATree::iterator;
147
152 constexpr explicit KeyedAATree(bool unique_keys,
153 Compare&& compare,
154 GetKey&& get_key)
155 : GenericAATree(unique_keys),
156 compare_(std::move(compare)),
157 get_key_(std::move(get_key)) {}
158
159 // Modifiers
160
161 void SetCompare(Compare&& compare) { compare_ = std::move(compare); }
162 void SetGetKey(GetKey&& get_key) { get_key_ = std::move(get_key); }
163
173 std::pair<iterator, bool> insert(AATreeItem& item);
174
178 template <class Iterator>
179 void insert(Iterator first, Iterator last);
180
183
186 size_t erase_all(Key key);
187
192 void merge(KeyedAATree<K>& other);
193
194 // Lookup
195
199 size_t count(Key key);
200
203 iterator find(Key key);
204
208 std::pair<iterator, iterator> equal_range(Key key);
209
212 iterator lower_bound(Key key);
213
216 iterator upper_bound(Key key);
217
218 private:
223 AATreeItem* InsertImpl(AATreeItem& parent,
224 AATreeItem& child,
225 AATreeItem*& duplicate);
226
230 AATreeItem* GetLowerBoundImpl(AATreeItem* item, Key key);
231
235 AATreeItem* GetUpperBoundImpl(AATreeItem* item, Key key);
236
237 Compare compare_;
238 GetKey get_key_;
239};
240
252template <typename K, typename V>
253class AATree final : public KeyedAATree<K> {
254 public:
255 using Base = KeyedAATree<K>;
256 using Key = typename Base::Key;
257 using Compare = typename Base::Compare;
258 using GetKey = Function<Key(const V&)>;
259
264 class Item : public AATreeItem {
265 public:
266 constexpr explicit Item() = default;
267
268 private:
269 // IntrusiveItem is used to ensure T inherits from this container's Item
270 // type. See also `CheckItemType`.
271 template <typename, typename, bool>
272 friend struct IntrusiveItem;
273 using ItemType = V;
274 };
275
277 class Pair : public Item {
278 public:
279 constexpr explicit Pair(Key key) : key_(key) {}
280 constexpr Key key() const { return key_; }
281
282 constexpr bool operator<(const Pair& rhs) { return key_ < rhs.key(); }
283
284 private:
285 const Key key_;
286 };
287
292 constexpr AATree(bool unique_keys, Compare&& compare, GetKey&& get_key)
293 : KeyedAATree<Key>(unique_keys,
294 std::move(compare),
295 std::move([this](const AATreeItem& item) -> Key {
296 return get_key_(static_cast<const V&>(item));
297 })),
298 get_key_(std::move(get_key)) {}
299
300 GetKey get_key_;
301};
302
303// Template method implementations.
304
305template <typename K>
306std::pair<GenericAATree::iterator, bool> KeyedAATree<K>::insert(
307 AATreeItem& item) {
308 CheckIntrusiveItemIsUncontained(!item.IsMapped());
309 item.SetLevel(1);
310 if (empty()) {
311 SetRoot(&item);
312 return std::make_pair(iterator(&root_, &item), true);
313 }
314 AATreeItem* duplicate = nullptr;
315 SetRoot(InsertImpl(*root_, item, duplicate));
316 if (duplicate == nullptr) {
317 return std::make_pair(iterator(&root_, &item), true);
318 }
319 item.Reset();
320 return std::make_pair(iterator(&root_, duplicate), false);
321}
322
323template <typename K>
324AATreeItem* KeyedAATree<K>::InsertImpl(AATreeItem& parent,
325 AATreeItem& child,
326 AATreeItem*& duplicate) {
327 if (compare_(get_key_(child), get_key_(parent))) {
328 AATreeItem* left = parent.left_.get();
329 left = left == nullptr ? &child : InsertImpl(*left, child, duplicate);
330 parent.SetLeft(left);
331
332 } else if (compare_(get_key_(parent), get_key_(child)) || !unique_keys()) {
333 AATreeItem* right = parent.right_.get();
334 right = right == nullptr ? &child : InsertImpl(*right, child, duplicate);
335 parent.SetRight(right);
336
337 } else {
338 duplicate = &parent;
339 return &parent;
340 }
341
342 return parent.Skew()->Split();
343}
344
345template <typename K>
346template <class Iterator>
347void KeyedAATree<K>::insert(Iterator first, Iterator last) {
348 for (Iterator iter = first; iter != last; ++iter) {
349 if constexpr (std::is_pointer_v<
350 typename std::iterator_traits<Iterator>::value_type>) {
351 insert(**iter);
352 } else {
353 insert(*iter);
354 }
355 }
356}
357
358template <typename K>
360 size_t removed = 0;
361 iterator iter = lower_bound(key);
362 while (iter != end() && !compare_(key, get_key_(*iter))) {
363 iter = erase_one(*iter);
364 ++removed;
365 }
366 return removed;
367}
368
369template <typename K>
371 auto iter = other.begin();
372 while (!other.empty()) {
373 AATreeItem& item = *iter;
374 iter = other.erase_one(item);
375 insert(item);
376 }
377}
378
379template <typename K>
380size_t KeyedAATree<K>::count(Key key) {
381 return std::distance(lower_bound(key), upper_bound(key));
382}
383
384template <typename K>
385GenericAATree::iterator KeyedAATree<K>::find(Key key) {
386 iterator iter = lower_bound(key);
387 if (iter == end() || compare_(key, get_key_(*iter))) {
388 return end();
389 }
390 return iter;
391}
392
393template <typename K>
394std::pair<GenericAATree::iterator, GenericAATree::iterator>
396 return std::make_pair(lower_bound(key), upper_bound(key));
397}
398
399template <typename K>
400GenericAATree::iterator KeyedAATree<K>::lower_bound(Key key) {
401 AATreeItem* item = GetLowerBoundImpl(root_, key);
402 return item == nullptr ? end() : iterator(&root_, item);
403}
404
405template <typename K>
406AATreeItem* KeyedAATree<K>::GetLowerBoundImpl(AATreeItem* item, Key key) {
407 if (item == nullptr) {
408 return nullptr;
409 }
410 // If the item's key is less than the key, go right.
411 if (compare_(get_key_(*item), key)) {
412 return GetLowerBoundImpl(item->right_.get(), key);
413 }
414 // Otherwise the item's key is greater than the key. Try to go left.
415 AATreeItem* left = item->left_.get();
416 if (left == nullptr) {
417 return item;
418 }
419 AATreeItem* next = GetLowerBoundImpl(left, key);
420 return next == nullptr ? item : next;
421}
422
423template <typename K>
424GenericAATree::iterator KeyedAATree<K>::upper_bound(Key key) {
425 AATreeItem* item = GetUpperBoundImpl(root_, key);
426 return item == nullptr ? end() : iterator(&root_, item);
427}
428
429template <typename K>
430AATreeItem* KeyedAATree<K>::GetUpperBoundImpl(AATreeItem* item, Key key) {
431 if (item == nullptr) {
432 return nullptr;
433 }
434 // If the item's key is less than or equal to the key, go right.
435 if (!compare_(key, get_key_(*item))) {
436 return GetUpperBoundImpl(item->right_.get(), key);
437 }
438 // Otherwise the item's key is greater than the key. Try to go left.
439 AATreeItem* left = item->left_.get();
440 if (left == nullptr) {
441 return item;
442 }
443 AATreeItem* next = GetUpperBoundImpl(left, key);
444 return next == nullptr ? item : next;
445}
446
447} // namespace pw::containers::internal
An extension of Item that includes storage for a key.
Definition: aa_tree.h:277
Definition: aa_tree.h:253
Definition: aa_tree.h:141
iterator erase_one(AATreeItem &item)
iterator erase_range(AATreeItem &first, AATreeItem &last)
iterator lower_bound(Key key)
Definition: aa_tree.h:400
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:395
iterator upper_bound(Key key)
Definition: aa_tree.h:424
void insert(Iterator first, Iterator last)
Definition: aa_tree.h:347
void merge(KeyedAATree< K > &other)
Definition: aa_tree.h:370
iterator find(Key key)
Definition: aa_tree.h:385
std::pair< iterator, bool > insert(AATreeItem &item)
Definition: aa_tree.h:306
iterator erase_one(AATreeItem &item)
size_t erase_all(Key key)
Definition: aa_tree.h:359
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:152
size_t count(Key key)
Definition: aa_tree.h:380
constexpr AATree(bool unique_keys, Compare &&compare, GetKey &&get_key)
Definition: aa_tree.h:292
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