#include "a/rbt.h"
static A_INLINE void a_rbt_new_child(a_rbt *root, a_rbt_node *parent, a_rbt_node *node, a_rbt_node *newnode)
{
if (parent)
{
if (parent->left == node)
{
parent->left = newnode;
}
else
{
parent->right = newnode;
}
}
else
{
root->node = newnode;
}
}
static A_INLINE void a_rbt_set_parent_color(a_rbt_node *node, a_rbt_node *parent, unsigned int color)
{
#if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 1)
node->parent_ = (a_uptr)parent + color;
#else
node->parent = parent;
node->color = color;
#endif
}
static A_INLINE void a_rbt_set_parent(a_rbt_node *node, a_rbt_node *parent)
{
#if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 1)
node->parent_ = (a_uptr)parent + (node->parent_ & 1);
#else
node->parent = parent;
#endif
}
static A_INLINE unsigned int a_rbt_color(a_rbt_node const *node)
{
#if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 1)
return (unsigned int)(node->parent_ & 1);
#else
return node->color;
#endif
}
static A_INLINE void a_rbt_set_black(a_rbt_node *node)
{
#if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 1)
node->parent_ |= 1;
#else
node->color = 1;
#endif
}
static A_INLINE void a_rbt_set_parents(a_rbt *root, a_rbt_node *node, a_rbt_node *newnode, unsigned int color)
{
a_rbt_node *const parent = a_rbt_parent(node);
#if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 1)
newnode->parent_ = node->parent_;
#else
newnode->parent = node->parent;
newnode->color = node->color;
#endif
a_rbt_set_parent_color(node, newnode, color);
a_rbt_new_child(root, parent, node, newnode);
}
#if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 1)
#define A_RBT_PARENT(node) a_cast_r(a_rbt_node *, (node)->parent_)
#else
#define A_RBT_PARENT(node) (node)->parent
#endif
void a_rbt_insert_adjust(a_rbt *root, a_rbt_node *node)
{
for (a_rbt_node *parent = A_RBT_PARENT(node), *gparent, *tmp;;)
{
if (A_UNLIKELY(!parent))
{
a_rbt_set_parent_color(node, A_NULL, 1);
break;
}
if (a_rbt_color(parent)) { break; }
gparent = A_RBT_PARENT(parent);
tmp = gparent->right;
if (parent != tmp)
{
if (tmp && a_rbt_color(tmp) == 0)
{
a_rbt_set_parent_color(tmp, gparent, 1);
a_rbt_set_parent_color(parent, gparent, 1);
node = gparent;
parent = a_rbt_parent(node);
a_rbt_set_parent_color(node, parent, 0);
continue;
}
tmp = parent->right;
if (node == tmp)
{
tmp = node->left;
parent->right = tmp;
node->left = parent;
if (tmp) { a_rbt_set_parent_color(tmp, parent, 1); }
a_rbt_set_parent_color(parent, node, 0);
parent = node;
tmp = node->right;
}
gparent->left = tmp;
parent->right = gparent;
if (tmp) { a_rbt_set_parent_color(tmp, gparent, 1); }
a_rbt_set_parents(root, gparent, parent, 0);
break;
}
else
{
tmp = gparent->left;
if (tmp && a_rbt_color(tmp) == 0)
{
a_rbt_set_parent_color(tmp, gparent, 1);
a_rbt_set_parent_color(parent, gparent, 1);
node = gparent;
parent = a_rbt_parent(node);
a_rbt_set_parent_color(node, parent, 0);
continue;
}
tmp = parent->left;
if (node == tmp)
{
tmp = node->right;
parent->left = tmp;
node->right = parent;
if (tmp) { a_rbt_set_parent_color(tmp, parent, 1); }
a_rbt_set_parent_color(parent, node, 0);
parent = node;
tmp = node->left;
}
gparent->right = tmp;
parent->left = gparent;
if (tmp) { a_rbt_set_parent_color(tmp, gparent, 1); }
a_rbt_set_parents(root, gparent, parent, 0);
break;
}
}
}
static A_INLINE void a_rbt_remove_adjust(a_rbt *root, a_rbt_node *parent)
{
for (a_rbt_node *node = A_NULL, *sibling, *tmp1, *tmp2;;)
{
if (node != parent->right)
{
sibling = parent->right;
if (a_rbt_color(sibling) == 0)
{
tmp1 = sibling->left;
parent->right = tmp1;
sibling->left = parent;
a_rbt_set_parent_color(tmp1, parent, 1);
a_rbt_set_parents(root, parent, sibling, 0);
sibling = tmp1;
A_ASSUME(tmp1);
}
tmp1 = sibling->right;
if (!tmp1 || a_rbt_color(tmp1))
{
tmp2 = sibling->left;
if (!tmp2 || a_rbt_color(tmp2))
{
a_rbt_set_parent_color(sibling, parent, 0);
if (a_rbt_color(parent) == 0)
{
a_rbt_set_black(parent);
}
else
{
node = parent;
parent = a_rbt_parent(node);
if (parent) { continue; }
}
break;
}
tmp1 = tmp2->right;
sibling->left = tmp1;
tmp2->right = sibling;
parent->right = tmp2;
if (tmp1) { a_rbt_set_parent_color(tmp1, sibling, 1); }
tmp1 = sibling;
sibling = tmp2;
}
tmp2 = sibling->left;
parent->right = tmp2;
sibling->left = parent;
a_rbt_set_parent_color(tmp1, sibling, 1);
if (tmp2) { a_rbt_set_parent(tmp2, parent); }
a_rbt_set_parents(root, parent, sibling, 1);
break;
}
else
{
A_ASSUME(parent->left);
sibling = parent->left;
if (a_rbt_color(sibling) == 0)
{
tmp1 = sibling->right;
parent->left = tmp1;
sibling->right = parent;
a_rbt_set_parent_color(tmp1, parent, 1);
a_rbt_set_parents(root, parent, sibling, 0);
sibling = tmp1;
A_ASSUME(tmp1);
}
tmp1 = sibling->left;
if (!tmp1 || a_rbt_color(tmp1))
{
tmp2 = sibling->right;
if (!tmp2 || a_rbt_color(tmp2))
{
a_rbt_set_parent_color(sibling, parent, 0);
if (a_rbt_color(parent) == 0)
{
a_rbt_set_black(parent);
}
else
{
node = parent;
parent = a_rbt_parent(node);
if (parent) { continue; }
}
break;
}
tmp1 = tmp2->left;
sibling->right = tmp1;
tmp2->left = sibling;
parent->left = tmp2;
if (tmp1) { a_rbt_set_parent_color(tmp1, sibling, 1); }
tmp1 = sibling;
sibling = tmp2;
}
tmp2 = sibling->right;
parent->left = tmp2;
sibling->right = parent;
a_rbt_set_parent_color(tmp1, sibling, 1);
if (tmp2) { a_rbt_set_parent(tmp2, parent); }
a_rbt_set_parents(root, parent, sibling, 1);
break;
}
}
}
void a_rbt_remove(a_rbt *root, a_rbt_node *node)
{
a_rbt_node *child = node->right;
a_rbt_node *tmp = node->left;
a_rbt_node *parent, *adjust;
#if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 1)
a_uptr parent_;
#else
unsigned int color;
#endif
if (!tmp)
{
#if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 1)
parent_ = node->parent_;
#else
color = node->color;
#endif
parent = a_rbt_parent(node);
a_rbt_new_child(root, parent, node, child);
if (child)
{
#if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 1)
child->parent_ = parent_;
#else
child->parent = parent;
child->color = color;
#endif
adjust = A_NULL;
}
else
{
#if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 1)
adjust = (parent_ & 1) ? parent : A_NULL;
#else
adjust = color ? parent : A_NULL;
#endif
}
}
else if (!child)
{
#if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 1)
tmp->parent_ = node->parent_;
#else
tmp->parent = node->parent;
tmp->color = node->color;
#endif
parent = a_rbt_parent(node);
a_rbt_new_child(root, parent, node, tmp);
adjust = A_NULL;
}
else
{
a_rbt_node *successor = child, *child2;
tmp = child->left;
if (!tmp)
{
parent = successor;
child2 = successor->right;
}
else
{
do {
parent = successor;
successor = tmp;
tmp = tmp->left;
} while (tmp);
child2 = successor->right;
parent->left = child2;
successor->right = child;
a_rbt_set_parent(child, successor);
}
tmp = node->left;
successor->left = tmp;
a_rbt_set_parent(tmp, successor);
#if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 1)
parent_ = node->parent_;
#else
color = node->color;
#endif
tmp = a_rbt_parent(node);
a_rbt_new_child(root, tmp, node, successor);
if (child2)
{
a_rbt_set_parent_color(child2, parent, 1);
adjust = A_NULL;
}
else
{
adjust = a_rbt_color(successor) ? parent : A_NULL;
}
#if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 1)
successor->parent_ = parent_;
#else
successor->parent = tmp;
successor->color = color;
#endif
}
if (adjust) { a_rbt_remove_adjust(root, adjust); }
}
a_rbt_node *a_rbt_insert(a_rbt *root, a_rbt_node *node, int (*cmp)(void const *, void const *))
{
a_rbt_node *parent = root->node;
a_rbt_node **link = &root->node;
while (*link)
{
parent = *link;
int const res = cmp(node, parent);
if (res < 0)
{
link = &parent->left;
}
else if (res > 0)
{
link = &parent->right;
}
else { return parent; }
}
*link = a_rbt_init(node, parent);
a_rbt_insert_adjust(root, node);
return A_NULL;
}
a_rbt_node *a_rbt_search(a_rbt const *root, void const *ctx, int (*cmp)(void const *, void const *))
{
for (a_rbt_node *cur = root->node; cur;)
{
int const res = cmp(ctx, cur);
if (res < 0)
{
cur = cur->left;
}
else if (res > 0)
{
cur = cur->right;
}
else { return cur; }
}
return A_NULL;
}
a_rbt_node *a_rbt_head(a_rbt const *root)
{
a_rbt_node *node = root->node;
if (node)
{
while (node->left) { node = node->left; }
}
return node;
}
a_rbt_node *a_rbt_tail(a_rbt const *root)
{
a_rbt_node *node = root->node;
if (node)
{
while (node->right) { node = node->right; }
}
return node;
}
a_rbt_node *a_rbt_next(a_rbt_node *node)
{
if (node->right)
{
node = node->right;
while (node->left) { node = node->left; }
}
else
{
a_rbt_node *leaf;
do {
leaf = node;
node = a_rbt_parent(node);
} while (node && node->left != leaf);
}
return node;
}
a_rbt_node *a_rbt_prev(a_rbt_node *node)
{
if (node->left)
{
node = node->left;
while (node->right) { node = node->right; }
}
else
{
a_rbt_node *leaf;
do {
leaf = node;
node = a_rbt_parent(node);
} while (node && node->right != leaf);
}
return node;
}
a_rbt_node *a_rbt_pre_next(a_rbt_node *node)
{
a_rbt_node *leaf;
if (node->left) { return node->left; }
if (node->right) { return node->right; }
for (leaf = node, node = a_rbt_parent(node); node;
leaf = node, node = a_rbt_parent(node))
{
if (node->right && node->right != leaf)
{
node = node->right;
break;
}
}
return node;
}
a_rbt_node *a_rbt_pre_prev(a_rbt_node *node)
{
a_rbt_node *leaf;
if (node->right) { return node->right; }
if (node->left) { return node->left; }
for (leaf = node, node = a_rbt_parent(node); node;
leaf = node, node = a_rbt_parent(node))
{
if (node->left && node->left != leaf)
{
node = node->left;
break;
}
}
return node;
}
#define A_RBT_POST(head, tail) \
for (;;) \
{ \
if (node->head) \
{ \
node = node->head; \
} \
else if (node->tail) \
{ \
node = node->tail; \
} \
else { break; } \
} \
(void)0
a_rbt_node *a_rbt_post_head(a_rbt const *root)
{
a_rbt_node *node = root->node;
if (node) { A_RBT_POST(left, right); }
return node;
}
a_rbt_node *a_rbt_post_tail(a_rbt const *root)
{
a_rbt_node *node = root->node;
if (node) { A_RBT_POST(right, left); }
return node;
}
a_rbt_node *a_rbt_post_next(a_rbt_node *node)
{
a_rbt_node *leaf = node;
node = a_rbt_parent(node);
if (node && node->right && node->right != leaf)
{
node = node->right;
A_RBT_POST(left, right);
}
return node;
}
a_rbt_node *a_rbt_post_prev(a_rbt_node *node)
{
a_rbt_node *leaf = node;
node = a_rbt_parent(node);
if (node && node->left && node->left != leaf)
{
node = node->left;
A_RBT_POST(right, left);
}
return node;
}
a_rbt_node *a_rbt_tear(a_rbt *root, a_rbt_node **next)
{
a_rbt_node *node = *next;
if (!node)
{
node = root->node;
if (!node) { return node; }
}
A_RBT_POST(left, right);
*next = a_rbt_parent(node);
a_rbt_new_child(root, *next, node, A_NULL);
return node;
}