static uint32 rbt_validate( /*@in@*/ RBT_ROOT *root , /*@in@*/ RBT_NODE *node , /*@out@*/ uint32 *count ) { uint32 black_height_left ; uint32 black_height_right ; uint32 lcount = 0 ; HQASSERT( node != NULL , "Null node: shouldn't happen" ) ; if ( node == &( root->nil ) ) { /* Note: the "p" member of the sentinel could be anything, since it is set during deletion operations. */ HQASSERT( node->key == ( uintptr_t )0 && node->data == NULL && node->left == NULL && node->right == NULL && node->red == FALSE , "Something's stomped on the sentinel! " "(Not a phrase you hear every day)" ) ; return 0 ; } if ( count == NULL ) { count = & lcount ; } count++ ; HQASSERT( node->p != NULL && node->left != NULL && node->right != NULL , "There should be no NULL pointers: point to sentinel instead." ) ; if ( node->red ) { HQASSERT( ! node->left->red && ! node->right->red , "Red nodes must have 2 black descendents." ) ; } if ( node->left != &( root->nil ) ) { HQASSERT( root->compare_keys( root , node->left->key , node->key ) < 0 , "Key order is wrong!" ) ; } if ( node->right != &( root->nil ) ) { HQASSERT( root->compare_keys( root , node->right->key , node->key ) > 0 , "Key order is wrong!" ) ; } black_height_left = rbt_validate( root , node->left , count ) ; black_height_right = rbt_validate( root , node->right , count ) ; HQASSERT( black_height_right == black_height_left , "Black heights must match." ) ; HQASSERT( lcount == 0 || lcount == root->count , "Node count does not validate" ) ; return black_height_left + ( node->red ? 0 : 1 ) ; }
Bool rbt_walk( RBT_ROOT *root , Bool ( *callback )( RBT_ROOT *root , RBT_NODE *node , void *walk_data ) , void *walk_data ) { rbt_validate( root , root->node , NULL ) ; if ( ! rbt_walk_internal( root , root->node , callback , walk_data )) { return FALSE ; } rbt_validate( root , root->node , NULL ) ; return TRUE ; }
/************************************************************************ Add a new node to the tree, useful for data that is pre-sorted. @return appended node */ UNIV_INTERN const ib_rbt_node_t* rbt_add_node( /*=========*/ ib_rbt_t* tree, /*!< in: rb tree */ ib_rbt_bound_t* parent, /*!< in: bounds */ const void* value) /*!< in: this value is copied to the node */ { ib_rbt_node_t* node; /* Create the node that will hold the value data */ node = (ib_rbt_node_t*) ut_malloc(SIZEOF_NODE(tree)); memcpy(node->value, value, tree->sizeof_value); node->parent = node->left = node->right = tree->nil; /* If tree is empty */ if (parent->last == NULL) { parent->last = tree->root; } /* Append the node, the hope here is that the caller knows what s/he is doing. */ rbt_tree_add_child(tree, parent, node); rbt_balance_tree(tree, node); ++tree->n_nodes; #if defined(IB_RBT_TESTING) ut_a(rbt_validate(tree)); #endif return(node); }
/****************************************************************//** Add a new caller-provided node to tree at the specified position. The node must have its key fields initialized correctly. @return added node */ UNIV_INTERN const ib_rbt_node_t* rbt_add_preallocated_node( /*======================*/ ib_rbt_t* tree, /*!< in: rb tree */ ib_rbt_bound_t* parent, /*!< in: parent */ ib_rbt_node_t* node) /*!< in: node */ { node->parent = node->left = node->right = tree->nil; /* If tree is empty */ if (parent->last == NULL) { parent->last = tree->root; } /* Append the node, the hope here is that the caller knows what s/he is doing. */ rbt_tree_add_child(tree, parent, node); rbt_balance_tree(tree, node); ++tree->n_nodes; #if defined(IB_RBT_TESTING) ut_a(rbt_validate(tree)); #endif return(node); }
/************************************************************************ Merge the node from dst into src. Return the number of nodes merged. Delete the nodes from src after copying node to dst. As a side effect the duplicates will be left untouched in the src. @return no. of recs merged */ UNIV_INTERN ulint rbt_merge_uniq_destructive( /*=======================*/ ib_rbt_t* dst, /*!< in: dst rb tree */ ib_rbt_t* src) /*!< in: src rb tree */ { ib_rbt_bound_t parent; ib_rbt_node_t* src_node; ulint old_size = rbt_size(dst); if (rbt_empty(src) || dst == src) { return(0); } for (src_node = (ib_rbt_node_t*) rbt_first(src); src_node; /* */) { ib_rbt_node_t* prev = src_node; src_node = (ib_rbt_node_t*)rbt_next(src, prev); /* Skip duplicates. */ if (rbt_search(dst, &parent, prev->value) != 0) { /* Remove and reset the node but preserve the node (data) value. */ rbt_remove_node_and_rebalance(src, prev); /* The nil should be taken from the dst tree. */ prev->parent = prev->left = prev->right = dst->nil; rbt_tree_add_child(dst, &parent, prev); rbt_balance_tree(dst, prev); ++dst->n_nodes; } } #if defined(IB_RBT_TESTING) ut_a(rbt_validate(dst)); ut_a(rbt_validate(src)); #endif return(rbt_size(dst) - old_size); }
RBT_NODE *rbt_remove( RBT_ROOT *root , RBT_NODE *z ) { RBT_NODE *x ; RBT_NODE *y ; if ( z == &( root->nil ) ) { return NULL ; } HQTRACE( rbt_debug , ( "rbt_remove: [%x] %x" , root , z->key )) ; if ( z->left == &( root->nil ) || z->right == &( root->nil ) ) { y = z ; } else { y = rbt_successor( root , z ) ; } HQASSERT( y != NULL , "Should rbt_successor return NULL?" ) ; if ( y->left != &( root->nil ) ) { x = y->left ; } else { x = y->right ; } x->p = y->p ; if ( y->p == &( root->nil ) ) { root->node = x ; } else { if ( y == y->p->left ) { y->p->left = x ; } else { y->p->right = x ; } } if ( y != z ) { uintptr_t tk ; void *td ; /* The example pseudo-code just copies data and "other fields" from y to z. That's not good enough when any one of them is a pointer: we end up with one data struct being doubly referenced and the other one orphaned. Solution: swap the pointers instead. */ tk = z->key ; z->key = y->key ; y->key = tk ; td = z->data ; z->data = y->data ; y->data = td ; } if ( y->red == FALSE ) { rbt_remove_fixup( root , x ) ; } root->count-- ; rbt_validate( root , root->node , NULL ) ; return y ; }
static void rbt_remove_fixup( RBT_ROOT *root , RBT_NODE *x ) { RBT_NODE *w ; while ( x != root->node && ! x->red ) { HQTRACE( rbt_debug , ( "rbt_remove_fixup: [%x] %x" , root , x->key )) ; if ( x == x->p->left ) { w = x->p->right ; if ( w->red ) { w->red = FALSE ; x->p->red = TRUE ; rbt_leftrotate( root , x->p ) ; w = x->p->right ; } if ( ! w->left->red && ! w->right->red ) { w->red = TRUE ; x = x->p ; } else { if ( ! w->right->red ) { w->left->red = FALSE ; w->red = TRUE ; rbt_rightrotate( root , w ) ; w = x->p->right ; } w->red = x->p->red ; x->p->red = FALSE ; w->right->red = FALSE ; rbt_leftrotate( root , x->p ) ; x = root->node ; } } else { w = x->p->left ; if ( w->red ) { w->red = FALSE ; x->p->red = TRUE ; rbt_rightrotate( root , x->p ) ; w = x->p->left ; } if ( ! w->right->red && ! w->left->red ) { w->red = TRUE ; x = x->p ; } else { if ( ! w->left->red ) { w->right->red = FALSE ; w->red = TRUE ; rbt_leftrotate( root , w ) ; w = x->p->left ; } w->red = x->p->red ; x->p->red = FALSE ; w->left->red = FALSE ; rbt_rightrotate( root , x->p ) ; x = root->node ; } } } x->red = FALSE ; HQTRACE( rbt_debug , ( "rbt_remove_fixup complete: [%x] %x" , root , x->key )) ; rbt_validate( root , root->node , NULL ) ; }
void rbt_insert( /*@in@*/ RBT_ROOT *root , RBT_NODE *x ) { RBT_NODE *y ; rbt_validate( root , root->node , NULL ) ; HQTRACE( rbt_debug , ( "rbt_insert: [%x] %x" , root , x->key )) ; bt_insert( root , x ) ; x->red = TRUE ; while ( x != root->node && x->p->red ) { if ( x->p == x->p->p->left ) { y = x->p->p->right ; if ( y->red ) { x->p->red = FALSE ; y->red = FALSE ; x->p->p->red = TRUE ; x = x->p->p ; } else { if ( x == x->p->right ) { x = x->p ; rbt_leftrotate( root , x ) ; } x->p->red = FALSE ; x->p->p->red = TRUE ; rbt_rightrotate( root , x->p->p ) ; } } else { y = x->p->p->left ; if ( y->red ) { x->p->red = FALSE ; y->red = FALSE ; x->p->p->red = TRUE ; x = x->p->p ; } else { if ( x == x->p->left ) { x = x->p ; rbt_rightrotate( root , x ) ; } x->p->red = FALSE ; x->p->p->red = TRUE ; rbt_leftrotate( root , x->p->p ) ; } } } root->node->red = FALSE ; root->count++ ; rbt_validate( root , root->node , NULL ) ; }