1*61c4878aSAndroid Build Coastguard Worker // Copyright 2024 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker #include "pw_containers/internal/aa_tree_item.h"
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker namespace pw::containers::internal {
18*61c4878aSAndroid Build Coastguard Worker
GetLevel() const19*61c4878aSAndroid Build Coastguard Worker uint8_t AATreeItem::GetLevel() const {
20*61c4878aSAndroid Build Coastguard Worker return parent_.packed_value() | (left_.packed_value() << 2) |
21*61c4878aSAndroid Build Coastguard Worker (right_.packed_value() << 4);
22*61c4878aSAndroid Build Coastguard Worker }
23*61c4878aSAndroid Build Coastguard Worker
SetLevel(uint8_t level)24*61c4878aSAndroid Build Coastguard Worker void AATreeItem::SetLevel(uint8_t level) {
25*61c4878aSAndroid Build Coastguard Worker parent_.set_packed_value(level & 3);
26*61c4878aSAndroid Build Coastguard Worker left_.set_packed_value((level >> 2) & 3);
27*61c4878aSAndroid Build Coastguard Worker right_.set_packed_value((level >> 4) & 3);
28*61c4878aSAndroid Build Coastguard Worker }
29*61c4878aSAndroid Build Coastguard Worker
IsMapped() const30*61c4878aSAndroid Build Coastguard Worker bool AATreeItem::IsMapped() const {
31*61c4878aSAndroid Build Coastguard Worker return GetLevel() != 0 || parent_.get() != nullptr ||
32*61c4878aSAndroid Build Coastguard Worker left_.get() != nullptr || right_.get() != nullptr;
33*61c4878aSAndroid Build Coastguard Worker }
34*61c4878aSAndroid Build Coastguard Worker
GetTreeSize()35*61c4878aSAndroid Build Coastguard Worker size_t AATreeItem::GetTreeSize() {
36*61c4878aSAndroid Build Coastguard Worker return 1 + (left_.get() == nullptr ? 0 : left_->GetTreeSize()) +
37*61c4878aSAndroid Build Coastguard Worker (right_.get() == nullptr ? 0 : right_->GetTreeSize());
38*61c4878aSAndroid Build Coastguard Worker }
39*61c4878aSAndroid Build Coastguard Worker
GetRoot()40*61c4878aSAndroid Build Coastguard Worker AATreeItem* AATreeItem::GetRoot() {
41*61c4878aSAndroid Build Coastguard Worker AATreeItem* node = this;
42*61c4878aSAndroid Build Coastguard Worker while (node->parent_.get() != nullptr) {
43*61c4878aSAndroid Build Coastguard Worker node = node->parent_.get();
44*61c4878aSAndroid Build Coastguard Worker }
45*61c4878aSAndroid Build Coastguard Worker return node;
46*61c4878aSAndroid Build Coastguard Worker }
47*61c4878aSAndroid Build Coastguard Worker
GetLeftmost()48*61c4878aSAndroid Build Coastguard Worker AATreeItem* AATreeItem::GetLeftmost() {
49*61c4878aSAndroid Build Coastguard Worker return left_.get() == nullptr ? this : left_->GetLeftmost();
50*61c4878aSAndroid Build Coastguard Worker }
51*61c4878aSAndroid Build Coastguard Worker
GetRightmost()52*61c4878aSAndroid Build Coastguard Worker AATreeItem* AATreeItem::GetRightmost() {
53*61c4878aSAndroid Build Coastguard Worker return right_.get() == nullptr ? this : right_->GetRightmost();
54*61c4878aSAndroid Build Coastguard Worker }
55*61c4878aSAndroid Build Coastguard Worker
GetPredecessor()56*61c4878aSAndroid Build Coastguard Worker AATreeItem* AATreeItem::GetPredecessor() {
57*61c4878aSAndroid Build Coastguard Worker if (left_.get() != nullptr) {
58*61c4878aSAndroid Build Coastguard Worker return left_->GetRightmost();
59*61c4878aSAndroid Build Coastguard Worker }
60*61c4878aSAndroid Build Coastguard Worker const AATreeItem* current = this;
61*61c4878aSAndroid Build Coastguard Worker AATreeItem* ancestor = parent_.get();
62*61c4878aSAndroid Build Coastguard Worker while (ancestor != nullptr && ancestor->left_.get() == current) {
63*61c4878aSAndroid Build Coastguard Worker current = ancestor;
64*61c4878aSAndroid Build Coastguard Worker ancestor = ancestor->parent_.get();
65*61c4878aSAndroid Build Coastguard Worker }
66*61c4878aSAndroid Build Coastguard Worker return ancestor;
67*61c4878aSAndroid Build Coastguard Worker }
68*61c4878aSAndroid Build Coastguard Worker
GetSuccessor()69*61c4878aSAndroid Build Coastguard Worker AATreeItem* AATreeItem::GetSuccessor() {
70*61c4878aSAndroid Build Coastguard Worker if (right_.get() != nullptr) {
71*61c4878aSAndroid Build Coastguard Worker return right_->GetLeftmost();
72*61c4878aSAndroid Build Coastguard Worker }
73*61c4878aSAndroid Build Coastguard Worker const AATreeItem* current = this;
74*61c4878aSAndroid Build Coastguard Worker AATreeItem* ancestor = parent_.get();
75*61c4878aSAndroid Build Coastguard Worker while (ancestor != nullptr && ancestor->right_.get() == current) {
76*61c4878aSAndroid Build Coastguard Worker current = ancestor;
77*61c4878aSAndroid Build Coastguard Worker ancestor = ancestor->parent_.get();
78*61c4878aSAndroid Build Coastguard Worker }
79*61c4878aSAndroid Build Coastguard Worker return ancestor;
80*61c4878aSAndroid Build Coastguard Worker }
81*61c4878aSAndroid Build Coastguard Worker
Unmap()82*61c4878aSAndroid Build Coastguard Worker AATreeItem* AATreeItem::Unmap() {
83*61c4878aSAndroid Build Coastguard Worker AATreeItem* node;
84*61c4878aSAndroid Build Coastguard Worker if (left_.get() == nullptr && right_.get() == nullptr) {
85*61c4878aSAndroid Build Coastguard Worker // Leaf node.
86*61c4878aSAndroid Build Coastguard Worker node = nullptr;
87*61c4878aSAndroid Build Coastguard Worker
88*61c4878aSAndroid Build Coastguard Worker } else if (left_.get() == nullptr) {
89*61c4878aSAndroid Build Coastguard Worker // Replace the node with the next one in value.
90*61c4878aSAndroid Build Coastguard Worker node = GetSuccessor();
91*61c4878aSAndroid Build Coastguard Worker right_->parent_.set(nullptr);
92*61c4878aSAndroid Build Coastguard Worker node->SetRight(node->Unmap());
93*61c4878aSAndroid Build Coastguard Worker
94*61c4878aSAndroid Build Coastguard Worker } else {
95*61c4878aSAndroid Build Coastguard Worker // Replace the node with the previous one in value.
96*61c4878aSAndroid Build Coastguard Worker node = GetPredecessor();
97*61c4878aSAndroid Build Coastguard Worker left_->parent_.set(nullptr);
98*61c4878aSAndroid Build Coastguard Worker node->SetLeft(node->Unmap());
99*61c4878aSAndroid Build Coastguard Worker node->SetRight(right_.get());
100*61c4878aSAndroid Build Coastguard Worker }
101*61c4878aSAndroid Build Coastguard Worker if (parent_.get() != nullptr) {
102*61c4878aSAndroid Build Coastguard Worker parent_->Replace(this, node);
103*61c4878aSAndroid Build Coastguard Worker } else if (node == nullptr) {
104*61c4878aSAndroid Build Coastguard Worker // Removing the only node from the tree.
105*61c4878aSAndroid Build Coastguard Worker Reset();
106*61c4878aSAndroid Build Coastguard Worker return nullptr;
107*61c4878aSAndroid Build Coastguard Worker }
108*61c4878aSAndroid Build Coastguard Worker node = node == nullptr ? GetRoot() : node->Rebalance();
109*61c4878aSAndroid Build Coastguard Worker Reset();
110*61c4878aSAndroid Build Coastguard Worker return node;
111*61c4878aSAndroid Build Coastguard Worker }
112*61c4878aSAndroid Build Coastguard Worker
SetLeft(AATreeItem * left)113*61c4878aSAndroid Build Coastguard Worker void AATreeItem::SetLeft(AATreeItem* left) {
114*61c4878aSAndroid Build Coastguard Worker if (left != nullptr) {
115*61c4878aSAndroid Build Coastguard Worker left->parent_.set(this);
116*61c4878aSAndroid Build Coastguard Worker }
117*61c4878aSAndroid Build Coastguard Worker left_.set(left);
118*61c4878aSAndroid Build Coastguard Worker }
119*61c4878aSAndroid Build Coastguard Worker
SetRight(AATreeItem * right)120*61c4878aSAndroid Build Coastguard Worker void AATreeItem::SetRight(AATreeItem* right) {
121*61c4878aSAndroid Build Coastguard Worker if (right != nullptr) {
122*61c4878aSAndroid Build Coastguard Worker right->parent_.set(this);
123*61c4878aSAndroid Build Coastguard Worker }
124*61c4878aSAndroid Build Coastguard Worker right_.set(right);
125*61c4878aSAndroid Build Coastguard Worker }
126*61c4878aSAndroid Build Coastguard Worker
Replace(AATreeItem * old_child,AATreeItem * new_child)127*61c4878aSAndroid Build Coastguard Worker void AATreeItem::Replace(AATreeItem* old_child, AATreeItem* new_child) {
128*61c4878aSAndroid Build Coastguard Worker if (left_.get() == old_child) {
129*61c4878aSAndroid Build Coastguard Worker SetLeft(new_child);
130*61c4878aSAndroid Build Coastguard Worker } else if (right_.get() == old_child) {
131*61c4878aSAndroid Build Coastguard Worker SetRight(new_child);
132*61c4878aSAndroid Build Coastguard Worker }
133*61c4878aSAndroid Build Coastguard Worker }
134*61c4878aSAndroid Build Coastguard Worker
Skew()135*61c4878aSAndroid Build Coastguard Worker AATreeItem* AATreeItem::Skew() {
136*61c4878aSAndroid Build Coastguard Worker if (left_.get() == nullptr || GetLevel() != left_->GetLevel()) {
137*61c4878aSAndroid Build Coastguard Worker return this;
138*61c4878aSAndroid Build Coastguard Worker }
139*61c4878aSAndroid Build Coastguard Worker AATreeItem* skewed = left_.get();
140*61c4878aSAndroid Build Coastguard Worker SetLeft(skewed->right_.get());
141*61c4878aSAndroid Build Coastguard Worker skewed->parent_.set(parent_.get());
142*61c4878aSAndroid Build Coastguard Worker skewed->SetRight(this);
143*61c4878aSAndroid Build Coastguard Worker return skewed;
144*61c4878aSAndroid Build Coastguard Worker }
145*61c4878aSAndroid Build Coastguard Worker
Split()146*61c4878aSAndroid Build Coastguard Worker AATreeItem* AATreeItem::Split() {
147*61c4878aSAndroid Build Coastguard Worker if (right_.get() == nullptr || right_->right_.get() == nullptr ||
148*61c4878aSAndroid Build Coastguard Worker GetLevel() != right_->right_->GetLevel()) {
149*61c4878aSAndroid Build Coastguard Worker return this;
150*61c4878aSAndroid Build Coastguard Worker }
151*61c4878aSAndroid Build Coastguard Worker AATreeItem* split = right_.get();
152*61c4878aSAndroid Build Coastguard Worker SetRight(split->left_.get());
153*61c4878aSAndroid Build Coastguard Worker split->parent_.set(parent_.get());
154*61c4878aSAndroid Build Coastguard Worker split->SetLeft(this);
155*61c4878aSAndroid Build Coastguard Worker split->SetLevel(split->GetLevel() + 1);
156*61c4878aSAndroid Build Coastguard Worker return split;
157*61c4878aSAndroid Build Coastguard Worker }
158*61c4878aSAndroid Build Coastguard Worker
Rebalance()159*61c4878aSAndroid Build Coastguard Worker AATreeItem* AATreeItem::Rebalance() {
160*61c4878aSAndroid Build Coastguard Worker AATreeItem* node = this;
161*61c4878aSAndroid Build Coastguard Worker while (true) {
162*61c4878aSAndroid Build Coastguard Worker uint8_t left_level =
163*61c4878aSAndroid Build Coastguard Worker node->left_.get() == nullptr ? 0 : node->left_->GetLevel();
164*61c4878aSAndroid Build Coastguard Worker uint8_t right_level =
165*61c4878aSAndroid Build Coastguard Worker node->right_.get() == nullptr ? 0 : node->right_->GetLevel();
166*61c4878aSAndroid Build Coastguard Worker uint8_t new_level = std::min(left_level, right_level) + 1;
167*61c4878aSAndroid Build Coastguard Worker if (new_level < node->GetLevel()) {
168*61c4878aSAndroid Build Coastguard Worker node->SetLevel(new_level);
169*61c4878aSAndroid Build Coastguard Worker if (new_level < right_level) {
170*61c4878aSAndroid Build Coastguard Worker node->right_->SetLevel(new_level);
171*61c4878aSAndroid Build Coastguard Worker }
172*61c4878aSAndroid Build Coastguard Worker }
173*61c4878aSAndroid Build Coastguard Worker AATreeItem* parent = node->parent_.get();
174*61c4878aSAndroid Build Coastguard Worker AATreeItem* orig = node;
175*61c4878aSAndroid Build Coastguard Worker node = node->Skew();
176*61c4878aSAndroid Build Coastguard Worker if (node->right_.get() != nullptr) {
177*61c4878aSAndroid Build Coastguard Worker node->SetRight(node->right_->Skew());
178*61c4878aSAndroid Build Coastguard Worker if (node->right_->right_.get() != nullptr) {
179*61c4878aSAndroid Build Coastguard Worker node->right_->SetRight(node->right_->right_->Skew());
180*61c4878aSAndroid Build Coastguard Worker }
181*61c4878aSAndroid Build Coastguard Worker }
182*61c4878aSAndroid Build Coastguard Worker node = node->Split();
183*61c4878aSAndroid Build Coastguard Worker if (node->right_.get() != nullptr) {
184*61c4878aSAndroid Build Coastguard Worker node->SetRight(node->right_->Split());
185*61c4878aSAndroid Build Coastguard Worker }
186*61c4878aSAndroid Build Coastguard Worker if (parent == nullptr) {
187*61c4878aSAndroid Build Coastguard Worker return node;
188*61c4878aSAndroid Build Coastguard Worker }
189*61c4878aSAndroid Build Coastguard Worker parent->Replace(orig, node);
190*61c4878aSAndroid Build Coastguard Worker node = parent;
191*61c4878aSAndroid Build Coastguard Worker }
192*61c4878aSAndroid Build Coastguard Worker }
193*61c4878aSAndroid Build Coastguard Worker
Clear()194*61c4878aSAndroid Build Coastguard Worker void AATreeItem::Clear() {
195*61c4878aSAndroid Build Coastguard Worker if (parent_.get() != nullptr) {
196*61c4878aSAndroid Build Coastguard Worker parent_->Replace(this, nullptr);
197*61c4878aSAndroid Build Coastguard Worker }
198*61c4878aSAndroid Build Coastguard Worker if (left_.get() != nullptr) {
199*61c4878aSAndroid Build Coastguard Worker left_->Clear();
200*61c4878aSAndroid Build Coastguard Worker }
201*61c4878aSAndroid Build Coastguard Worker if (right_.get() != nullptr) {
202*61c4878aSAndroid Build Coastguard Worker right_->Clear();
203*61c4878aSAndroid Build Coastguard Worker }
204*61c4878aSAndroid Build Coastguard Worker Reset();
205*61c4878aSAndroid Build Coastguard Worker }
206*61c4878aSAndroid Build Coastguard Worker
Reset()207*61c4878aSAndroid Build Coastguard Worker void AATreeItem::Reset() {
208*61c4878aSAndroid Build Coastguard Worker parent_ = PackedPtr<AATreeItem>();
209*61c4878aSAndroid Build Coastguard Worker left_ = PackedPtr<AATreeItem>();
210*61c4878aSAndroid Build Coastguard Worker right_ = PackedPtr<AATreeItem>();
211*61c4878aSAndroid Build Coastguard Worker }
212*61c4878aSAndroid Build Coastguard Worker
213*61c4878aSAndroid Build Coastguard Worker } // namespace pw::containers::internal
214