// Copyright 2024 The Pigweed Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #include "pw_containers/internal/aa_tree_item.h" namespace pw::containers::internal { uint8_t AATreeItem::GetLevel() const { return parent_.packed_value() | (left_.packed_value() << 2) | (right_.packed_value() << 4); } void AATreeItem::SetLevel(uint8_t level) { parent_.set_packed_value(level & 3); left_.set_packed_value((level >> 2) & 3); right_.set_packed_value((level >> 4) & 3); } bool AATreeItem::IsMapped() const { return GetLevel() != 0 || parent_.get() != nullptr || left_.get() != nullptr || right_.get() != nullptr; } size_t AATreeItem::GetTreeSize() { return 1 + (left_.get() == nullptr ? 0 : left_->GetTreeSize()) + (right_.get() == nullptr ? 0 : right_->GetTreeSize()); } AATreeItem* AATreeItem::GetRoot() { AATreeItem* node = this; while (node->parent_.get() != nullptr) { node = node->parent_.get(); } return node; } AATreeItem* AATreeItem::GetLeftmost() { return left_.get() == nullptr ? this : left_->GetLeftmost(); } AATreeItem* AATreeItem::GetRightmost() { return right_.get() == nullptr ? this : right_->GetRightmost(); } AATreeItem* AATreeItem::GetPredecessor() { if (left_.get() != nullptr) { return left_->GetRightmost(); } const AATreeItem* current = this; AATreeItem* ancestor = parent_.get(); while (ancestor != nullptr && ancestor->left_.get() == current) { current = ancestor; ancestor = ancestor->parent_.get(); } return ancestor; } AATreeItem* AATreeItem::GetSuccessor() { if (right_.get() != nullptr) { return right_->GetLeftmost(); } const AATreeItem* current = this; AATreeItem* ancestor = parent_.get(); while (ancestor != nullptr && ancestor->right_.get() == current) { current = ancestor; ancestor = ancestor->parent_.get(); } return ancestor; } AATreeItem* AATreeItem::Unmap() { AATreeItem* node; if (left_.get() == nullptr && right_.get() == nullptr) { // Leaf node. node = nullptr; } else if (left_.get() == nullptr) { // Replace the node with the next one in value. node = GetSuccessor(); right_->parent_.set(nullptr); node->SetRight(node->Unmap()); } else { // Replace the node with the previous one in value. node = GetPredecessor(); left_->parent_.set(nullptr); node->SetLeft(node->Unmap()); node->SetRight(right_.get()); } if (parent_.get() != nullptr) { parent_->Replace(this, node); } else if (node == nullptr) { // Removing the only node from the tree. Reset(); return nullptr; } node = node == nullptr ? GetRoot() : node->Rebalance(); Reset(); return node; } void AATreeItem::SetLeft(AATreeItem* left) { if (left != nullptr) { left->parent_.set(this); } left_.set(left); } void AATreeItem::SetRight(AATreeItem* right) { if (right != nullptr) { right->parent_.set(this); } right_.set(right); } void AATreeItem::Replace(AATreeItem* old_child, AATreeItem* new_child) { if (left_.get() == old_child) { SetLeft(new_child); } else if (right_.get() == old_child) { SetRight(new_child); } } AATreeItem* AATreeItem::Skew() { if (left_.get() == nullptr || GetLevel() != left_->GetLevel()) { return this; } AATreeItem* skewed = left_.get(); SetLeft(skewed->right_.get()); skewed->parent_.set(parent_.get()); skewed->SetRight(this); return skewed; } AATreeItem* AATreeItem::Split() { if (right_.get() == nullptr || right_->right_.get() == nullptr || GetLevel() != right_->right_->GetLevel()) { return this; } AATreeItem* split = right_.get(); SetRight(split->left_.get()); split->parent_.set(parent_.get()); split->SetLeft(this); split->SetLevel(split->GetLevel() + 1); return split; } AATreeItem* AATreeItem::Rebalance() { AATreeItem* node = this; while (true) { uint8_t left_level = node->left_.get() == nullptr ? 0 : node->left_->GetLevel(); uint8_t right_level = node->right_.get() == nullptr ? 0 : node->right_->GetLevel(); uint8_t new_level = std::min(left_level, right_level) + 1; if (new_level < node->GetLevel()) { node->SetLevel(new_level); if (new_level < right_level) { node->right_->SetLevel(new_level); } } AATreeItem* parent = node->parent_.get(); AATreeItem* orig = node; node = node->Skew(); if (node->right_.get() != nullptr) { node->SetRight(node->right_->Skew()); if (node->right_->right_.get() != nullptr) { node->right_->SetRight(node->right_->right_->Skew()); } } node = node->Split(); if (node->right_.get() != nullptr) { node->SetRight(node->right_->Split()); } if (parent == nullptr) { return node; } parent->Replace(orig, node); node = parent; } } void AATreeItem::Clear() { if (parent_.get() != nullptr) { parent_->Replace(this, nullptr); } if (left_.get() != nullptr) { left_->Clear(); } if (right_.get() != nullptr) { right_->Clear(); } Reset(); } void AATreeItem::Reset() { parent_ = PackedPtr(); left_ = PackedPtr(); right_ = PackedPtr(); } } // namespace pw::containers::internal