/** @brief Validate and fix-up tree properties for a new insert/colored node
 *
 *  This routine checks and fixes the Red-Black Tree properties based on
 *  @a the_node being just added to the tree.
 *
 *  @note It does NOT disable interrupts to ensure the atomicity of the
 *        append operation.
 */
static void _RBTree_Validate_insert( RBTree_Node *the_node )
{
  RBTree_Node  *parent = _RBTree_Parent( the_node );
  RBTree_Color  parentcolor;
  RBTree_Node  *grandparent = _RBTree_Parent_and_color( parent, &parentcolor );

  /* note: the insert root case is handled already */
  /* if the parent is black, nothing needs to be done
   * otherwise may need to loop a few times */
  while ( parentcolor == RBT_RED ) {
    /* The root is black, so the grandparent must exist */
    RBTree_Node *uncle = _RBTree_Sibling( parent, grandparent );
    RBTree_Node *grandgrandparent = _RBTree_Parent( grandparent );

    /*
     * If uncle exists and is red, repaint uncle/parent black and grandparent
     * red.
     */
    if ( uncle != NULL && _RBTree_Color( uncle ) == RBT_RED ) {
      _RBTree_Set_parent_and_color( parent, grandparent, RBT_BLACK );
      _RBTree_Set_parent_and_color( uncle, grandparent, RBT_BLACK );
      _RBTree_Set_parent_and_color( grandparent, grandgrandparent, RBT_RED );
      the_node = grandparent;
      parent = grandgrandparent;
      grandparent = _RBTree_Parent_and_color( parent, &parentcolor );

      if ( grandparent == NULL )
        break;
    } else { /* If uncle does not exist or is black */
      RBTree_Direction dir = _RBTree_Direction( the_node, parent );
      RBTree_Direction parentdir = _RBTree_Direction( parent, grandparent );

      /* ensure node is on the same branch direction as parent */
      if ( dir != parentdir ) {
        RBTree_Node *oldparent = parent;

        parent = the_node;
        the_node = oldparent;
        _RBTree_Rotate( oldparent, parentdir );
      }

      _RBTree_Set_color( parent, RBT_BLACK );
      _RBTree_Set_parent_and_color( grandparent, grandgrandparent, RBT_RED );

      /* now rotate grandparent in the other branch direction (toward uncle) */
      _RBTree_Rotate( grandparent, _RBTree_Opposite_direction( parentdir ) );

      grandparent = _RBTree_Parent( parent );
      break;
    }
  }

  if ( grandparent == NULL )
    _RBTree_Set_parent_and_color( the_node, parent, RBT_BLACK );
}
Exemple #2
0
void _RBTree_Iterate_unprotected(
  const RBTree_Control *rbtree,
  RBTree_Direction dir,
  RBTree_Visitor visitor,
  void *visitor_arg
)
{
  RBTree_Direction opp_dir = _RBTree_Opposite_direction( dir );
  const RBTree_Node *current = _RBTree_First( rbtree, opp_dir );
  bool stop = false;

  while ( !stop && current != NULL ) {
    stop = (*visitor)( current, dir, visitor_arg );

    current = _RBTree_Next_unprotected( current, dir );
  }
}
Exemple #3
0
/** @brief  Validate and fix-up tree properties after deleting a node
 *
 *  This routine is called on a black node, @a the_node, after its deletion.
 *  This function maintains the properties of the red-black tree.
 *
 *  @note It does NOT disable interrupts to ensure the atomicity
 *        of the extract operation.
 */
