blob: dfca3eeb90363bb08dcfb43602b7fca6770ebec8 [file] [log] [blame] [edit]
/*
* Copyright (C) 2025 The Android Open Source Project
*
* 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
*
* http://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.
*/
/* Part of this work is inspired by the original OpenBSD's tree.h */
/* $OpenBSD: tree.h,v 1.31 2023/03/08 04:43:09 guenther Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "src/base/intrusive_tree.h"
namespace perfetto::base::internal {
namespace {
void RBSetBlackRed(RBNode* black, RBNode* red) {
black->color = RBColor::BLACK;
red->color = RBColor::RED;
}
void RBRotateLeft(RBNode** root, RBNode* elm, RBNode* tmp) {
tmp = elm->right;
if ((elm->right = tmp->left)) {
tmp->left->parent = elm;
}
// RB_AUGMENT(elm);
if ((tmp->parent = elm->parent)) {
if (elm == elm->parent->left)
elm->parent->left = tmp;
else
elm->parent->right = tmp;
} else
*root = tmp;
tmp->left = elm;
elm->parent = tmp;
// RB_AUGMENT(tmp);
// if ((tmp->parent))
// RB_AUGMENT(tmp->parent);
}
void RBRotateRight(RBNode** root, RBNode* elm, RBNode* tmp) {
tmp = elm->left;
if ((elm->left = tmp->right)) {
tmp->right->parent = elm;
}
// RB_AUGMENT(elm);
if ((tmp->parent = elm->parent)) {
if (elm == elm->parent->left)
elm->parent->left = tmp;
else
elm->parent->right = tmp;
} else
*root = tmp;
tmp->right = elm;
elm->parent = tmp;
// RB_AUGMENT(tmp);
// if ((tmp->parent))
// RB_AUGMENT(tmp->parent);
}
void RBRemoveColor(RBNode** root, RBNode* parent, RBNode* elm) {
RBNode* tmp;
while ((elm == nullptr || elm->color == RBColor::BLACK) && elm != *root) {
if (parent->left == elm) {
tmp = parent->right;
if (tmp->color == RBColor::RED) {
RBSetBlackRed(tmp, parent);
RBRotateLeft(root, parent, tmp);
tmp = parent->right;
}
if ((tmp->left == nullptr || tmp->left->color == RBColor::BLACK) &&
(tmp->right == nullptr || tmp->right->color == RBColor::BLACK)) {
tmp->color = RBColor::RED;
elm = parent;
parent = elm->parent;
} else {
if (tmp->right == nullptr || tmp->right->color == RBColor::BLACK) {
RBNode* oleft;
if ((oleft = tmp->left))
oleft->color = RBColor::BLACK;
tmp->color = RBColor::RED;
RBRotateRight(root, tmp, oleft);
tmp = parent->right;
}
tmp->color = parent->color;
parent->color = RBColor::BLACK;
if (tmp->right)
tmp->right->color = RBColor::BLACK;
RBRotateLeft(root, parent, tmp);
elm = *root;
break;
}
} else {
tmp = parent->left;
if (tmp->color == RBColor::RED) {
RBSetBlackRed(tmp, parent);
RBRotateRight(root, parent, tmp);
tmp = parent->left;
}
if ((tmp->left == nullptr || tmp->left->color == RBColor::BLACK) &&
(tmp->right == nullptr || tmp->right->color == RBColor::BLACK)) {
tmp->color = RBColor::RED;
elm = parent;
parent = elm->parent;
} else {
if (tmp->left == nullptr || tmp->left->color == RBColor::BLACK) {
RBNode* oright;
if ((oright = tmp->right))
oright->color = RBColor::BLACK;
tmp->color = RBColor::RED;
RBRotateLeft(root, tmp, oright);
tmp = parent->left;
}
tmp->color = parent->color;
parent->color = RBColor::BLACK;
if (tmp->left)
tmp->left->color = RBColor::BLACK;
RBRotateRight(root, parent, tmp);
elm = *root;
break;
}
}
}
if (elm)
elm->color = RBColor::BLACK;
}
} // namespace
void RBInsertColor(RBNode** root, RBNode* elm) {
RBNode *parent, *gparent, *tmp;
while ((parent = elm->parent) && parent->color == RBColor::RED) {
gparent = parent->parent;
if (parent == gparent->left) {
tmp = gparent->right;
if (tmp && tmp->color == RBColor::RED) {
tmp->color = RBColor::BLACK;
RBSetBlackRed(parent, gparent);
elm = gparent;
continue;
}
if (parent->right == elm) {
RBRotateLeft(root, parent, tmp);
tmp = parent;
parent = elm;
elm = tmp;
}
RBSetBlackRed(parent, gparent);
RBRotateRight(root, gparent, tmp);
} else {
tmp = gparent->left;
if (tmp && tmp->color == RBColor::RED) {
tmp->color = RBColor::BLACK;
RBSetBlackRed(parent, gparent);
elm = gparent;
continue;
}
if (parent->left == elm) {
RBRotateRight(root, parent, tmp);
tmp = parent;
parent = elm;
elm = tmp;
}
RBSetBlackRed(parent, gparent);
RBRotateLeft(root, gparent, tmp);
}
}
(*root)->color = RBColor::BLACK;
}
void RBRemove(RBNode** root, RBNode* elm) {
RBNode* child = elm;
RBNode* parent = elm;
RBNode* old = elm;
RBColor color;
if (elm->left == nullptr)
child = elm->right;
else if (elm->right == nullptr)
child = elm->left;
else {
RBNode* left;
elm = elm->right;
while ((left = elm->left))
elm = left;
child = elm->right;
parent = elm->parent;
color = elm->color;
if (child)
child->parent = parent;
if (parent) {
if (parent->left == elm) {
parent->left = child;
} else {
parent->right = child;
}
// RB_AUGMENT(parent);
} else {
*root = child;
}
if (elm->parent == old)
parent = elm;
*elm = *old;
if (old->parent) {
if (old->parent->left == old) {
old->parent->left = elm;
} else {
old->parent->right = elm;
}
// RB_AUGMENT(old->parent);
} else {
*root = elm;
}
old->left->parent = elm;
if (old->right)
old->right->parent = elm;
if (parent) {
left = parent;
// do {
// RB_AUGMENT(left);
// } while ((left = left->parent));
}
goto color;
}
parent = elm->parent;
color = elm->color;
if (child)
child->parent = parent;
if (parent) {
if (parent->left == elm)
parent->left = child;
else
parent->right = child;
// RB_AUGMENT(parent);
} else {
*root = child;
}
color:
if (color == RBColor::BLACK)
RBRemoveColor(root, parent, child);
}
// Returns nullptr after reaching the last leaf (the max element).
const RBNode* RBNext(const RBNode* node) {
if (node->right) {
node = node->right;
while (node->left)
node = node->left;
} else {
if (node->parent && node == node->parent->left) {
node = node->parent;
} else {
while (node->parent && node == node->parent->right) {
node = node->parent;
}
node = node->parent;
}
}
return node;
}
} // namespace perfetto::base::internal