Pigweed
 
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, typename>
110 friend class AATree;
111
113 AATreeItem* root_ = nullptr;
114
126 const bool unique_keys_;
127};
128
140template <typename K, typename V>
141class 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
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
165 class Pair : public Item {
166 public:
167 constexpr explicit Pair(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
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
196 std::pair<iterator, bool> insert(AATreeItem& item);
197
201 template <class Iterator>
202 void insert(Iterator first, Iterator last);
203
206
209 size_t erase_all(Key key);
210
215 void merge(AATree<K, V>& other);
216
217 // Lookup
218
222 size_t count(Key key);
223
226 iterator find(Key key);
227
231 std::pair<iterator, iterator> equal_range(Key key);
232
235 iterator lower_bound(Key key);
236
239 iterator upper_bound(Key key);
240
241 private:
246 AATreeItem* InsertImpl(AATreeItem& parent,
247 AATreeItem& child,
248 AATreeItem*& duplicate);
249
253 AATreeItem* GetLowerBoundImpl(AATreeItem* item, Key key);
254
258 AATreeItem* GetUpperBoundImpl(AATreeItem* item, Key key);
259
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
271template <typename K, typename V>
272std::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
289template <typename K, typename V>
290AATreeItem* 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
311template <typename K, typename V>
312template <class Iterator>
313void 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
324template <typename K, typename V>
325size_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
335template <typename K, typename V>
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
345template <typename K, typename V>
346size_t AATree<K, V>::count(Key key) {
347 return std::distance(lower_bound(key), upper_bound(key));
348}
349
350template <typename K, typename V>
351GenericAATree::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
359template <typename K, typename V>
360std::pair<GenericAATree::iterator, GenericAATree::iterator>
362 return std::make_pair(lower_bound(key), upper_bound(key));
363}
364
365template <typename K, typename V>
366GenericAATree::iterator AATree<K, V>::lower_bound(Key key) {
367 AATreeItem* item = GetLowerBoundImpl(root_, key);
368 return item == nullptr ? end() : iterator(&root_, item);
369}
370
371template <typename K, typename V>
372AATreeItem* 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
389template <typename K, typename V>
390GenericAATree::iterator AATree<K, V>::upper_bound(Key key) {
391 AATreeItem* item = GetUpperBoundImpl(root_, key);
392 return item == nullptr ? end() : iterator(&root_, item);
393}
394
395template <typename K, typename V>
396AATreeItem* 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
An extension of Item that includes storage for a key.
Definition: aa_tree.h:165
Definition: aa_tree.h:141
iterator find(Key key)
Definition: aa_tree.h:351
std::pair< iterator, bool > insert(AATreeItem &item)
Definition: aa_tree.h:272
size_t erase_all(Key key)
Definition: aa_tree.h:325
iterator upper_bound(Key key)
Definition: aa_tree.h:390
iterator erase_one(AATreeItem &item)
std::pair< iterator, iterator > equal_range(Key key)
Definition: aa_tree.h:361
void insert(Iterator first, Iterator last)
Definition: aa_tree.h:313
iterator lower_bound(Key key)
Definition: aa_tree.h:366
void merge(AATree< K, V > &other)
Definition: aa_tree.h:336
size_t count(Key key)
Definition: aa_tree.h:346
constexpr AATree(bool unique_keys, Compare &&compare, GetKey &&get_key)
Definition: aa_tree.h:180
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
fit::function_impl< function_internal::config::kInlineCallableSize, !function_internal::config::kEnableDynamicAllocation, FunctionType, PW_FUNCTION_DEFAULT_ALLOCATOR_TYPE > Function
Definition: function.h:74