static void _RBTree_Extract_validate( RBTree_Node *the_node )
{
  RBTree_Node     *parent;

  parent = the_node->parent;

  if ( !parent->parent )
    return;

  /* continue to correct tree as long as the_node is black and not the root */
  while ( !_RBTree_Is_red( the_node ) && parent->parent ) {
    RBTree_Node *sibling = _RBTree_Sibling( the_node, parent );

    /* if sibling is red, switch parent (black) and sibling colors,
     * then rotate parent left, making the sibling be the_node's grandparent.
     * Now the_node has a black sibling and red parent. After rotation,
     * update sibling pointer.
     */
    if ( _RBTree_Is_red( sibling ) ) {
      RBTree_Direction dir = _RBTree_Direction( the_node, parent );
      RBTree_Direction opp_dir = _RBTree_Opposite_direction( dir );

      parent->color = RBT_RED;
      sibling->color = RBT_BLACK;
      _RBTree_Rotate( parent, dir );
      sibling = parent->child[ opp_dir ];
    }

    /* sibling is black, see if both of its children are also black. */
    if ( !_RBTree_Is_red( sibling->child[ RBT_RIGHT ] ) &&
         !_RBTree_Is_red( sibling->child[ RBT_LEFT ] ) ) {
      sibling->color = RBT_RED;

      if ( _RBTree_Is_red( parent ) ) {
        parent->color = RBT_BLACK;
        break;
      }

      the_node = parent;   /* done if parent is red */
      parent = the_node->parent;
    } else {
      /* at least one of sibling's children is red. we now proceed in two
       * cases, either the_node is to the left or the right of the parent.
       * In both cases, first check if one of sibling's children is black,
       * and if so rotate in the proper direction and update sibling pointer.
       * Then switch the sibling and parent colors, and rotate through parent.
       */
      RBTree_Direction dir = _RBTree_Direction( the_node, parent );
      RBTree_Direction opp_dir = _RBTree_Opposite_direction( dir );

      if (
        !_RBTree_Is_red( sibling->child[ opp_dir ] )
      ) {
        sibling->color = RBT_RED;
        sibling->child[ dir ]->color = RBT_BLACK;
        _RBTree_Rotate( sibling, opp_dir );
        sibling = parent->child[ opp_dir ];
      }

      sibling->color = parent->color;
      parent->color = RBT_BLACK;
      sibling->child[ opp_dir ]->color = RBT_BLACK;
      _RBTree_Rotate( parent, dir );
      break; /* done */
    }
  } /* while */

  if ( !the_node->parent->parent )
    the_node->color = RBT_BLACK;
}
/** @brief  Validate and fix-up tree properties after deleting a node
 *
 *  This routine is called on a black node, @a the_node, after its deletion.
 *  This function maintains the properties of the red-black tree.
 */
static void rtems_rbtree_extract_validate( RBTree_Node *the_node )
{
  RBTree_Color  color;
  RBTree_Node  *parent = _RBTree_Parent_and_color( the_node, &color );
  RBTree_Color  parentcolor;
  RBTree_Node  *grandparent = _RBTree_Parent_and_color( parent, &parentcolor );

  if ( grandparent == NULL )
    return;

  /* continue to correct tree as long as the_node is black and not the root */
  while ( grandparent != NULL &&  color == RBT_BLACK ) {
    RBTree_Node  *sibling = _RBTree_Sibling( the_node, parent );

    /* if sibling is red, switch parent (black) and sibling colors,
     * then rotate parent left, making the sibling be the_node's grandparent.
     * Now the_node has a black sibling and red parent. After rotation,
     * update sibling pointer.
     */
    if ( _RBTree_Color( sibling ) == RBT_RED ) {
      RBTree_Direction dir = _RBTree_Direction( the_node, parent );
      RBTree_Direction opp_dir = _RBTree_Opposite_direction( dir );

      parentcolor = RBT_RED;
      _RBTree_Set_parent_and_color( parent, grandparent, parentcolor );
      _RBTree_Set_parent_and_color( sibling, parent, RBT_BLACK );

      _RBTree_Rotate( parent, dir );
      grandparent = sibling;
      sibling = parent->child[ opp_dir ];
    }

    /* sibling is black, see if both of its children are also black. */
    if ( _RBTree_Is_null_or_black( sibling->child[ RBT_RIGHT ] ) &&
         _RBTree_Is_null_or_black( sibling->child[ RBT_LEFT ] ) ) {
      _RBTree_Set_parent_and_color( sibling, parent, RBT_RED );

      if ( parentcolor == RBT_RED ) {
        _RBTree_Set_parent_and_color( parent, grandparent, RBT_BLACK );
        break;
      }

      the_node = parent;   /* done if parent is red */
      parent = grandparent;
      grandparent = _RBTree_Parent_and_color( parent, &parentcolor );
    } else {
      /* at least one of sibling's children is red. we now proceed in two
       * cases, either the_node is to the left or the right of the parent.
       * In both cases, first check if one of sibling's children is black,
       * and if so rotate in the proper direction and update sibling pointer.
       * Then switch the sibling and parent colors, and rotate through parent.
       */
      RBTree_Direction dir = _RBTree_Direction( the_node, parent );
      RBTree_Direction opp_dir = _RBTree_Opposite_direction( dir );

      if ( _RBTree_Is_null_or_black( sibling->child[ opp_dir ] ) ) {
        _RBTree_Set_parent_and_color( sibling, parent, RBT_RED );
        _RBTree_Set_parent_and_color(
          sibling->child[ dir ],
          sibling,
          RBT_BLACK
         );
        _RBTree_Rotate( sibling, opp_dir );
        sibling = parent->child[ opp_dir ];
      }

      _RBTree_Set_parent_and_color( sibling, parent, parentcolor );
      _RBTree_Set_parent_and_color( parent, grandparent, RBT_BLACK );
      _RBTree_Set_parent_and_color(
         sibling->child[ opp_dir ],
         sibling,
         RBT_BLACK
       );

      _RBTree_Rotate( parent, dir );
      grandparent = sibling;
      break; /* done */
    }
  } /* while */

  if ( grandparent == NULL )
    _RBTree_Set_parent_and_color( the_node, parent, RBT_BLACK );
}