Ticket #1886: rbtree_duplicate_key3.diff

File rbtree_duplicate_key3.diff, 17.9 KB (added by Petr Benes, on 08/09/11 at 13:03:01)

RBTree duplicate keys possible - version 2

  • cpukit/sapi/include/rtems/rbtree.h

    diff --git a/cpukit/sapi/include/rtems/rbtree.h b/cpukit/sapi/include/rtems/rbtree.h
    index 6a75fc4..42811ca 100644
    a b typedef RBTree_Node rtems_rbtree_node; 
    4343typedef RBTree_Control rtems_rbtree_control;
    4444
    4545/**
     46 * @typedef rtems_rbtree_compare_function
     47 *
     48 * This type defines function pointers for user-provided comparison
     49 * function. The function compares two nodes in order to determine
     50 * the order in a red-black tree.
     51 */
     52typedef RBTree_Compare_function rtems_rbtree_compare_function;
     53
     54/**
     55 * @typedef rtems_rbtree_unique
     56 *
     57 * This enum type defines whether the tree can contain nodes with
     58 * duplicate keys.
     59 */
     60typedef enum {
     61  /** The tree is not unique, insertion of duplicate keys is performed
     62   *  in a FIFO manner. */
     63  RTEMS_RBTREE_DUPLICATE = false,
     64  /** The tree is unique, insertion of duplicate key is refused. */
     65  RTEMS_RBTREE_UNIQUE    = true
     66} rtems_rbtree_unique;
     67
     68/**
    4669 *  @brief RBTree initializer for an empty rbtree with designator @a name.
    4770 */
    4871#define RTEMS_RBTREE_INITIALIZER_EMPTY(name) \
  • cpukit/sapi/inline/rtems/rbtree.inl

    diff --git a/cpukit/sapi/inline/rtems/rbtree.inl b/cpukit/sapi/inline/rtems/rbtree.inl
    index f5b28e4..234ae90 100644
    a b  
    3535 *  @a starting_address.  Each node is of @a node_size bytes.
    3636 */
    3737RTEMS_INLINE_ROUTINE void rtems_rbtree_initialize(
    38   rtems_rbtree_control *the_rbtree,
    39   void                 *compare_function,
    40   void                 *starting_address,
    41   size_t                number_nodes,
    42   size_t                node_size
     38  rtems_rbtree_control          *the_rbtree,
     39  rtems_rbtree_compare_function  compare_function,
     40  void                          *starting_address,
     41  size_t                         number_nodes,
     42  size_t                         node_size,
     43  rtems_rbtree_unique            is_unique
    4344)
    4445{
    4546  _RBTree_Initialize( the_rbtree, compare_function, starting_address,
    46     number_nodes, node_size);
     47    number_nodes, node_size, is_unique);
    4748}
    4849
    4950/**
    RTEMS_INLINE_ROUTINE void rtems_rbtree_initialize( 
    5253 *  This routine initializes @a the_rbtree to contain zero nodes.
    5354 */
    5455RTEMS_INLINE_ROUTINE void rtems_rbtree_initialize_empty(
    55   rtems_rbtree_control *the_rbtree,
    56   void                 *compare_function
     56  rtems_rbtree_control          *the_rbtree,
     57  rtems_rbtree_compare_function  compare_function,
     58  rtems_rbtree_unique            is_unique
    5759)
    5860{
    59   _RBTree_Initialize_empty( the_rbtree, compare_function );
     61  _RBTree_Initialize_empty( the_rbtree, compare_function, is_unique );
    6062}
    6163
    6264/**
    RTEMS_INLINE_ROUTINE bool rtems_rbtree_is_root( 
    257259 *  This function returns a pointer to the node having key equal to the key
    258260 *  of @a the_node if it exists within @a the_rbtree, and NULL if not.
    259261 *  @a the_node has to be made up before a search.
     262 *
     263 *  @note If the tree is not unique and contains duplicate keys, the set
     264 *        of duplicate keys acts as FIFO.
    260265 */
    261266RTEMS_INLINE_ROUTINE rtems_rbtree_node* rtems_rbtree_find(
    262267  rtems_rbtree_control *the_rbtree,
    RTEMS_INLINE_ROUTINE rtems_rbtree_control *rtems_rbtree_find_header( 
    382387 *
    383388 *  This routine inserts @a the_node on @a the_rbtree.
    384389 *  It disables interrupts to ensure the atomicity of the insert operation.
     390 *
     391 *  @retval 0 Successfully inserted.
     392 *  @retval -1 NULL @a the_node.
     393 *  @retval RBTree_Node* if one with equal key to the key of @a the_node exists
     394 *          in an unique @a the_rbtree.
    385395 */
    386 RTEMS_INLINE_ROUTINE void rtems_rbtree_insert(
     396RTEMS_INLINE_ROUTINE rtems_rbtree_node *rtems_rbtree_insert(
    387397  rtems_rbtree_control *the_rbtree,
    388398  rtems_rbtree_node *the_node
    389399)
    390400{
    391   _RBTree_Insert( the_rbtree, the_node );
     401  return _RBTree_Insert( the_rbtree, the_node );
     402}
     403
     404/** @brief Determines whether the tree is unique
     405 */
     406RTEMS_INLINE_ROUTINE rtems_rbtree_unique rtems_rbtree_is_unique(
     407    rtems_rbtree_control *the_rbtree
     408)
     409{
     410  return( _RBTree_Is_unique(the_rbtree) );
    392411}
    393412
    394413#endif
  • cpukit/score/include/rtems/score/rbtree.h

    diff --git a/cpukit/score/include/rtems/score/rbtree.h b/cpukit/score/include/rtems/score/rbtree.h
    index a0c6e2c..e32ec21 100644
    a b typedef enum { 
    100100} RBTree_Direction;
    101101
    102102/**
     103 * This type defines function pointers for user-provided comparison
     104 * function. The function compares two nodes in order to determine
     105 * the order in a red-black tree.
     106 */
     107typedef int (*RBTree_Compare_function)(
     108    RBTree_Node *node1,
     109    RBTree_Node *node2
     110);
     111
     112/**
    103113 *  @struct RBTree_Control
    104114 *
    105115 * This is used to manage a RBT.  A rbtree consists of a tree of zero or more
    typedef struct { 
    126136  /** This points to the min and max nodes of this RBT. */
    127137  RBTree_Node *first[2];
    128138  /**
    129    * Comparison function pointer. Keys to compare has to be found
     139   * Comparison function pointer. Keys to compare have to be found
    130140   * inside to maintain generality. It has to return 1 if first node
    131141   * has higher key than second, -1 if lower, 0 if equal.
    132142   */
    133   int (*compare_function) (RBTree_Node*, RBTree_Node*);
     143  RBTree_Compare_function compare_function;
     144  /** Determines whether the tree accepts duplicate keys. */
     145  bool is_unique;
    134146} RBTree_Control;
    135147
    136148/**
    typedef struct { 
    142154  .root = NULL, \
    143155  .first[0] = NULL, \
    144156  .first[1] = NULL, \
    145   .compare_function = NULL \
     157  .compare_function = NULL, \
     158  .is_unique = 0 \
    146159}
    147160
    148161/**
    RBTree_Node name = RBTREE_NODE_INITIALIZER_EMPTY(name) 
    176189 *  @a starting_address.  Each node is of @a node_size bytes.
    177190 */
    178191void _RBTree_Initialize(
    179   RBTree_Control *the_rbtree,
    180   void           *compare_function,
    181   void           *starting_address,
    182   size_t          number_nodes,
    183   size_t          node_size
     192  RBTree_Control          *the_rbtree,
     193  RBTree_Compare_function  compare_function,
     194  void                    *starting_address,
     195  size_t                   number_nodes,
     196  size_t                   node_size,
     197  bool                     is_unique
    184198);
    185199
    186200/**
    RBTree_Control *_RBTree_Find_header( 
    247261 *
    248262 *  @retval 0 Successfully inserted.
    249263 *  @retval -1 NULL @a the_node.
    250  *  @retval RBTree_Node* if one with equal value to @a the_node->value exists
    251  *          in @a the_rbtree.
     264 *  @retval RBTree_Node* if one with equal value to @a the_node 's key exists
     265 *          in an unique @a the_rbtree.
    252266 *
    253267 *  @note It does NOT disable interrupts to ensure the atomicity
    254268 *        of the extract operation.
    RBTree_Node *_RBTree_Insert_unprotected( 
    263277 *
    264278 *  This routine inserts @a the_node on the tree @a the_rbtree.
    265279 *
     280 *  @retval 0 Successfully inserted.
     281 *  @retval -1 NULL @a the_node.
     282 *  @retval RBTree_Node* if one with equal value to @a the_node 's key exists
     283 *          in an unique @a the_rbtree.
     284 *
    266285 *  @note It disables interrupts to ensure the atomicity
    267286 *  of the extract operation.
    268287 */
    269 void _RBTree_Insert(
     288RBTree_Node *_RBTree_Insert(
    270289  RBTree_Control *the_rbtree,
    271290  RBTree_Node *the_node
    272291);
  • cpukit/score/inline/rtems/score/rbtree.inl

    diff --git a/cpukit/score/inline/rtems/score/rbtree.inl b/cpukit/score/inline/rtems/score/rbtree.inl
    index 8e1c66e..e73a80b 100644
    a b RTEMS_INLINE_ROUTINE bool _RBTree_Is_root( 
    235235 *  This routine initializes @a the_rbtree to contain zero nodes.
    236236 */
    237237RTEMS_INLINE_ROUTINE void _RBTree_Initialize_empty(
    238     RBTree_Control *the_rbtree,
    239     void           *compare_function
     238    RBTree_Control          *the_rbtree,
     239    RBTree_Compare_function  compare_function,
     240    bool                     is_unique
    240241    )
    241242{
    242243  the_rbtree->permanent_null   = NULL;
    RTEMS_INLINE_ROUTINE void _RBTree_Initialize_empty( 
    244245  the_rbtree->first[0]         = NULL;
    245246  the_rbtree->first[1]         = NULL;
    246247  the_rbtree->compare_function = compare_function;
     248  the_rbtree->is_unique        = is_unique;
    247249}
    248250
    249251/** @brief Return a pointer to node's grandparent
    RTEMS_INLINE_ROUTINE RBTree_Control *_RBTree_Find_header_unprotected( 
    317319 *  This function returns a pointer to the node in @a the_rbtree
    318320 *  having key equal to key of  @a the_node if it exists,
    319321 *  and NULL if not. @a the_node has to be made up before a search.
     322 *
     323 *  @note If the tree is not unique and contains duplicate keys, the set
     324 *        of duplicate keys acts as FIFO.
    320325 */
    321326RTEMS_INLINE_ROUTINE RBTree_Node *_RBTree_Find_unprotected(
    322327    RBTree_Control *the_rbtree,
    RTEMS_INLINE_ROUTINE RBTree_Node *_RBTree_Find_unprotected( 
    324329    )
    325330{
    326331  RBTree_Node* iter_node = the_rbtree->root;
     332  RBTree_Node* found = NULL;
    327333  int compare_result;
    328334  while (iter_node) {
    329335    compare_result = the_rbtree->compare_function(the_node, iter_node);
    330336    if (compare_result == 0) {
    331         return(iter_node);
     337      found = iter_node;
     338      if ( the_rbtree->is_unique )
     339        break;
    332340    }
    333341
    334     RBTree_Direction dir = (compare_result != -1);
     342    RBTree_Direction dir = (compare_result == 1);
    335343    iter_node = iter_node->child[dir];
    336344  } /* while(iter_node) */
    337345
    338   return 0;
     346  return found;
    339347}
    340348
    341349/** @brief Find the nodes in-order predecessor
    RTEMS_INLINE_ROUTINE void _RBTree_Rotate( 
    428436  RBTree_Node *c;
    429437  if (the_node == NULL) return;
    430438  if (the_node->child[(1-dir)] == NULL) return;
    431  
    432439
    433440  c = the_node->child[(1-dir)];
    434441  the_node->child[(1-dir)] = c->child[dir];
    RTEMS_INLINE_ROUTINE void _RBTree_Rotate( 
    443450  c->parent = the_node->parent;
    444451  the_node->parent = c;
    445452}
     453
     454/** @brief Determines whether the tree is unique
     455 */
     456RTEMS_INLINE_ROUTINE bool _RBTree_Is_unique(
     457    RBTree_Control *the_rbtree
     458)
     459{
     460  return( the_rbtree && the_rbtree->is_unique );
     461}
    446462/**@}*/
    447463
    448464#endif
  • cpukit/score/src/rbtree.c

    diff --git a/cpukit/score/src/rbtree.c b/cpukit/score/src/rbtree.c
    index cc20361..cc8accf 100644
    a b  
    3232 */
    3333
    3434void _RBTree_Initialize(
    35   RBTree_Control *the_rbtree,
    36   void           *compare_function,
    37   void           *starting_address,
    38   size_t         number_nodes,
    39   size_t         node_size
     35  RBTree_Control          *the_rbtree,
     36  RBTree_Compare_function  compare_function,
     37  void                    *starting_address,
     38  size_t                   number_nodes,
     39  size_t                   node_size,
     40  bool                     is_unique
    4041)
    4142{
    4243  size_t      count;
    void _RBTree_Initialize( 
    4647  if (!the_rbtree) return;
    4748
    4849  /* could do sanity checks here */
    49   _RBTree_Initialize_empty(the_rbtree, compare_function);
     50  _RBTree_Initialize_empty(the_rbtree, compare_function, is_unique);
    5051
    5152  count = number_nodes;
    5253  next  = starting_address;
  • cpukit/score/src/rbtreeinsert.c

    diff --git a/cpukit/score/src/rbtreeinsert.c b/cpukit/score/src/rbtreeinsert.c
    index c2c60ed..7ae8d71 100644
    a b void _RBTree_Validate_insert_unprotected( 
    7272 *  @retval 0 Successfully inserted.
    7373 *  @retval -1 NULL @a the_node.
    7474 *  @retval RBTree_Node* if one with equal key to the key of @a the_node exists
    75  *          in @a the_rbtree.
     75 *          in an unique @a the_rbtree.
    7676 *
    7777 *  @note It does NOT disable interrupts to ensure the atomicity
    7878 *        of the extract operation.
    RBTree_Node *_RBTree_Insert_unprotected( 
    9797    /* typical binary search tree insert, descend tree to leaf and insert */
    9898    while (iter_node) {
    9999      compare_result = the_rbtree->compare_function(the_node, iter_node);
    100       if ( !compare_result ) return iter_node;
     100      if ( the_rbtree->is_unique && !compare_result )
     101        return iter_node;
    101102      RBTree_Direction dir = (compare_result != -1);
    102103      if (!iter_node->child[dir]) {
    103104        the_node->child[RBT_LEFT] = the_node->child[RBT_RIGHT] = NULL;
    RBTree_Node *_RBTree_Insert_unprotected( 
    138139 *    only case
    139140 */
    140141
    141 void _RBTree_Insert(
     142RBTree_Node *_RBTree_Insert(
    142143  RBTree_Control *tree,
    143144  RBTree_Node *node
    144145)
    void _RBTree_Insert( 
    146147  ISR_Level level;
    147148
    148149  _ISR_Disable( level );
    149     _RBTree_Insert_unprotected( tree, node );
     150    return _RBTree_Insert_unprotected( tree, node );
    150151  _ISR_Enable( level );
    151152}
  • testsuites/sptests/sprbtree01/init.c

    diff --git a/testsuites/sptests/sprbtree01/init.c b/testsuites/sptests/sprbtree01/init.c
    index df83d41..f9f0d22 100644
    a b rtems_task Init( 
    100100  puts( "\n\n*** TEST OF RTEMS RBTREE API ***" );
    101101
    102102  puts( "Init - Initialize rbtree empty" );
    103   rtems_rbtree_initialize_empty( &rbtree1, &test_compare_function );
    104  
     103  rtems_rbtree_initialize_empty( &rbtree1, &test_compare_function,
     104                                 RTEMS_RBTREE_UNIQUE );
     105
     106  if ( !rtems_rbtree_is_unique( &rbtree1 ) )
     107    puts( "INIT - FAILED IS UNIQUE CHECK" );
     108  if ( rtems_rbtree_is_unique( NULL ) )
     109    puts( "INIT - FAILED IS UNIQUE CHECK" );
     110
    105111  /* verify that the rbtree insert work */
    106112  puts( "INIT - Verify rtems_rbtree_insert with two nodes" );
    107113  node1.id = 1;
    rtems_task Init( 
    111117  rtems_rbtree_insert( &rbtree1, &node1.Node );
    112118  rtems_rbtree_insert( &rbtree1, &node2.Node );
    113119
    114   p = _RBTree_Insert_unprotected( &rbtree1, NULL );
     120  p = rtems_rbtree_insert( &rbtree1, NULL );
    115121  if (p != (void *)(-1))
    116122    puts( "INIT - FAILED NULL NODE INSERT" );
    117123
    rtems_task Init( 
    149155  puts("INIT - Verify rtems_rbtree_insert with the same value twice");
    150156  node2.key = node1.key;
    151157  rtems_rbtree_insert(&rbtree1, &node1.Node);
    152   rtems_rbtree_insert(&rbtree1, &node2.Node);
     158  p = rtems_rbtree_insert(&rbtree1, &node2.Node);
     159
     160  if (p != &node1.Node)
     161    puts( "INIT - FAILED DUPLICATE INSERT" );
     162
    153163  for ( p = rtems_rbtree_get_min(&rbtree1), id = 1 ; p ;
    154164      p = rtems_rbtree_get_min(&rbtree1) , id++ ) {
    155165    test_node *t = rtems_rbtree_container_of(p,test_node,Node);
    rtems_task Init( 
    527537    node_array[i].key = i;
    528538  }
    529539  rtems_rbtree_initialize( &rbtree1, &test_compare_function,
    530                            &node_array[0].Node, 100, sizeof(test_node));
     540                           &node_array[0].Node, 100,
     541                           sizeof(test_node), RTEMS_RBTREE_UNIQUE );
    531542
    532543  puts( "INIT - Removing 100 nodes" );
    533544
    rtems_task Init( 
    553564    rtems_test_exit(0);
    554565  }
    555566
     567  /* Initialize the tree for duplicate keys */
     568  puts( "Init - Initialize duplicate rbtree empty" );
     569  rtems_rbtree_initialize_empty( &rbtree1, &test_compare_function,
     570                                 RTEMS_RBTREE_DUPLICATE );
     571
     572  if ( rtems_rbtree_is_unique( &rbtree1 ) )
     573    puts( "INIT - FAILED IS UNIQUE CHECK" );
     574  if ( rtems_rbtree_is_unique( NULL ) )
     575    puts( "INIT - FAILED IS UNIQUE CHECK" );
     576
     577  puts( "INIT - Verify rtems_rbtree_insert with 100 nodes value [0,99]" );
     578  for (i = 0; i < 100; i++) {
     579    node_array[i].id = i;
     580    node_array[i].key = i%5;
     581    rtems_rbtree_insert( &rbtree1, &node_array[i].Node );
     582
     583    if (!rb_assert(rbtree1.root) )
     584      puts( "INIT - FAILED TREE CHECK" );
     585  }
     586
     587  puts( "INIT - Verify rtems_rbtree_find in a duplicate tree" );
     588  search_node.key = 2;
     589  p = rtems_rbtree_find(&rbtree1, &search_node.Node);
     590  if(rtems_rbtree_container_of(p,test_node,Node)->id != 2) {
     591    puts ("INIT - ERROR ON RBTREE ID MISMATCH");
     592    rtems_test_exit(0);
     593  }
     594
     595  puts( "INIT - Removing 100 nodes" );
     596
     597  for ( p = rtems_rbtree_get_min(&rbtree1), id = 0 ; p ;
     598      p = rtems_rbtree_get_min(&rbtree1) , id++ ) {
     599    test_node *t = rtems_rbtree_container_of(p,test_node,Node);
     600    if ( id > 99 ) {
     601      puts( "INIT - TOO MANY NODES ON RBTREE" );
     602      rtems_test_exit(0);
     603    }
     604    if ( t->id != ( ((id*5)%100) + (id/20) ) ) {
     605      puts( "INIT - ERROR ON RBTREE ID MISMATCH" );
     606      rtems_test_exit(0);
     607    }
     608
     609    if (!rb_assert(rbtree1.root) )
     610      puts( "INIT - FAILED TREE CHECK" );
     611  }
     612
     613  if(!rtems_rbtree_is_empty(&rbtree1)) {
     614    puts( "INIT - TREE NOT EMPTY" );
     615    rtems_test_exit(0);
     616  }
     617
     618  puts( "INIT - Verify rtems_rbtree_insert with 100 nodes value [99,0]" );
     619  for (i = 0; i < 100; i++) {
     620    node_array[i].id = 99-i;
     621    node_array[i].key = (99-i)%5;
     622    rtems_rbtree_insert( &rbtree1, &node_array[i].Node );
     623
     624    if (!rb_assert(rbtree1.root) )
     625      puts( "INIT - FAILED TREE CHECK" );
     626  }
     627
     628  puts( "INIT - Verify rtems_rbtree_find in a duplicate tree" );
     629  search_node.key = 2;
     630  p = rtems_rbtree_find(&rbtree1, &search_node.Node);
     631  if(rtems_rbtree_container_of(p,test_node,Node)->id != 97) {
     632    puts ("INIT - ERROR ON RBTREE ID MISMATCH");
     633    rtems_test_exit(0);
     634  }
     635
     636  puts( "INIT - Removing 100 nodes" );
     637
     638  for ( p = rtems_rbtree_get_min(&rbtree1), id = 0 ; p ;
     639      p = rtems_rbtree_get_min(&rbtree1) , id++ ) {
     640    test_node *t = rtems_rbtree_container_of(p,test_node,Node);
     641    if ( id > 99 ) {
     642      puts( "INIT - TOO MANY NODES ON RBTREE" );
     643      rtems_test_exit(0);
     644    }
     645    if ( t->id != ( (((99-id)*5)%100) + (id/20) ) ) {
     646      puts( "INIT - ERROR ON RBTREE ID MISMATCH" );
     647      rtems_test_exit(0);
     648    }
     649
     650    if (!rb_assert(rbtree1.root) )
     651      puts( "INIT - FAILED TREE CHECK" );
     652  }
     653
     654  if(!rtems_rbtree_is_empty(&rbtree1)) {
     655    puts( "INIT - TREE NOT EMPTY" );
     656    rtems_test_exit(0);
     657  }
     658
    556659  puts( "*** END OF RTEMS RBTREE API TEST ***" );
    557660  rtems_test_exit(0);
    558661}
  • testsuites/sptests/sprbtree01/sprbtree01.scn

    diff --git a/testsuites/sptests/sprbtree01/sprbtree01.scn b/testsuites/sptests/sprbtree01/sprbtree01.scn
    index 3060a96..0bf2007 100644
    a b INIT - Insert 20 random numbers 
    2424INIT - Removing 20 nodes
    2525INIT - Verify rtems_rbtree_initialize with 100 nodes value [0,99]
    2626INIT - Removing 100 nodes
     27Init - Initialize duplicate rbtree empty
     28INIT - Verify rtems_rbtree_insert with 100 nodes value [0,99]
     29INIT - Verify rtems_rbtree_find in a duplicate tree
     30INIT - Removing 100 nodes
     31INIT - Verify rtems_rbtree_insert with 100 nodes value [99,0]
     32INIT - Verify rtems_rbtree_find in a duplicate tree
     33INIT - Removing 100 nodes
    2734*** END OF RTEMS RBTREE API TEST ***