/* Deletes from |tree| and returns an item matching |item|. Returns a null pointer if no matching item found. */ void * rtrb_delete (struct rtrb_table *tree, const void *item) { struct rtrb_node *pa[RTRB_MAX_HEIGHT]; /* Nodes on stack. */ unsigned char da[RTRB_MAX_HEIGHT]; /* Directions moved from stack nodes. */ int k; /* Stack height. */ struct rtrb_node *p; assert (tree != NULL && item != NULL); k = 1; da[0] = 0; pa[0] = (struct rtrb_node *) &tree->rtrb_root; p = tree->rtrb_root; if (p == NULL) return NULL; for (;;) { int cmp, dir; cmp = tree->rtrb_compare (item, p->rtrb_data, tree->rtrb_param); if (cmp == 0) break; dir = cmp > 0; if (dir == 0) { if (p->rtrb_link[0] == NULL) return NULL; } else /* |dir == 1| */ { if (p->rtrb_rtag == RTRB_THREAD) return NULL; } pa[k] = p; da[k++] = dir; p = p->rtrb_link[dir]; } tree->rtrb_count--; item = p->rtrb_data; if (p->rtrb_link[0] == NULL) { if (p->rtrb_rtag == RTRB_CHILD) { pa[k - 1]->rtrb_link[da[k - 1]] = p->rtrb_link[1]; } else { pa[k - 1]->rtrb_link[da[k - 1]] = p->rtrb_link[da[k - 1]]; if (da[k - 1] == 1) pa[k - 1]->rtrb_rtag = RTRB_THREAD; } } else { enum rtrb_color t; struct rtrb_node *r = p->rtrb_link[0]; if (r->rtrb_rtag == RTRB_THREAD) { r->rtrb_link[1] = p->rtrb_link[1]; r->rtrb_rtag = p->rtrb_rtag; t = r->rtrb_color; r->rtrb_color = p->rtrb_color; p->rtrb_color = t; pa[k - 1]->rtrb_link[da[k - 1]] = r; da[k] = 0; pa[k++] = r; } else { struct rtrb_node *s; int j = k++; for (;;) { da[k] = 1; pa[k++] = r; s = r->rtrb_link[1]; if (s->rtrb_rtag == RTRB_THREAD) break; r = s; } da[j] = 0; pa[j] = pa[j - 1]->rtrb_link[da[j - 1]] = s; if (s->rtrb_link[0] != NULL) r->rtrb_link[1] = s->rtrb_link[0]; else { r->rtrb_rtag = RTRB_THREAD; r->rtrb_link[1] = s; } s->rtrb_link[0] = p->rtrb_link[0]; s->rtrb_link[1] = p->rtrb_link[1]; s->rtrb_rtag = p->rtrb_rtag; t = s->rtrb_color; s->rtrb_color = p->rtrb_color; p->rtrb_color = t; } } if (p->rtrb_color == RTRB_BLACK) { for (; k > 1; k--) { struct rtrb_node *x; if (da[k - 1] == 0 || pa[k - 1]->rtrb_rtag == RTRB_CHILD) x = pa[k - 1]->rtrb_link[da[k - 1]]; else x = NULL; if (x != NULL && x->rtrb_color == RTRB_RED) { x->rtrb_color = RTRB_BLACK; break; } if (da[k - 1] == 0) { struct rtrb_node *w = pa[k - 1]->rtrb_link[1]; if (w->rtrb_color == RTRB_RED) { w->rtrb_color = RTRB_BLACK; pa[k - 1]->rtrb_color = RTRB_RED; pa[k - 1]->rtrb_link[1] = w->rtrb_link[0]; w->rtrb_link[0] = pa[k - 1]; pa[k - 2]->rtrb_link[da[k - 2]] = w; pa[k] = pa[k - 1]; da[k] = 0; pa[k - 1] = w; k++; w = pa[k - 1]->rtrb_link[1]; } if ((w->rtrb_link[0] == NULL || w->rtrb_link[0]->rtrb_color == RTRB_BLACK) && (w->rtrb_rtag == RTRB_THREAD || w->rtrb_link[1]->rtrb_color == RTRB_BLACK)) { w->rtrb_color = RTRB_RED; } else { if (w->rtrb_rtag == RTRB_THREAD || w->rtrb_link[1]->rtrb_color == RTRB_BLACK) { struct rtrb_node *y = w->rtrb_link[0]; y->rtrb_color = RTRB_BLACK; w->rtrb_color = RTRB_RED; w->rtrb_link[0] = y->rtrb_link[1]; y->rtrb_link[1] = w; w = pa[k - 1]->rtrb_link[1] = y; if (w->rtrb_rtag == RTRB_THREAD) { w->rtrb_rtag = RTRB_CHILD; w->rtrb_link[1]->rtrb_link[0] = NULL; } } w->rtrb_color = pa[k - 1]->rtrb_color; pa[k - 1]->rtrb_color = RTRB_BLACK; w->rtrb_link[1]->rtrb_color = RTRB_BLACK; pa[k - 1]->rtrb_link[1] = w->rtrb_link[0]; w->rtrb_link[0] = pa[k - 1]; pa[k - 2]->rtrb_link[da[k - 2]] = w; if (w->rtrb_link[0]->rtrb_link[1] == NULL) { w->rtrb_link[0]->rtrb_rtag = RTRB_THREAD; w->rtrb_link[0]->rtrb_link[1] = w; } break; } } else { struct rtrb_node *w = pa[k - 1]->rtrb_link[0]; if (w->rtrb_color == RTRB_RED) { w->rtrb_color = RTRB_BLACK; pa[k - 1]->rtrb_color = RTRB_RED; pa[k - 1]->rtrb_link[0] = w->rtrb_link[1]; w->rtrb_link[1] = pa[k - 1]; pa[k - 2]->rtrb_link[da[k - 2]] = w; pa[k] = pa[k - 1]; da[k] = 1; pa[k - 1] = w; k++; w = pa[k - 1]->rtrb_link[0]; } if ((w->rtrb_link[0] == NULL || w->rtrb_link[0]->rtrb_color == RTRB_BLACK) && (w->rtrb_rtag == RTRB_THREAD || w->rtrb_link[1]->rtrb_color == RTRB_BLACK)) { w->rtrb_color = RTRB_RED; } else { if (w->rtrb_link[0] == NULL || w->rtrb_link[0]->rtrb_color == RTRB_BLACK) { struct rtrb_node *y = w->rtrb_link[1]; y->rtrb_color = RTRB_BLACK; w->rtrb_color = RTRB_RED; w->rtrb_link[1] = y->rtrb_link[0]; y->rtrb_link[0] = w; w = pa[k - 1]->rtrb_link[0] = y; if (w->rtrb_link[0]->rtrb_link[1] == NULL) { w->rtrb_link[0]->rtrb_rtag = RTRB_THREAD; w->rtrb_link[0]->rtrb_link[1] = w; } } w->rtrb_color = pa[k - 1]->rtrb_color; pa[k - 1]->rtrb_color = RTRB_BLACK; w->rtrb_link[0]->rtrb_color = RTRB_BLACK; pa[k - 1]->rtrb_link[0] = w->rtrb_link[1]; w->rtrb_link[1] = pa[k - 1]; pa[k - 2]->rtrb_link[da[k - 2]] = w; if (w->rtrb_rtag == RTRB_THREAD) { w->rtrb_rtag = RTRB_CHILD; pa[k - 1]->rtrb_link[0] = NULL; } break; } } } if (tree->rtrb_root != NULL) tree->rtrb_root->rtrb_color = RTRB_BLACK; } tree->rtrb_alloc->libavl_free (tree->rtrb_alloc, p); return (void *) item; }