Example #1
0
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 ) ;
}
Example #2
0
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 ;
}
Example #3
0
/************************************************************************
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);
}
Example #4
0
/****************************************************************//**
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);
}
Example #5
0
/************************************************************************
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);
}
Example #6
0
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 ;
}
Example #7
0
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 ) ;
}
Example #8
0
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 ) ;
}