libtrbase  1.0.2
Web server and task management solution.
tree_macros.h
Go to the documentation of this file.
1 /**
2  * \file
3  *
4  * \author Georg Hopp
5  *
6  * \copyright
7  * Copyright © 2014 Georg Hopp
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #ifndef __TR_TREE_MACROS_H__
24 #define __TR_TREE_MACROS_H__
25 
26 #include "trbase.h"
27 
28 #define TR_TREE_RIGHT(node) (NULL!=(node)?(node)->right:NULL)
29 #define TR_TREE_LEFT(node) (NULL!=(node)?(node)->left:NULL)
30 #define TR_TREE_PARENT(node) (NULL!=(node)?(node)->parent:NULL)
31 
32 #define TR_TREE_CHILD(node) \
33  (NULL==TR_TREE_RIGHT((node))?TR_TREE_LEFT((node)):TR_TREE_RIGHT((node)))
34 
35 #define TR_TREE_SIBLING(node) \
36  (NULL!=(node)->parent? \
37  ((node)==(node)->parent->left? \
38  (node)->parent->right: \
39  (node)->parent->left): \
40  NULL)
41 
42 #define TR_TREE_UNCLE(node) \
43  ((node)->parent == (node)->parent->parent->left \
44  ? (node)->parent->parent->right \
45  : (node)->parent->parent->left)
46 
47 #define TR_TREE_REPLACE_NODE(root, node1, node2) \
48  if (NULL != (node1)->parent) { \
49  if ((node1) == (node1)->parent->left) { \
50  (node1)->parent->left = (node2); \
51  } else { \
52  (node1)->parent->right = (node2); \
53  } \
54  } else { \
55  *(root) = (node2); \
56  } \
57  if (NULL != (node2)) { \
58  (node2)->parent = (node1)->parent; \
59  }
60 
61 #define TR_TREE_ROT_RCLD_right(node) ((node)->left)
62 #define TR_TREE_ROT_RCLD_left(node) ((node)->right)
63 
64 #define TR_TREE_ROTATE(lr, root, node) \
65  if (NULL != (node)) { \
66  void * stPar = node->parent; \
67  void * relCld = TR_TREE_ROT_RCLD_##lr(node); \
68  void * relCCld = TR_TREE_ROT_RCLD_##lr(node)->lr; \
69  void * nLeft_p = &TR_TREE_ROT_RCLD_##lr(node); \
70  if (NULL != relCCld) { \
71  TR_TREE_ROT_RCLD_##lr(node)->lr->parent = node; \
72  } \
73  TR_TREE_ROT_RCLD_##lr(node)->lr = node; \
74  if (NULL != node->parent) { \
75  if (node->parent->left == node) { \
76  node->parent->left = relCld; \
77  } else { \
78  node->parent->right = relCld; \
79  } \
80  } else { \
81  *(root) = relCld; \
82  } \
83  node->parent = relCld; \
84  TR_TREE_ROT_RCLD_##lr(node)->parent = stPar; \
85  *(void**)nLeft_p = relCCld; \
86  }
87 
88 typedef enum {rbBlack=1, rbRed=2} TR_rbColor;
89 
90 #define TR_TREE_NODE_BLACK(node) \
91  (NULL == (node) || rbBlack == (node)->color)
92 #define TR_TREE_NODE_RED(node) \
93  (NULL == (node) || rbRed == (node)->color)
94 #define TR_TREE_NODE_STRICT_BLACK(node) \
95  (NULL != (node) && rbBlack == (node)->color)
96 #define TR_TREE_NODE_STRICT_RED(node) \
97  (NULL != (node) && rbRed == (node)->color)
98 
99 #define TR_TREE_INORDER_SUCC(node, succ) \
100  succ = (node)->right; \
101  while (NULL != succ->left) { \
102  succ = succ->left; \
103  }
104 
105 /*
106  * Find data in a tree.
107  * Attention: This will change node, so normally you need to copy
108  * it before using this macro.
109  * Also be aware that found needs to be a valid lvalue and an integer.
110  */
111 #define TR_TREE_FIND(node, search, found, comp) \
112  (found) = -1; \
113  if ((node)) { \
114  while (1) { \
115  (found) = (comp)((node)->data, (search)); \
116  if (0 != (found)) { \
117  if (0 < (found)) { \
118  if (! (node)->left) break; \
119  (node) = (node)->left; \
120  } else { \
121  if (! (node)->right) break; \
122  (node) = (node)->right; \
123  } \
124  } else { \
125  break; \
126  } \
127  } \
128  }
129 
130 #define TR_TREE_BALANCE_DELETE_CASE1(node) \
131  if (NULL == (node)->parent) { \
132  break; \
133  }
134 
135 #define TR_TREE_BALANCE_DELETE_CASE2(root, node, sibling) \
136  if (NULL != (sibling) && rbRed == (sibling)->color) { \
137  (node)->parent->color = rbRed; \
138  (sibling)->color = rbBlack; \
139  if (NULL != (node)->parent->right \
140  && (node) != (node)->parent->right) { \
141  TR_TREE_ROTATE(left, (root), (node)->parent); \
142  } else { \
143  TR_TREE_ROTATE(right, (root), (node)->parent); \
144  } \
145  (sibling) = TR_TREE_SIBLING((node)); \
146  }
147 
148 #define TR_TREE_BALANCE_DELETE_CASE34(root, node, sibling) \
149  if (NULL == (sibling) \
150  || (rbBlack == (sibling)->color \
151  && TR_TREE_NODE_BLACK((sibling)->left) \
152  && TR_TREE_NODE_BLACK((sibling)->right))) { \
153  if (NULL != (sibling)) { \
154  (sibling)->color = rbRed; \
155  } \
156  if (rbBlack == (node)->parent->color) { \
157  (node) = (node)->parent; \
158  continue; \
159  } else { \
160  (node)->parent->color = rbBlack; \
161  break; \
162  } \
163  }
164 
165 /*
166  * this if statement is trivial,
167  * due to case 2 (even though case 2 changed the sibling to a
168  * sibling's child,
169  * the sibling's child can't be red, since no red parent can
170  * have a red child).
171  *
172  * the following statements just force the red to be on the
173  * left of the left of the parent,
174  * or right of the right, so case 6 will rotate correctly.
175  */
176 #define TR_TREE_BALANCE_DELETE_CASE5(root, node, sibling) \
177  if (NULL != (sibling) && rbBlack == (sibling)->color) { \
178  if ((node) == (node)->parent->left \
179  && TR_TREE_NODE_BLACK((sibling)->right) \
180  && TR_TREE_NODE_STRICT_RED((sibling)->left)) { \
181  (sibling)->color = rbRed; \
182  (sibling)->left->color = rbBlack; \
183  TR_TREE_ROTATE(right, (root), (sibling)); \
184  } else if ((node) == (node)->parent->right \
185  && TR_TREE_NODE_BLACK((sibling)->left) \
186  && TR_TREE_NODE_STRICT_RED((sibling)->right)) { \
187  (sibling)->color = rbRed; \
188  (sibling)->right->color = rbBlack; \
189  TR_TREE_ROTATE(left, (root), (sibling)); \
190  } \
191  (sibling) = TR_TREE_SIBLING((node)); \
192  }
193 
194 #define TR_TREE_BALANCE_DELETE_CASE6(root, node, sibling) \
195  if (NULL != (sibling)) { \
196  (sibling)->color = (node)->parent->color; \
197  } \
198  if (NULL != (node) && NULL != (node)->parent) { \
199  (node)->parent->color = rbBlack; \
200  if (NULL != (node)->parent->right \
201  && (node) != (node)->parent->right) { \
202  if (NULL != (sibling)->right) { \
203  (sibling)->right->color = rbBlack; \
204  } \
205  TR_TREE_ROTATE(left, (root), (node)->parent); \
206  } else { \
207  if (NULL != (sibling)->left) { \
208  (sibling)->left->color = rbBlack; \
209  } \
210  TR_TREE_ROTATE(right, (root), (node)->parent); \
211  } \
212  }
213 
214 #define TR_TREE_BALANCE_DELETE(root, node, sibling) \
215  while(1) { \
216  TR_TREE_BALANCE_DELETE_CASE1((node)) \
217  sibling = TR_TREE_SIBLING(node); \
218  TR_TREE_BALANCE_DELETE_CASE2((root), (node), (sibling)) \
219  TR_TREE_BALANCE_DELETE_CASE34((root), (node), (sibling)) \
220  TR_TREE_BALANCE_DELETE_CASE5((root), (node), (sibling)) \
221  TR_TREE_BALANCE_DELETE_CASE6((root), (node), (sibling)) \
222  break; \
223  }
224 
225 #define TR_TREE_BALANCE_INSERT_CASE1(node) \
226  if (NULL == (node)->parent) { \
227  (node)->color = rbBlack; \
228  break; \
229  }
230 
231 #define TR_TREE_BALANCE_INSERT_CASE2(node) \
232  if (rbBlack == (node)->parent->color) { \
233  break; \
234  }
235 
236 #define TR_TREE_BALANCE_INSERT_CASE3(node) \
237  if (NULL != TR_TREE_UNCLE(node) \
238  && rbRed == TR_TREE_UNCLE(node)->color) { \
239  (node)->parent->color = rbBlack; \
240  TR_TREE_UNCLE(node)->color = rbBlack; \
241  (node)->parent->parent->color = rbRed; \
242  (node) = (node)->parent->parent; \
243  continue; \
244  }
245 
246 #define TR_TREE_BALANCE_INSERT_CASE4(root, node) \
247  if ((node) == (node)->parent->right \
248  && (node)->parent == (node)->parent->parent->left) { \
249  TR_TREE_ROTATE(left, (root), (node)->parent); \
250  (node) = (node)->left; \
251  } else if ((node) == (node)->parent->left \
252  && (node)->parent == (node)->parent->parent->right) { \
253  TR_TREE_ROTATE(right, (root), (node)->parent); \
254  (node) = (node)->right; \
255  }
256 
257 #define TR_TREE_BALANCE_INSERT_CASE5(root, node) \
258  (node)->parent->color = rbBlack; \
259  (node)->parent->parent->color = rbRed; \
260  if ((node) == (node)->parent->left) { \
261  TR_TREE_ROTATE(right, (root), (node)->parent->parent); \
262  } else { \
263  TR_TREE_ROTATE(left, (root), (node)->parent->parent); \
264  }
265 
266 #define TR_TREE_BALANCE_INSERT(root, node) \
267  while (1) { \
268  TR_TREE_BALANCE_INSERT_CASE1((node)) \
269  TR_TREE_BALANCE_INSERT_CASE2((node)) \
270  if (NULL != (node)->parent->parent) { \
271  TR_TREE_BALANCE_INSERT_CASE3((node)) \
272  TR_TREE_BALANCE_INSERT_CASE4((root), (node)) \
273  TR_TREE_BALANCE_INSERT_CASE5((root), (node)) \
274  } \
275  break; \
276  }
277 
278 #endif // __TR_TREE_MACROS_H__
279 
280 // vim: set ts=4 sw=4:
TR_rbColor
Definition: tree_macros.h:88