#include "a/avl.h"
static A_INLINE void a_avl_new_child(a_avl *root, a_avl_node *parent, a_avl_node *node, a_avl_node *newnode)
{
if (parent)
{
if (parent->left == node)
{
parent->left = newnode;
}
else
{
parent->right = newnode;
}
}
else
{
root->node = newnode;
}
}
static A_INLINE a_avl_node *a_avl_child(a_avl_node const *node, int sign)
{
return sign < 0 ? node->left : node->right;
}
static A_INLINE void a_avl_set_child(a_avl_node *node, a_avl_node *child, int sign)
{
*(sign < 0 ? &node->left : &node->right) = child;
}
static A_INLINE void a_avl_set_parent_factor(a_avl_node *node, a_avl_node *parent, int factor)
{
#if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 3)
node->parent_ = (a_uptr)parent | (a_uptr)(factor + 1);
#else
node->parent = parent;
node->factor = factor;
#endif
}
static A_INLINE void a_avl_set_parent(a_avl_node *node, a_avl_node *parent)
{
#if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 3)
node->parent_ = (a_uptr)parent | (node->parent_ & 3);
#else
node->parent = parent;
#endif
}
static A_INLINE int a_avl_factor(a_avl_node const *node)
{
#if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 3)
return (int)(node->parent_ & 3) - 1;
#else
return node->factor;
#endif
}
static A_INLINE void a_avl_set_factor(a_avl_node *node, int amount)
{
#if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 3)
node->parent_ += (a_uptr)amount;
#else
node->factor += amount;
#endif
}
static A_INLINE void a_avl_rotate(a_avl *root, a_avl_node *A, int sign)
{
a_avl_node *const P = a_avl_parent(A);
a_avl_node *const B = a_avl_child(A, -sign);
a_avl_node *const E = a_avl_child(B, +sign);
a_avl_set_child(A, E, -sign);
a_avl_set_parent(A, B);
a_avl_set_child(B, A, +sign);
a_avl_set_parent(B, P);
if (E) { a_avl_set_parent(E, A); }
a_avl_new_child(root, P, A, B);
}
static A_INLINE a_avl_node *a_avl_rotate2(a_avl *root, a_avl_node *B, a_avl_node *A, int sign)
{
a_avl_node *const P = a_avl_parent(A);
a_avl_node *const E = a_avl_child(B, +sign);
a_avl_node *const F = a_avl_child(E, -sign);
a_avl_node *const G = a_avl_child(E, +sign);
int const e = a_avl_factor(E);
a_avl_set_child(A, G, -sign);
a_avl_set_parent_factor(A, E, (sign * e >= 0) ? 0 : -e);
a_avl_set_child(B, F, +sign);
a_avl_set_parent_factor(B, E, (sign * e <= 0) ? 0 : -e);
a_avl_set_child(E, A, +sign);
a_avl_set_child(E, B, -sign);
a_avl_set_parent_factor(E, P, 0);
if (F) { a_avl_set_parent(F, B); }
if (G) { a_avl_set_parent(G, A); }
a_avl_new_child(root, P, A, E);
return E;
}
static A_INLINE a_bool a_avl_handle_growth(a_avl *root, a_avl_node *parent, a_avl_node *node, int sign)
{
int const cur_factor = a_avl_factor(parent);
if (cur_factor == 0)
{
a_avl_set_factor(parent, sign);
return A_FALSE;
}
int const new_factor = cur_factor + sign;
if (new_factor == 0)
{
a_avl_set_factor(parent, sign);
return A_TRUE;
}
if (sign * a_avl_factor(node) > 0)
{
a_avl_rotate(root, parent, -sign);
a_avl_set_factor(parent, -sign);
a_avl_set_factor(node, -sign); }
else
{
a_avl_rotate2(root, node, parent, -sign);
}
return A_TRUE;
}
void a_avl_insert_adjust(a_avl *root, a_avl_node *node)
{
a_avl_node *parent = a_avl_parent(node);
if (!parent) { return; }
if (parent->left == node)
{
a_avl_set_factor(parent, -1);
}
else
{
a_avl_set_factor(parent, +1);
}
if (a_avl_factor(parent) == 0) { return; }
a_bool done;
do {
node = parent;
parent = a_avl_parent(node);
if (!parent) { return; }
if (parent->left == node)
{
done = a_avl_handle_growth(root, parent, node, -1);
}
else
{
done = a_avl_handle_growth(root, parent, node, +1);
}
} while (!done);
}
static A_INLINE a_avl_node *a_avl_handle_shrink(a_avl *root, a_avl_node *parent, int sign, a_bool *left)
{
int const cur_factor = a_avl_factor(parent);
if (cur_factor == 0)
{
a_avl_set_factor(parent, sign);
return A_NULL;
}
a_avl_node *node;
int const new_factor = cur_factor + sign;
if (new_factor == 0)
{
a_avl_set_factor(parent, sign);
node = parent;
}
else
{
node = a_avl_child(parent, sign);
if (sign * a_avl_factor(node) >= 0)
{
a_avl_rotate(root, parent, -sign);
if (a_avl_factor(node) == 0)
{
a_avl_set_factor(node, -sign);
return A_NULL;
}
else
{
a_avl_set_factor(parent, -sign);
a_avl_set_factor(node, -sign);
}
}
else
{
node = a_avl_rotate2(root, node, parent, -sign);
}
}
parent = a_avl_parent(node);
if (parent) { *left = (parent->left == node); }
return parent;
}
static A_INLINE a_avl_node *a_avl_handle_remove(a_avl *root, a_avl_node *X, a_bool *left)
{
a_avl_node *node;
a_avl_node *Y = X->right;
if (!Y->left)
{
*left = A_FALSE;
node = Y;
}
else
{
a_avl_node *Q;
do {
Q = Y;
Y = Y->left;
} while (Y->left);
Q->left = Y->right;
if (Y->right)
{
a_avl_set_parent(Y->right, Q);
}
Y->right = X->right;
a_avl_set_parent(X->right, Y);
*left = A_TRUE;
node = Q;
}
Y->left = X->left;
a_avl_set_parent(X->left, Y);
#if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 3)
Y->parent_ = X->parent_;
#else
Y->parent = X->parent;
Y->factor = X->factor;
#endif
a_avl_new_child(root, a_avl_parent(X), X, Y);
return node;
}
void a_avl_remove(a_avl *root, a_avl_node *node)
{
a_avl_node *parent;
a_bool left = A_FALSE;
if (node->left && node->right)
{
parent = a_avl_handle_remove(root, node, &left);
}
else
{
a_avl_node *const child = node->left ? node->left : node->right;
parent = a_avl_parent(node);
if (parent)
{
if (parent->left == node)
{
parent->left = child;
left = A_TRUE;
}
else
{
parent->right = child;
left = A_FALSE;
}
if (child) { a_avl_set_parent(child, parent); }
}
else
{
if (child) { a_avl_set_parent(child, parent); }
root->node = child;
return;
}
}
do
{
if (left)
{
parent = a_avl_handle_shrink(root, parent, +1, &left);
}
else
{
parent = a_avl_handle_shrink(root, parent, -1, &left);
}
} while (parent);
}
a_avl_node *a_avl_insert(a_avl *root, a_avl_node *node, int (*cmp)(void const *, void const *))
{
a_avl_node *parent = root->node;
a_avl_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_avl_init(node, parent);
a_avl_insert_adjust(root, node);
return A_NULL;
}
a_avl_node *a_avl_search(a_avl const *root, void const *ctx, int (*cmp)(void const *, void const *))
{
for (a_avl_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_avl_node *a_avl_head(a_avl const *root)
{
a_avl_node *node = root->node;
if (node)
{
while (node->left) { node = node->left; }
}
return node;
}
a_avl_node *a_avl_tail(a_avl const *root)
{
a_avl_node *node = root->node;
if (node)
{
while (node->right) { node = node->right; }
}
return node;
}
a_avl_node *a_avl_next(a_avl_node *node)
{
if (node->right)
{
node = node->right;
while (node->left) { node = node->left; }
}
else
{
a_avl_node *leaf;
do {
leaf = node;
node = a_avl_parent(node);
} while (node && node->left != leaf);
}
return node;
}
a_avl_node *a_avl_prev(a_avl_node *node)
{
if (node->left)
{
node = node->left;
while (node->right) { node = node->right; }
}
else
{
a_avl_node *leaf;
do {
leaf = node;
node = a_avl_parent(node);
} while (node && node->right != leaf);
}
return node;
}
a_avl_node *a_avl_pre_next(a_avl_node *node)
{
a_avl_node *leaf;
if (node->left) { return node->left; }
if (node->right) { return node->right; }
for (leaf = node, node = a_avl_parent(node); node;
leaf = node, node = a_avl_parent(node))
{
if (node->right && node->right != leaf)
{
node = node->right;
break;
}
}
return node;
}
a_avl_node *a_avl_pre_prev(a_avl_node *node)
{
a_avl_node *leaf;
if (node->right) { return node->right; }
if (node->left) { return node->left; }
for (leaf = node, node = a_avl_parent(node); node;
leaf = node, node = a_avl_parent(node))
{
if (node->left && node->left != leaf)
{
node = node->left;
break;
}
}
return node;
}
#define A_AVL_POST(head, tail) \
for (;;) \
{ \
if (node->head) \
{ \
node = node->head; \
} \
else if (node->tail) \
{ \
node = node->tail; \
} \
else { break; } \
} \
(void)0
a_avl_node *a_avl_post_head(a_avl const *root)
{
a_avl_node *node = root->node;
if (node) { A_AVL_POST(left, right); }
return node;
}
a_avl_node *a_avl_post_tail(a_avl const *root)
{
a_avl_node *node = root->node;
if (node) { A_AVL_POST(right, left); }
return node;
}
a_avl_node *a_avl_post_next(a_avl_node *node)
{
a_avl_node *leaf = node;
node = a_avl_parent(node);
if (node && node->right && node->right != leaf)
{
node = node->right;
A_AVL_POST(left, right);
}
return node;
}
a_avl_node *a_avl_post_prev(a_avl_node *node)
{
a_avl_node *leaf = node;
node = a_avl_parent(node);
if (node && node->left && node->left != leaf)
{
node = node->left;
A_AVL_POST(right, left);
}
return node;
}
a_avl_node *a_avl_tear(a_avl *root, a_avl_node **next)
{
a_avl_node *node = *next;
if (!node)
{
node = root->node;
if (!node) { return node; }
}
A_AVL_POST(left, right);
*next = a_avl_parent(node);
a_avl_new_child(root, *next, node, A_NULL);
return node;
}