-
-static bool
-gl_tree_remove_node (gl_list_t list, gl_list_node_t node)
-{
- gl_list_node_t parent;
-
-#if WITH_HASHTABLE
- /* Remove node from the hash table.
- Note that this is only possible _before_ the node is removed from the
- tree structure, because remove_from_bucket() uses node_position(). */
- remove_from_bucket (list, node);
-#endif
-
- parent = node->parent;
-
- if (node->left == NULL)
- {
- /* Replace node with node->right. */
- gl_list_node_t child = node->right;
-
- if (child != NULL)
- {
- child->parent = parent;
- /* Since node->left == NULL, child must be RED and of height 1,
- hence node must have been BLACK. Recolor the child. */
- child->color = BLACK;
- }
- if (parent == NULL)
- list->root = child;
- else
- {
- if (parent->left == node)
- parent->left = child;
- else /* parent->right == node */
- parent->right = child;
-
- /* Update branch_size fields of the parent nodes. */
- {
- gl_list_node_t p;
-
- for (p = parent; p != NULL; p = p->parent)
- p->branch_size--;
- }
-
- if (child == NULL && node->color == BLACK)
- rebalance_after_remove (list, child, parent);
- }
- }
- else if (node->right == NULL)
- {
- /* It is not absolutely necessary to treat this case. But the more
- general case below is more complicated, hence slower. */
- /* Replace node with node->left. */
- gl_list_node_t child = node->left;
-
- child->parent = parent;
- /* Since node->right == NULL, child must be RED and of height 1,
- hence node must have been BLACK. Recolor the child. */
- child->color = BLACK;
- if (parent == NULL)
- list->root = child;
- else
- {
- if (parent->left == node)
- parent->left = child;
- else /* parent->right == node */
- parent->right = child;
-
- /* Update branch_size fields of the parent nodes. */
- {
- gl_list_node_t p;
-
- for (p = parent; p != NULL; p = p->parent)
- p->branch_size--;
- }
- }
- }
- else
- {
- /* Replace node with the rightmost element of the node->left subtree. */
- gl_list_node_t subst;
- gl_list_node_t subst_parent;
- gl_list_node_t child;
- color_t removed_color;
-
- for (subst = node->left; subst->right != NULL; )
- subst = subst->right;
-
- subst_parent = subst->parent;
-
- child = subst->left;
-
- removed_color = subst->color;
-
- /* The case subst_parent == node is special: If we do nothing special,
- we get confusion about node->left, subst->left and child->parent.
- subst_parent == node
- <==> The 'for' loop above terminated immediately.
- <==> subst == subst_parent->left
- [otherwise subst == subst_parent->right]
- In this case, we would need to first set
- child->parent = node; node->left = child;
- and later - when we copy subst into node's position - again
- child->parent = subst; subst->left = child;
- Altogether a no-op. */
- if (subst_parent != node)
- {
- if (child != NULL)
- child->parent = subst_parent;
- subst_parent->right = child;
- }
-
- /* Update branch_size fields of the parent nodes. */
- {
- gl_list_node_t p;
-
- for (p = subst_parent; p != NULL; p = p->parent)
- p->branch_size--;
- }
-
- /* Copy subst into node's position.
- (This is safer than to copy subst's value into node, keep node in
- place, and free subst.) */
- if (subst_parent != node)
- {
- subst->left = node->left;
- subst->left->parent = subst;
- }
- subst->right = node->right;
- subst->right->parent = subst;
- subst->color = node->color;
- subst->branch_size = node->branch_size;
- subst->parent = parent;
- if (parent == NULL)
- list->root = subst;
- else if (parent->left == node)
- parent->left = subst;
- else /* parent->right == node */
- parent->right = subst;
-
- if (removed_color == BLACK)
- {
- if (child != NULL && child->color == RED)
- /* Recolor the child. */
- child->color = BLACK;
- else
- /* Rebalancing starts at child's parent, that is subst_parent -
- except when subst_parent == node. In this case, we need to use
- its replacement, subst. */
- rebalance_after_remove (list, child,
- subst_parent != node ? subst_parent : subst);
- }
- }
-
- if (list->base.dispose_fn != NULL)
- list->base.dispose_fn (node->value);
- free (node);
- return true;
-}