source: rtems/cpukit/score/src/rbtreeextract.c @ 5472ad41

4.115
Last change on this file since 5472ad41 was d188381a, checked in by Joel Sherrill <joel.sherrill@…>, on 08/02/11 at 13:37:21

2011-08-02 Petr Benes <benesp16@…>

PR 1861/cpukit

  • score/src/rbtreeextract.c: Remove redundant code.
  • Property mode set to 100644
File size: 7.9 KB
Line 
1/*
2 *  Copyright (c) 2010 Gedare Bloom.
3 *
4 *  The license and distribution terms for this file may be
5 *  found in the file LICENSE in this distribution or at
6 *  http://www.rtems.com/license/LICENSE.
7 *
8 *  $Id$
9 */
10
11#if HAVE_CONFIG_H
12#include "config.h"
13#endif
14
15#include <rtems/system.h>
16#include <rtems/score/address.h>
17#include <rtems/score/rbtree.h>
18#include <rtems/score/isr.h>
19
20/** @brief  Validate and fix-up tree properties after deleting a node
21 *
22 *  This routine is called on a black node, @a the_node, after its deletion.
23 *  This function maintains the properties of the red-black tree.
24 *
25 *  @note It does NOT disable interrupts to ensure the atomicity
26 *        of the extract operation.
27 */
28void _RBTree_Extract_validate_unprotected(
29    RBTree_Node *the_node
30    )
31{
32  RBTree_Node *parent, *sibling;
33  RBTree_Direction dir;
34
35  parent = the_node->parent;
36  if(!parent->parent) return;
37
38  sibling = _RBTree_Sibling(the_node);
39
40  /* continue to correct tree as long as the_node is black and not the root */
41  while (!_RBTree_Is_red(the_node) && parent->parent) {
42
43    /* if sibling is red, switch parent (black) and sibling colors,
44     * then rotate parent left, making the sibling be the_node's grandparent.
45     * Now the_node has a black sibling and red parent. After rotation,
46     * update sibling pointer.
47     */
48    if (_RBTree_Is_red(sibling)) {
49      parent->color = RBT_RED;
50      sibling->color = RBT_BLACK;
51      dir = the_node != parent->child[0];
52      _RBTree_Rotate(parent, dir);
53      sibling = parent->child[!dir];
54    }
55
56    /* sibling is black, see if both of its children are also black. */
57    if (!_RBTree_Is_red(sibling->child[RBT_RIGHT]) &&
58        !_RBTree_Is_red(sibling->child[RBT_LEFT])) {
59        sibling->color = RBT_RED;
60        if (_RBTree_Is_red(parent)) {
61          parent->color = RBT_BLACK;
62          break;
63        }
64        the_node = parent; /* done if parent is red */
65        parent = the_node->parent;
66        sibling = _RBTree_Sibling(the_node);
67    } else {
68      /* at least one of sibling's children is red. we now proceed in two
69       * cases, either the_node is to the left or the right of the parent.
70       * In both cases, first check if one of sibling's children is black,
71       * and if so rotate in the proper direction and update sibling pointer.
72       * Then switch the sibling and parent colors, and rotate through parent.
73       */
74      dir = the_node != parent->child[0];
75      if (!_RBTree_Is_red(sibling->child[!dir])) {
76        sibling->color = RBT_RED;
77        sibling->child[dir]->color = RBT_BLACK;
78        _RBTree_Rotate(sibling, !dir);
79        sibling = parent->child[!dir];
80      }
81      sibling->color = parent->color;
82      parent->color = RBT_BLACK;
83      sibling->child[!dir]->color = RBT_BLACK;
84      _RBTree_Rotate(parent, dir);
85      break; /* done */
86    }
87  } /* while */
88  if(!the_node->parent->parent) the_node->color = RBT_BLACK;
89}
90
91/** @brief Extract a Node (unprotected)
92 *
93 *  This routine extracts (removes) @a the_node from @a the_rbtree.
94 *
95 *  @note It does NOT disable interrupts to ensure the atomicity
96 *        of the extract operation.
97 */
98void _RBTree_Extract_unprotected(
99    RBTree_Control *the_rbtree,
100    RBTree_Node *the_node
101    )
102{
103  RBTree_Node *leaf, *target;
104  RBTree_Color victim_color;
105  RBTree_Direction dir;
106
107  if (!the_node) return;
108
109  /* check if min needs to be updated */
110  if (the_node == the_rbtree->first[RBT_LEFT]) {
111    if (the_node->child[RBT_RIGHT])
112      the_rbtree->first[RBT_LEFT] = the_node->child[RBT_RIGHT];
113    else {
114      the_rbtree->first[RBT_LEFT] = the_node->parent;
115      if(_RBTree_Are_nodes_equal((RBTree_Node *)the_rbtree,
116            the_rbtree->first[RBT_LEFT]))
117        the_rbtree->first[RBT_LEFT] = NULL;
118    }
119  }
120  /* check if max needs to be updated: note, min can equal max (1 element) */
121  if (the_node == the_rbtree->first[RBT_RIGHT]) {
122    if (the_node->child[RBT_LEFT])
123      the_rbtree->first[RBT_RIGHT] = the_node->child[RBT_LEFT];
124    else {
125      the_rbtree->first[RBT_RIGHT] = the_node->parent;
126      if(_RBTree_Are_nodes_equal((RBTree_Node *)the_rbtree,
127            the_rbtree->first[RBT_RIGHT]))
128        the_rbtree->first[RBT_RIGHT] = NULL;
129    }
130  }
131
132  /* if the_node has at most one non-null child then it is safe to proceed
133   * check if both children are non-null, if so then we must find a target node
134   * either max in node->child[RBT_LEFT] or min in node->child[RBT_RIGHT],
135   * and replace the_node with the target node. This maintains the binary
136   * search tree property, but may violate the red-black properties.
137   */
138
139  if (the_node->child[RBT_LEFT] && the_node->child[RBT_RIGHT]) {
140    target = the_node->child[RBT_LEFT]; /* find max in node->child[RBT_LEFT] */
141    while (target->child[RBT_RIGHT]) target = target->child[RBT_RIGHT];
142
143    /* if the target node has a child, need to move it up the tree into
144     * target's position (target is the right child of target->parent)
145     * when target vacates it. if there is no child, then target->parent
146     * should become NULL. This may cause the coloring to be violated.
147     * For now we store the color of the node being deleted in victim_color.
148     */
149    leaf = target->child[RBT_LEFT];
150    if(leaf) {
151      leaf->parent = target->parent;
152    } else {
153      /* fix the tree here if the child is a null leaf. */
154      _RBTree_Extract_validate_unprotected(target);
155    }
156    victim_color = target->color;
157    dir = target != target->parent->child[0];
158    target->parent->child[dir] = leaf;
159
160    /* now replace the_node with target */
161    dir = the_node != the_node->parent->child[0];
162    the_node->parent->child[dir] = target;
163
164    /* set target's new children to the original node's children */
165    target->child[RBT_RIGHT] = the_node->child[RBT_RIGHT];
166    if (the_node->child[RBT_RIGHT])
167      the_node->child[RBT_RIGHT]->parent = target;
168    target->child[RBT_LEFT] = the_node->child[RBT_LEFT];
169    if (the_node->child[RBT_LEFT])
170      the_node->child[RBT_LEFT]->parent = target;
171
172    /* finally, update the parent node and recolor. target has completely
173     * replaced the_node, and target's child has moved up the tree if needed.
174     * the_node is no longer part of the tree, although it has valid pointers
175     * still.
176     */
177    target->parent = the_node->parent;
178    target->color = the_node->color;
179  } else {
180    /* the_node has at most 1 non-null child. Move the child in to
181     * the_node's location in the tree. This may cause the coloring to be
182     * violated. We will fix it later.
183     * For now we store the color of the node being deleted in victim_color.
184     */
185    leaf = the_node->child[RBT_LEFT] ?
186              the_node->child[RBT_LEFT] : the_node->child[RBT_RIGHT];
187    if( leaf ) {
188      leaf->parent = the_node->parent;
189    } else {
190      /* fix the tree here if the child is a null leaf. */
191      _RBTree_Extract_validate_unprotected(the_node);
192    }
193    victim_color = the_node->color;
194
195    /* remove the_node from the tree */
196    dir = the_node != the_node->parent->child[0];
197    the_node->parent->child[dir] = leaf;
198  }
199
200  /* fix coloring. leaf has moved up the tree. The color of the deleted
201   * node is in victim_color. There are two cases:
202   *   1. Deleted a red node, its child must be black. Nothing must be done.
203   *   2. Deleted a black node, its child must be red. Paint child black.
204   */
205  if (victim_color == RBT_BLACK) { /* eliminate case 1 */
206    if (leaf) {
207      leaf->color = RBT_BLACK; /* case 2 */
208    }
209  }
210
211  /* Wipe the_node */
212  _RBTree_Set_off_rbtree(the_node);
213
214  /* set root to black, if it exists */
215  if (the_rbtree->root) the_rbtree->root->color = RBT_BLACK;
216}
217
218
219/*
220 *  _RBTree_Extract
221 *
222 *  This kernel routine deletes the given node from a rbtree.
223 *
224 *  Input parameters:
225 *    node - pointer to node in rbtree to be deleted
226 *
227 *  Output parameters:  NONE
228 *
229 *  INTERRUPT LATENCY:
230 *    only case
231 */
232
233void _RBTree_Extract(
234  RBTree_Control *the_rbtree,
235  RBTree_Node *the_node
236)
237{
238  ISR_Level level;
239
240  _ISR_Disable( level );
241    _RBTree_Extract_unprotected( the_rbtree, the_node );
242  _ISR_Enable( level );
243}
Note: See TracBrowser for help on using the repository browser.