/* ============================================================================= * TMdelete * ============================================================================= */ static node_t* TMdelete (TM_ARGDECL rbtree_t* s, node_t* p) { /* * If strictly internal, copy successor's element to p and then make p * point to successor */ if (TX_LDNODE_PROMO(p, l) != NULL && TX_LDNODE_PROMO(p, r) != NULL) { node_t* s = TX_SUCCESSOR(p); TX_STF_P(p,k, TX_LDF_P(s, k)); TX_STF_P(p,v, TX_LDF_P(s, v)); p = s; } /* p has 2 children */ /* Start fixup at replacement node, if it exists */ node_t* replacement = ((TX_LDNODE_PROMO(p, l) != NULL) ? TX_LDNODE_PROMO(p, l) : TX_LDNODE_PROMO(p, r)); if (replacement != NULL) { /* Link replacement to parent */ /* TODO: precompute pp = p->p and substitute below ... */ TX_STF_P(replacement, p, TX_LDNODE(p, p)); node_t* pp = TX_LDNODE(p, p); if (pp == NULL) { TX_STF_P(s, root, replacement); } else if (p == TX_LDNODE_PROMO(pp, l)) { TX_STF_P(pp, l, replacement); } else { TX_STF_P(pp, r, replacement); } /* Null out links so they are OK to use by fixAfterDeletion */ TX_STF_P(p, l, (node_t*)NULL); TX_STF_P(p, r, (node_t*)NULL); TX_STF_P(p, p, (node_t*)NULL); /* Fix replacement */ if (TX_LDF(p,c) == BLACK) { TX_FIX_AFTER_DELETION(s, replacement); } } else if (TX_LDNODE(p,p) == NULL) { /* return if we are the only node */ TX_STF_P(s, root, (node_t*)NULL); } else { /* No children. Use self as phantom replacement and unlink */ if (TX_LDF_PROMO(p,c) == BLACK) { TX_FIX_AFTER_DELETION(s, p); } node_t* pp = TX_LDNODE(p, p); if (pp != NULL) { if (p == TX_LDNODE_PROMO(pp, l)) { TX_STF_P(pp,l, (node_t*)NULL); } else if (p == TX_LDNODE(pp, r)) { TX_STF_P(pp, r, (node_t*)NULL); } TX_STF_P(p, p, (node_t*)NULL); } } return p; }
/* ============================================================================= * TMinsert * ============================================================================= */ static node_t* TMinsert (TM_ARGDECL rbtree_t* s, void* k, void* v, node_t* n) { node_t* t = TX_LDNODE(s, root); if (t == NULL) { if (n == NULL) { return NULL; } /* Note: the following STs don't really need to be transactional */ TX_STF_P(n, l, (node_t*)NULL); TX_STF_P(n, r, (node_t*)NULL); TX_STF_P(n, p, (node_t*)NULL); TX_STF_P(n, k, k); TX_STF_P(n, v, v); TX_STF(n, c, BLACK); TX_STF_P(s, root, n); return NULL; } long int (*compare)(TM_ARGDECL const void*, const void*) = s->compare->compare_tm; for (;;) { long cmp = compare(TM_ARG k, TX_LDF_P(t, k)); if (cmp == 0) { return t; } else if (cmp < 0) { node_t* tl = TX_LDNODE(t, l); if (tl != NULL) { t = tl; } else { TX_STF_P(n, l, (node_t*)NULL); TX_STF_P(n, r, (node_t*)NULL); TX_STF_P(n, k, k); TX_STF_P(n, v, v); TX_STF_P(n, p, t); TX_STF_P(t, l, n); TX_FIX_AFTER_INSERTION(s, n); return NULL; } } else { /* cmp > 0 */ node_t* tr = TX_LDNODE(t, r); if (tr != NULL) { t = tr; } else { TX_STF_P(n, l, (node_t*)NULL); TX_STF_P(n, r, (node_t*)NULL); TX_STF_P(n, k, k); TX_STF_P(n, v, v); TX_STF_P(n, p, t); TX_STF_P(t, r, n); TX_FIX_AFTER_INSERTION(s, n); return NULL; } } } }
/* ============================================================================= * TMfixAfterInsertion * ============================================================================= */ static void TMfixAfterInsertion (TM_ARGDECL rbtree_t* s, node_t* x) { TX_STF(x, c, RED); while (x != NULL && x != TX_LDNODE(s, root)) { node_t* xp = TX_LDNODE(x, p); if (TX_LDF(xp, c) != RED) { break; } /* TODO: cache g = ppx = TX_PARENT_OF(TX_PARENT_OF(x)) */ if (TX_PARENT_OF(x) == TX_LEFT_OF(TX_PARENT_OF(TX_PARENT_OF(x)))) { node_t* y = TX_RIGHT_OF(TX_PARENT_OF(TX_PARENT_OF(x))); if (TX_COLOR_OF(y) == RED) { TX_SET_COLOR(TX_PARENT_OF(x), BLACK); TX_SET_COLOR(y, BLACK); TX_SET_COLOR(TX_PARENT_OF(TX_PARENT_OF(x)), RED); x = TX_PARENT_OF(TX_PARENT_OF(x)); } else { if (x == TX_RIGHT_OF(TX_PARENT_OF(x))) { x = TX_PARENT_OF(x); TX_ROTATE_LEFT(s, x); } TX_SET_COLOR(TX_PARENT_OF(x), BLACK); TX_SET_COLOR(TX_PARENT_OF(TX_PARENT_OF(x)), RED); if (TX_PARENT_OF(TX_PARENT_OF(x)) != NULL) { TX_ROTATE_RIGHT(s, TX_PARENT_OF(TX_PARENT_OF(x))); } } } else { node_t* y = TX_LEFT_OF(TX_PARENT_OF(TX_PARENT_OF(x))); if (TX_COLOR_OF(y) == RED) { TX_SET_COLOR(TX_PARENT_OF(x), BLACK); TX_SET_COLOR(y, BLACK); TX_SET_COLOR(TX_PARENT_OF(TX_PARENT_OF(x)), RED); x = TX_PARENT_OF(TX_PARENT_OF(x)); } else { if (x == TX_LEFT_OF(TX_PARENT_OF(x))) { x = TX_PARENT_OF(x); TX_ROTATE_RIGHT(s, x); } TX_SET_COLOR(TX_PARENT_OF(x), BLACK); TX_SET_COLOR(TX_PARENT_OF(TX_PARENT_OF(x)), RED); if (TX_PARENT_OF(TX_PARENT_OF(x)) != NULL) { TX_ROTATE_LEFT(s, TX_PARENT_OF(TX_PARENT_OF(x))); } } } } node_t* ro = TX_LDNODE(s, root); if (TX_LDF(ro, c) != BLACK) { TX_STF(ro, c, BLACK); } }
/* ============================================================================= * TMlookup * ============================================================================= */ static node_t* TMlookup (TM_ARGDECL rbtree_t* s, void* k) { node_t* p = TX_LDNODE(s, root); long int (*compare)(TM_ARGDECL const void*, const void*) = s->compare->compare_tm; while (p != NULL) { long cmp = compare(TM_ARG k, TX_LDF_P(p, k)); if (cmp == 0) { return p; } p = ((cmp < 0) ? TX_LDNODE(p, l) : TX_LDNODE(p, r)); } return NULL; }
/* ============================================================================= * TMrotateRight * ============================================================================= */ static void TMrotateRight (TM_ARGDECL rbtree_t* s, node_t* x) { node_t* l = TX_LDNODE(x, l); /* AKA l,y */ node_t* lr = TX_LDNODE(l, r); TX_STF_P(x, l, lr); if (lr != NULL) { TX_STF_P(lr, p, x); } node_t* xp = TX_LDNODE(x, p); TX_STF_P(l, p, xp); if (xp == NULL) { TX_STF_P(s, root, l); } else if (TX_LDNODE(xp, r) == x) { TX_STF_P(xp, r, l); } else { TX_STF_P(xp, l, l); } TX_STF_P(l, r, x); TX_STF_P(x, p, l); }
/* ============================================================================= * TMsuccessor * ============================================================================= */ static node_t* TMsuccessor (TM_ARGDECL node_t* t) { if (t == NULL) { return NULL; } else if (TX_LDNODE_PROMO(t, r) != NULL) { node_t* p = TX_LDNODE_PROMO(t,r); while (TX_LDNODE_PROMO(p, l) != NULL) { p = TX_LDNODE_PROMO(p, l); } return p; } else { node_t* p = TX_LDNODE(t, p); node_t* ch = t; while (p != NULL && ch == TX_LDNODE(p, r)) { ch = p; p = TX_LDNODE(p, p); } return p; } }
/* ============================================================================= * TMrotateLeft * ============================================================================= */ static void TMrotateLeft (TM_ARGDECL rbtree_t* s, node_t* x) { node_t* r = TX_LDNODE(x, r); /* AKA r, y */ node_t* rl = TX_LDNODE(r, l); TX_STF_P(x, r, rl); if (rl != NULL) { TX_STF_P(rl, p, x); } /* TODO: compute p = xp = x->p. Use xp for R-Values in following */ node_t* xp = TX_LDNODE(x, p); TX_STF_P(r, p, xp); if (xp == NULL) { TX_STF_P(s, root, r); } else if (TX_LDNODE(xp, l) == x) { TX_STF_P(xp, l, r); } else { TX_STF_P(xp, r, r); } TX_STF_P(r, l, x); TX_STF_P(x, p, r); }
/* ============================================================================= * TMfixAfterDeletion * ============================================================================= */ static void TMfixAfterDeletion (TM_ARGDECL rbtree_t* s, node_t* x) { while (x != TX_LDNODE(s,root) && TX_COLOR_OF(x) == BLACK) { if (x == TX_LEFT_OF(TX_PARENT_OF(x))) { node_t* sib = TX_RIGHT_OF(TX_PARENT_OF(x)); if (TX_COLOR_OF(sib) == RED) { TX_SET_COLOR(sib, BLACK); TX_SET_COLOR(TX_PARENT_OF(x), RED); TX_ROTATE_LEFT(s, TX_PARENT_OF(x)); sib = TX_RIGHT_OF(TX_PARENT_OF(x)); } if (TX_COLOR_OF(TX_LEFT_OF(sib)) == BLACK && TX_COLOR_OF(TX_RIGHT_OF(sib)) == BLACK) { TX_SET_COLOR(sib, RED); x = TX_PARENT_OF(x); } else { if (TX_COLOR_OF(TX_RIGHT_OF(sib)) == BLACK) { TX_SET_COLOR(TX_LEFT_OF(sib), BLACK); TX_SET_COLOR(sib, RED); TX_ROTATE_RIGHT(s, sib); sib = TX_RIGHT_OF(TX_PARENT_OF(x)); } TX_SET_COLOR(sib, TX_COLOR_OF(TX_PARENT_OF(x))); TX_SET_COLOR(TX_PARENT_OF(x), BLACK); TX_SET_COLOR(TX_RIGHT_OF(sib), BLACK); TX_ROTATE_LEFT(s, TX_PARENT_OF(x)); /* TODO: consider break ... */ x = TX_LDNODE(s,root); } } else { /* symmetric */ node_t* sib = TX_LEFT_OF(TX_PARENT_OF(x)); if (TX_COLOR_OF(sib) == RED) { TX_SET_COLOR(sib, BLACK); TX_SET_COLOR(TX_PARENT_OF(x), RED); TX_ROTATE_RIGHT(s, TX_PARENT_OF(x)); sib = TX_LEFT_OF(TX_PARENT_OF(x)); } if (TX_COLOR_OF(TX_RIGHT_OF(sib)) == BLACK && TX_COLOR_OF(TX_LEFT_OF(sib)) == BLACK) { TX_SET_COLOR(sib, RED); x = TX_PARENT_OF(x); } else { if (TX_COLOR_OF(TX_LEFT_OF(sib)) == BLACK) { TX_SET_COLOR(TX_RIGHT_OF(sib), BLACK); TX_SET_COLOR(sib, RED); TX_ROTATE_LEFT(s, sib); sib = TX_LEFT_OF(TX_PARENT_OF(x)); } TX_SET_COLOR(sib, TX_COLOR_OF(TX_PARENT_OF(x))); TX_SET_COLOR(TX_PARENT_OF(x), BLACK); TX_SET_COLOR(TX_LEFT_OF(sib), BLACK); TX_ROTATE_RIGHT(s, TX_PARENT_OF(x)); /* TODO: consider break ... */ x = TX_LDNODE(s, root); } } } if (x != NULL && TX_LDF(x,c) != BLACK) { TX_STF(x, c, BLACK); } }
/* ============================================================================= * TMrightOf * ============================================================================= */ static inline node_t* TMrightOf (TM_ARGDECL node_t* n) { return (n ? TX_LDNODE(n, r) : NULL); }
/* ============================================================================= * TMleftOf * ============================================================================= */ static inline node_t* TMleftOf (TM_ARGDECL node_t* n) { return (n ? TX_LDNODE(n, l) : NULL); }
/* ============================================================================= * TMparentOf * ============================================================================= */ static inline node_t* TMparentOf (TM_ARGDECL node_t* n) { return (n ? TX_LDNODE(n,p) : NULL); }