2014-11-20 22:28:13 +01:00
|
|
|
#include <3ds/util/rbtree.h>
|
|
|
|
#include "rbtree_internal.h"
|
|
|
|
|
|
|
|
static void
|
|
|
|
recolor(rbtree_t *tree,
|
|
|
|
rbtree_node_t *parent,
|
|
|
|
rbtree_node_t *node)
|
|
|
|
{
|
|
|
|
rbtree_node_t *sibling;
|
|
|
|
|
|
|
|
while(is_black(node) && node != tree->root)
|
|
|
|
{
|
|
|
|
int left = (node == parent->child[LEFT]);
|
|
|
|
|
|
|
|
sibling = parent->child[left];
|
|
|
|
|
|
|
|
if(is_red(sibling))
|
|
|
|
{
|
|
|
|
set_black(sibling);
|
|
|
|
set_red(parent);
|
|
|
|
rbtree_rotate(tree, parent, left);
|
|
|
|
sibling = parent->child[left];
|
|
|
|
}
|
|
|
|
|
|
|
|
if(is_black(sibling->child[LEFT]) && is_black(sibling->child[RIGHT]))
|
|
|
|
{
|
|
|
|
set_red(sibling);
|
|
|
|
node = parent;
|
|
|
|
parent = get_parent(node);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(is_black(sibling->child[left]))
|
|
|
|
{
|
|
|
|
set_black(sibling->child[!left]);
|
|
|
|
set_red(sibling);
|
|
|
|
rbtree_rotate(tree, sibling, !left);
|
|
|
|
sibling = parent->child[left];
|
|
|
|
}
|
|
|
|
|
|
|
|
if(is_black(parent))
|
|
|
|
set_black(sibling);
|
|
|
|
else
|
|
|
|
set_red(sibling);
|
|
|
|
set_black(parent);
|
|
|
|
set_black(sibling->child[left]);
|
|
|
|
|
|
|
|
rbtree_rotate(tree, parent, left);
|
|
|
|
|
|
|
|
node = tree->root;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-20 06:36:21 +02:00
|
|
|
if(node)
|
2014-11-20 22:28:13 +01:00
|
|
|
set_black(node);
|
|
|
|
}
|
|
|
|
|
2018-09-20 06:36:21 +02:00
|
|
|
static bool
|
|
|
|
in_tree(const rbtree_t *tree,
|
|
|
|
const rbtree_node_t *node)
|
|
|
|
{
|
|
|
|
if(tree->root == node)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
const rbtree_node_t *parent = get_parent(node);
|
|
|
|
while(parent)
|
|
|
|
{
|
|
|
|
if(tree->root == parent)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
parent = get_parent(parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-11-20 22:28:13 +01:00
|
|
|
rbtree_node_t*
|
|
|
|
rbtree_remove(rbtree_t *tree,
|
|
|
|
rbtree_node_t *node,
|
|
|
|
rbtree_node_destructor_t destructor)
|
|
|
|
{
|
2018-09-20 06:36:21 +02:00
|
|
|
rbtree_set_busy(tree);
|
|
|
|
if(!in_tree(tree, node))
|
|
|
|
svcBreak(USERBREAK_PANIC);
|
2018-09-19 06:43:59 +02:00
|
|
|
rbtree_validate(tree);
|
|
|
|
|
2014-11-20 22:28:13 +01:00
|
|
|
rbtree_color_t color;
|
|
|
|
rbtree_node_t *child, *parent, *original = node;
|
|
|
|
rbtree_node_t *next;
|
|
|
|
|
|
|
|
next = rbtree_node_next(node);
|
|
|
|
|
2018-09-20 06:36:21 +02:00
|
|
|
if(node->child[LEFT] && node->child[RIGHT])
|
2014-11-20 22:28:13 +01:00
|
|
|
{
|
|
|
|
rbtree_node_t *old = node;
|
|
|
|
|
|
|
|
node = node->child[RIGHT];
|
2018-09-20 06:36:21 +02:00
|
|
|
while(node->child[LEFT])
|
2014-11-20 22:28:13 +01:00
|
|
|
node = node->child[LEFT];
|
|
|
|
|
|
|
|
parent = get_parent(old);
|
2018-09-20 06:36:21 +02:00
|
|
|
if(parent)
|
2014-11-20 22:28:13 +01:00
|
|
|
{
|
|
|
|
if(parent->child[LEFT] == old)
|
|
|
|
parent->child[LEFT] = node;
|
|
|
|
else
|
|
|
|
parent->child[RIGHT] = node;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
tree->root = node;
|
|
|
|
|
|
|
|
child = node->child[RIGHT];
|
|
|
|
parent = get_parent(node);
|
|
|
|
color = get_color(node);
|
|
|
|
|
|
|
|
if(parent == old)
|
|
|
|
parent = node;
|
|
|
|
else
|
|
|
|
{
|
2018-09-20 06:36:21 +02:00
|
|
|
if(child)
|
2014-11-20 22:28:13 +01:00
|
|
|
set_parent(child, parent);
|
|
|
|
parent->child[LEFT] = child;
|
|
|
|
|
|
|
|
node->child[RIGHT] = old->child[RIGHT];
|
|
|
|
set_parent(old->child[RIGHT], node);
|
|
|
|
}
|
|
|
|
|
|
|
|
node->parent_color = old->parent_color;
|
|
|
|
node->child[LEFT] = old->child[LEFT];
|
|
|
|
set_parent(old->child[LEFT], node);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-09-20 06:36:21 +02:00
|
|
|
if(!node->child[LEFT])
|
2014-11-20 22:28:13 +01:00
|
|
|
child = node->child[RIGHT];
|
|
|
|
else
|
|
|
|
child = node->child[LEFT];
|
|
|
|
|
|
|
|
parent = get_parent(node);
|
|
|
|
color = get_color(node);
|
|
|
|
|
2018-09-20 06:36:21 +02:00
|
|
|
if(child)
|
2014-11-20 22:28:13 +01:00
|
|
|
set_parent(child, parent);
|
2018-09-20 06:36:21 +02:00
|
|
|
if(parent)
|
2014-11-20 22:28:13 +01:00
|
|
|
{
|
|
|
|
if(parent->child[LEFT] == node)
|
|
|
|
parent->child[LEFT] = child;
|
|
|
|
else
|
|
|
|
parent->child[RIGHT] = child;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
tree->root = child;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(color == BLACK)
|
|
|
|
recolor(tree, parent, child);
|
|
|
|
|
2018-09-20 06:36:21 +02:00
|
|
|
original->nodeTag[3] = 'D';
|
|
|
|
original->nodeTag[2] = 'O';
|
|
|
|
original->nodeTag[1] = 'N';
|
|
|
|
original->nodeTag[0] = 'E';
|
|
|
|
original->parent_color = 0;
|
|
|
|
original->child[LEFT] = NULL;
|
|
|
|
original->child[RIGHT] = NULL;
|
|
|
|
original->tree = NULL;
|
|
|
|
|
|
|
|
if(destructor)
|
2014-11-20 22:28:13 +01:00
|
|
|
(*destructor)(original);
|
|
|
|
|
|
|
|
tree->size -= 1;
|
|
|
|
|
2018-09-19 06:43:59 +02:00
|
|
|
rbtree_validate(tree);
|
2018-09-20 06:36:21 +02:00
|
|
|
rbtree_clear_busy(tree);
|
2018-09-19 06:43:59 +02:00
|
|
|
|
2014-11-20 22:28:13 +01:00
|
|
|
return next;
|
|
|
|
}
|