1 |
/* |
2 |
** Copyright (C) 2003 by Kevin L. Mitchell <klmitch@mit.edu> |
3 |
** |
4 |
** This library is free software; you can redistribute it and/or |
5 |
** modify it under the terms of the GNU Library General Public |
6 |
** License as published by the Free Software Foundation; either |
7 |
** version 2 of the License, or (at your option) any later version. |
8 |
** |
9 |
** This library is distributed in the hope that it will be useful, |
10 |
** but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 |
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 |
** Library General Public License for more details. |
13 |
** |
14 |
** You should have received a copy of the GNU Library General Public |
15 |
** License along with this library; if not, write to the Free |
16 |
** Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
17 |
** MA 02111-1307, USA |
18 |
** |
19 |
** @(#)$Id: rt_add.c,v 1.1 2003/06/28 18:48:21 klmitch Exp $ |
20 |
*/ |
21 |
#include "dbprim.h" |
22 |
#include "dbprim_int.h" |
23 |
|
24 |
RCSTAG("@(#)$Id: rt_add.c,v 1.1 2003/06/28 18:48:21 klmitch Exp $"); |
25 |
|
26 |
/* Locate the uncle of the given node */ |
27 |
#define uncle(node) (rn_isleft((node)->rn_parent) ? \ |
28 |
(node)->rn_parent->rn_parent->rn_right : \ |
29 |
(node)->rn_parent->rn_parent->rn_left) |
30 |
|
31 |
/* Flip the color of the given node */ |
32 |
#define flip(node) ((node)->rn_color = \ |
33 |
((node)->rn_color == RB_COLOR_BLACK) ? \ |
34 |
RB_COLOR_RED : RB_COLOR_BLACK) |
35 |
|
36 |
/** \ingroup dbprim_rbtree |
37 |
* \brief Add a node to a red-black tree. |
38 |
* |
39 |
* This function adds a node to a red-black tree. |
40 |
* |
41 |
* \param tree A pointer to a #rb_tree_t. |
42 |
* \param node A pointer to a #rb_node_t to be added to the tree. |
43 |
* \param key A pointer to a #db_key_t containing the key for the |
44 |
* node. |
45 |
* |
46 |
* \retval DB_ERR_BADARGS An invalid argument was given. |
47 |
* \retval DB_ERR_BUSY The node is already in a tree. |
48 |
* \retval DB_ERR_FROZEN The tree is currently frozen. |
49 |
* \retval DB_ERR_DUPLICATE The entry is a duplicate of an |
50 |
* existing node. |
51 |
*/ |
52 |
unsigned long |
53 |
rt_add(rb_tree_t *tree, rb_node_t *node, db_key_t *key) |
54 |
{ |
55 |
initialize_dbpr_error_table(); /* initialize error table */ |
56 |
|
57 |
if (!rt_verify(tree) || !rn_verify(node) || !key) /* verify arguments */ |
58 |
return DB_ERR_BADARGS; |
59 |
|
60 |
if (node->rn_tree) /* it's already in a tree... */ |
61 |
return DB_ERR_BUSY; |
62 |
|
63 |
if (tree->rt_flags & RBT_FLAG_FREEZE) /* don't add to frozen trees */ |
64 |
return DB_ERR_FROZEN; |
65 |
|
66 |
if (_rb_locate(tree, node, key) != node) /* add it to the tree... */ |
67 |
return DB_ERR_DUPLICATE; /* We don't allow duplication! */ |
68 |
|
69 |
/* OK, node has been added, now let's rebalance the tree... */ |
70 |
while (!rn_isblack(node) && !rn_isblack(node->rn_parent)) |
71 |
if (rn_isred(uncle(node))) { |
72 |
flip(node->rn_parent); /* Flip the colors of parent and grandparent */ |
73 |
flip(node->rn_parent->rn_parent); |
74 |
flip(uncle(node)); /* and flip the color of the uncle */ |
75 |
node = node->rn_parent->rn_parent; /* grandparent need balancing? */ |
76 |
} else if ((rn_isleft(node->rn_parent) && rn_isright(node)) || |
77 |
(rn_isright(node->rn_parent) && rn_isleft(node))) { |
78 |
flip(node); /* flip the colors that need flipping... */ |
79 |
flip(node->rn_parent->rn_parent); |
80 |
_rb_rotate(tree, node); /* rotate the node up two levels */ |
81 |
_rb_rotate(tree, node); |
82 |
} else { |
83 |
flip(node->rn_parent); /* flip the colors that need flipping... */ |
84 |
flip(node->rn_parent->rn_parent); |
85 |
_rb_rotate(tree, node->rn_parent); /* move the parent up a level */ |
86 |
node = node->rn_parent; /* new parent need balancing? */ |
87 |
} |
88 |
|
89 |
/* Make sure the root node is black */ |
90 |
tree->rt_root->rn_color = RB_COLOR_BLACK; |
91 |
|
92 |
return 0; |
93 |
} |