blob: adb484acfc998aae95f6f8c240cebcf703492f46 [file] [log] [blame]
// 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<AATreeItem>();
left_ = PackedPtr<AATreeItem>();
right_ = PackedPtr<AATreeItem>();
}
} // namespace pw::containers::internal