xref: /aosp_15_r20/external/pigweed/pw_containers/aa_tree_item.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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