summaryrefslogblamecommitdiffstats
path: root/cpukit/score/src/rbtreeinsert.c
blob: a7be44942003c4753e96250f50f72850eff8cf01 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
  
                                         


                                                           
                                         





                   
                                   
 









                                                        

                                                                            
                                                                        
                                             
  


                                                                       
                                                            
 

                                                      



                                                     




















                                                                             
 
                                                                 





                                               
       
 

                                   
 
                                                                               



                                                                             

     
 
                            
                                

 
                            




                             
 

                                            
                                                             

                                
                                                               
                                                  
                                                                      
          
                                                                            
                         

                                            
 
                                                            
                         
 
                                                                  


                                                                          
                                  
                                           

                                     


                                          
          

            

                                                                           

                                              
         
 

              
                                            
       
                            
 
                                     
                                        
   

                           
 
/*
 *  Copyright (c) 2010-2012 Gedare Bloom.
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.org/license/LICENSE.
 */

#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <rtems/score/rbtreeimpl.h>

RTEMS_STATIC_ASSERT(
  sizeof( RBTree_Compare_result ) >= sizeof( intptr_t ),
  RBTree_Compare_result_intptr_t
);

RTEMS_STATIC_ASSERT(
  sizeof( RBTree_Compare_result ) >= sizeof( int32_t ),
  RBTree_Compare_result_int32_t
);

/** @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_Node *grandparent = _RBTree_Parent( parent );

  /* 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 ( parent->color == RBT_RED ) {
    /* The root is black, so the grandparent must exist */
    RBTree_Node *uncle = _RBTree_Sibling( parent, grandparent );

    /*
     * If uncle exists and is red, repaint uncle/parent black and grandparent
     * red.
     */
    if ( uncle != NULL && uncle->color == RBT_RED ) {
      parent->color = RBT_BLACK;
      uncle->color = RBT_BLACK;
      grandparent->color = RBT_RED;
      the_node = grandparent;
      parent = _RBTree_Parent( the_node );
      grandparent = _RBTree_Parent( parent );

      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 );
      }

      parent->color = RBT_BLACK;
      grandparent->color = 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 )
    the_node->color = RBT_BLACK;
}

RBTree_Node *_RBTree_Insert(
  RBTree_Control *the_rbtree,
  RBTree_Node    *the_node,
  RBTree_Compare  compare,
  bool            is_unique
)
{
  RBTree_Node *iter_node = the_rbtree->root;

  if ( !iter_node ) { /* special case: first node inserted */
    the_node->color = RBT_BLACK;
    the_rbtree->root = the_node;
    the_rbtree->first[ 0 ] = the_rbtree->first[ 1 ] = the_node;
    the_node->parent = (RBTree_Node *) the_rbtree;
    the_node->child[ RBT_LEFT ] = the_node->child[ RBT_RIGHT ] = NULL;
  } else {
    /* typical binary search tree insert, descend tree to leaf and insert */
    while ( iter_node ) {
      RBTree_Compare_result compare_result =
        ( *compare )( the_node, iter_node );

      if ( is_unique && _RBTree_Is_equal( compare_result ) )
        return iter_node;

      RBTree_Direction dir = !_RBTree_Is_lesser( compare_result );

      if ( !iter_node->child[ dir ] ) {
        the_node->child[ RBT_LEFT ] = the_node->child[ RBT_RIGHT ] = NULL;
        the_node->color = RBT_RED;
        iter_node->child[ dir ] = the_node;
        the_node->parent = iter_node;
        /* update min/max */
        compare_result = ( *compare )(
          the_node,
          _RBTree_First( the_rbtree, dir )
        );

        if (
          ( dir == RBT_LEFT && _RBTree_Is_lesser( compare_result ) )
            || ( dir == RBT_RIGHT && !_RBTree_Is_lesser( compare_result ) )
        ) {
          the_rbtree->first[ dir ] = the_node;
        }

        break;
      } else {
        iter_node = iter_node->child[ dir ];
      }
    } /* while(iter_node) */

    /* verify red-black properties */
    _RBTree_Validate_insert( the_node );
  }

  return (RBTree_Node *) 0;
}