1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
2 /*
3 * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
4 * University Research and Technology
5 * Corporation. All rights reserved.
6 * Copyright (c) 2004-2013 The University of Tennessee and The University
7 * of Tennessee Research Foundation. All rights
8 * reserved.
9 * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
10 * University of Stuttgart. All rights reserved.
11 * Copyright (c) 2004-2005 The Regents of the University of California.
12 * All rights reserved.
13 * Copyright (c) 2015 Los Alamos National Security, LLC. All rights
14 * reserved.
15 * $COPYRIGHT$
16 *
17 * Additional copyrights may follow
18 *
19 * $HEADER$
20 */
21 /*
22 * @file
23 */
24
25 #include "opal_config.h"
26
27 #include "opal/class/opal_rb_tree.h"
28
29 /* Private functions */
30 static void btree_insert(opal_rb_tree_t *tree, opal_rb_tree_node_t * node);
31 static void btree_delete_fixup(opal_rb_tree_t *tree, opal_rb_tree_node_t * x);
32 static opal_rb_tree_node_t * btree_successor(opal_rb_tree_t * tree,
33 opal_rb_tree_node_t * node);
34 static opal_rb_tree_node_t * opal_rb_tree_find_node(opal_rb_tree_t *tree, void *key);
35 static void left_rotate(opal_rb_tree_t *tree, opal_rb_tree_node_t * x);
36 static void right_rotate(opal_rb_tree_t *tree, opal_rb_tree_node_t * x);
37 static void inorder_destroy(opal_rb_tree_t *tree, opal_rb_tree_node_t * node);
38 static void inorder_traversal(opal_rb_tree_t *tree,
39 opal_rb_tree_condition_fn_t cond,
40 opal_rb_tree_action_fn_t action,
41 opal_rb_tree_node_t * node);
42
43
44 /**
45 * the constructor function. creates the free list to get the nodes from
46 *
47 * @param object the tree that is to be used
48 *
49 * @retval NONE
50 */
opal_rb_tree_construct(opal_object_t * object)51 static void opal_rb_tree_construct(opal_object_t * object)
52 {
53 opal_rb_tree_t * tree = (opal_rb_tree_t *) object;
54 tree->root_ptr = NULL;
55 OBJ_CONSTRUCT(&(tree->free_list), opal_free_list_t);
56 opal_free_list_init (&(tree->free_list), sizeof(opal_rb_tree_node_t),
57 opal_cache_line_size, OBJ_CLASS(opal_rb_tree_node_t),
58 0,opal_cache_line_size, 0, -1 , 128, NULL, 0, NULL, NULL, NULL);
59 }
60
61 /**
62 * the destructor function. Free the tree and destroys the free list.
63 *
64 * @param object the tree object
65 */
opal_rb_tree_destruct(opal_object_t * object)66 static void opal_rb_tree_destruct(opal_object_t * object)
67 {
68 if(NULL != ((opal_rb_tree_t *)object)->root_ptr) {
69 opal_rb_tree_destroy((opal_rb_tree_t *) object);
70 }
71 OBJ_DESTRUCT(&(((opal_rb_tree_t *)object)->free_list));
72 return;
73 }
74
75 /* declare the instance of the classes */
76 OBJ_CLASS_INSTANCE(opal_rb_tree_node_t, opal_free_list_item_t, NULL, NULL);
77 OBJ_CLASS_INSTANCE(opal_rb_tree_t, opal_object_t, opal_rb_tree_construct,
78 opal_rb_tree_destruct);
79
80 /* Create the tree */
opal_rb_tree_init(opal_rb_tree_t * tree,opal_rb_tree_comp_fn_t comp)81 int opal_rb_tree_init(opal_rb_tree_t * tree,
82 opal_rb_tree_comp_fn_t comp)
83 {
84 opal_free_list_item_t * node;
85 /* we need to get memory for the root pointer from the free list */
86 node = opal_free_list_get (&(tree->free_list));
87 tree->root_ptr = (opal_rb_tree_node_t *) node;
88 if (NULL == node) {
89 return OPAL_ERR_OUT_OF_RESOURCE;
90 }
91
92 node = opal_free_list_get (&(tree->free_list));
93 if (NULL == node) {
94 opal_free_list_return (&tree->free_list, (opal_free_list_item_t*)tree->root_ptr);
95 return OPAL_ERR_OUT_OF_RESOURCE;
96 }
97 tree->nill = (opal_rb_tree_node_t *) node;
98 /* initialize tree->nill */
99 tree->nill->color = BLACK;
100 tree->nill->left = tree->nill;
101 tree->nill->right = tree->nill;
102 tree->nill->parent = tree->nill;
103
104 /* initialize the 'root' pointer */
105 tree->root_ptr->left = tree->nill;
106 tree->root_ptr->right = tree->nill;
107 tree->root_ptr->parent = tree->nill;
108 tree->root_ptr->color = BLACK;
109
110 tree->comp = comp;
111
112 /* set the tree size to zero */
113 tree->tree_size = 0;
114
115 return OPAL_SUCCESS;
116 }
117
118
119 /* This inserts a node into the tree based on the passed values. */
opal_rb_tree_insert(opal_rb_tree_t * tree,void * key,void * value)120 int opal_rb_tree_insert(opal_rb_tree_t *tree, void * key, void * value)
121 {
122 opal_rb_tree_node_t * y;
123 opal_rb_tree_node_t * node;
124 opal_free_list_item_t * item;
125
126 /* get the memory for a node */
127 item = opal_free_list_get (&tree->free_list);
128 if (NULL == item) {
129 return OPAL_ERR_OUT_OF_RESOURCE;
130 }
131 node = (opal_rb_tree_node_t *) item;
132 /* insert the data into the node */
133 node->key = key;
134 node->value = value;
135
136 /* insert the node into the tree */
137 btree_insert(tree, node);
138
139 /*do the rotations */
140 /* usually one would have to check for NULL, but because of the sentinal,
141 * we don't have to */
142 while (node->parent->color == RED) {
143 if (node->parent == node->parent->parent->left) {
144 y = node->parent->parent->right;
145 if (y->color == RED) {
146 node->parent->color = BLACK;
147 y->color = BLACK;
148 node->parent->parent->color = RED;
149 node = node->parent->parent;
150 } else {
151 if (node == node->parent->right) {
152 node = node->parent;
153 left_rotate(tree, node);
154 }
155 node->parent->color = BLACK;
156 node->parent->parent->color = RED;
157 right_rotate(tree, node->parent->parent);
158 }
159 } else {
160 y = node->parent->parent->left;
161 if (y->color == RED) {
162 node->parent->color = BLACK;
163 y->color = BLACK;
164 node->parent->parent->color = RED;
165 node = node->parent->parent;
166 } else {
167 if (node == node->parent->left) {
168 node = node->parent;
169 right_rotate(tree, node);
170 }
171 node->parent->color = BLACK;
172 node->parent->parent->color = RED;
173 left_rotate(tree, node->parent->parent);
174 }
175 }
176 }
177 /* after the rotations the root is black */
178 tree->root_ptr->left->color = BLACK;
179 return OPAL_SUCCESS;
180 }
181
182 /* Finds the node in the tree based on the key */
opal_rb_tree_find_with(opal_rb_tree_t * tree,void * key,opal_rb_tree_comp_fn_t compfn)183 void * opal_rb_tree_find_with(opal_rb_tree_t *tree, void *key,
184 opal_rb_tree_comp_fn_t compfn)
185 {
186 opal_rb_tree_node_t * node;
187 int compvalue;
188
189 node = tree->root_ptr->left;
190 while (node != tree->nill) {
191 compvalue = compfn(key, node->key);
192 /* if the result of the comparison function is 0, we found it */
193 if (compvalue == 0) {
194 return node->value;
195 }
196 /* else if it is less than 0, go left, else right */
197 node = ((compvalue < 0) ? node->left : node->right);
198 }
199 /* if we didn't find anything, return NULL */
200 return NULL;
201 }
202
203 /* Finds the node in the tree based on the key and returns a pointer
204 * to the node. This is a bit a code duplication, but this has to be fast
205 * so we go ahead with the duplication */
opal_rb_tree_find_node(opal_rb_tree_t * tree,void * key)206 static opal_rb_tree_node_t * opal_rb_tree_find_node(opal_rb_tree_t *tree, void *key)
207 {
208 opal_rb_tree_node_t * node;
209 int compvalue;
210
211 node = tree->root_ptr->left;
212 while (node != tree->nill) {
213 compvalue = tree->comp(key, node->key);
214 /* if the result of the comparison function is 0, we found it */
215 if (compvalue == 0) {
216 return node;
217 }
218 /* else if it is less than 0, go left, else right */
219 node = ((compvalue < 0) ? node->left : node->right);
220 }
221 /* if we didn't find anything, return NULL */
222 return NULL;
223 }
224
225 /* Delete a node from the tree based on the key */
opal_rb_tree_delete(opal_rb_tree_t * tree,void * key)226 int opal_rb_tree_delete(opal_rb_tree_t *tree, void *key)
227 {
228 opal_rb_tree_node_t * p;
229 opal_rb_tree_node_t * todelete;
230 opal_rb_tree_node_t * y;
231 opal_free_list_item_t * item;
232
233 p = opal_rb_tree_find_node(tree, key);
234 if (NULL == p) {
235 return OPAL_ERR_NOT_FOUND;
236 }
237 if ((p->left == tree->nill) || (p->right == tree->nill)) {
238 todelete = p;
239 } else {
240 todelete = btree_successor(tree, p);
241 }
242
243 if (todelete->left == tree->nill) {
244 y = todelete->right;
245 } else {
246 y = todelete->left;
247 }
248
249 y->parent = todelete->parent;
250
251 if (y->parent == tree->root_ptr) {
252 tree->root_ptr->left = y;
253 } else {
254 if (todelete == todelete->parent->left) {
255 todelete->parent->left = y;
256 } else {
257 todelete->parent->right = y;
258 }
259 }
260
261 if (todelete != p) {
262 p->key = todelete->key;
263 p->value = todelete->value;
264 }
265
266 if (todelete->color == BLACK) {
267 btree_delete_fixup(tree, y);
268 }
269 item = (opal_free_list_item_t *) todelete;
270 opal_free_list_return (&(tree->free_list), item);
271 --tree->tree_size;
272 return OPAL_SUCCESS;
273 }
274
275
276 /* Destroy the hashmap */
opal_rb_tree_destroy(opal_rb_tree_t * tree)277 int opal_rb_tree_destroy(opal_rb_tree_t *tree)
278 {
279 opal_free_list_item_t * item;
280 /* Recursive inorder traversal for delete */
281
282 inorder_destroy(tree, tree->root_ptr);
283 /* Now free the root -- root does not get free'd in the above
284 * inorder destroy */
285 item = (opal_free_list_item_t *) tree->root_ptr;
286 opal_free_list_return(&(tree->free_list), item);
287
288 /* free the tree->nill node */
289 item = (opal_free_list_item_t *) tree->nill;
290 opal_free_list_return (&(tree->free_list), item);
291 return OPAL_SUCCESS;
292 }
293
294
295 /* Find the next inorder successor of a node */
296
btree_successor(opal_rb_tree_t * tree,opal_rb_tree_node_t * node)297 static opal_rb_tree_node_t * btree_successor(opal_rb_tree_t * tree, opal_rb_tree_node_t * node)
298 {
299 opal_rb_tree_node_t * p;
300
301 if (node->right == tree->nill) {
302 p = node->parent;
303 while (node == p->right) {
304 node = p;
305 p = p->parent;
306 }
307 if(p == tree->root_ptr) {
308 return tree->nill;
309 }
310 return p;
311 }
312
313 p = node->right;
314 while(p->left != tree->nill) {
315 p = p->left;
316 }
317 return p;
318 }
319
320
321 /* Insert an element in the normal binary search tree fashion */
322 /* this function goes through the tree and finds the leaf where
323 * the node will be inserted */
btree_insert(opal_rb_tree_t * tree,opal_rb_tree_node_t * node)324 static void btree_insert(opal_rb_tree_t *tree, opal_rb_tree_node_t * node)
325 {
326 opal_rb_tree_node_t * parent = tree->root_ptr;
327 opal_rb_tree_node_t * n = parent->left; /* the real root of the tree */
328
329 /* set up initial values for the node */
330 node->color = RED;
331 node->parent = NULL;
332 node->left = tree->nill;
333 node->right = tree->nill;
334
335 /* find the leaf where we will insert the node */
336 while (n != tree->nill) {
337 parent = n;
338 n = ((tree->comp(node->key, n->key) <= 0) ? n->left : n->right);
339 }
340
341 /* place it on either the left or the right */
342 if((parent == tree->root_ptr) || (tree->comp(node->key, parent->key) <= 0)) {
343 parent->left = node;
344 } else {
345 parent->right = node;
346 }
347
348 /* set its parent and children */
349 node->parent = parent;
350 node->left = tree->nill;
351 node->right = tree->nill;
352 ++(tree->tree_size);
353 return;
354 }
355
356 /* Fixup the balance of the btree after deletion */
btree_delete_fixup(opal_rb_tree_t * tree,opal_rb_tree_node_t * x)357 static void btree_delete_fixup(opal_rb_tree_t *tree, opal_rb_tree_node_t * x)
358 {
359 opal_rb_tree_node_t * w;
360 opal_rb_tree_node_t * root = tree->root_ptr->left;
361 while ((x != root) && (x->color == BLACK)) {
362 if (x == x->parent->left) {
363 w = x->parent->right;
364 if (w->color == RED) {
365 w->color = BLACK;
366 x->parent->color = RED;
367 left_rotate(tree, x->parent);
368 w = x->parent->right;
369 }
370 if ((w->left->color == BLACK) && (w->right->color == BLACK)) {
371 w->color = RED;
372 x = x->parent;
373 } else {
374 if (w->right->color == BLACK) {
375 w->left->color = BLACK;
376 w->color = RED;
377 right_rotate(tree, w);
378 w = x->parent->right;
379 }
380 w->color = x->parent->color;
381 x->parent->color = BLACK;
382 w->right->color = BLACK;
383 left_rotate(tree, x->parent);
384 x = root;
385 }
386 } else { /* right */
387
388 w = x->parent->left;
389 if (w->color == RED) {
390 w->color = BLACK;
391 x->parent->color = RED;
392 right_rotate(tree, x->parent);
393 w = x->parent->left;
394 }
395 if ((w->right->color == BLACK) && (w->left->color == BLACK)) {
396 w->color = RED;
397 x = x->parent;
398 } else {
399 if (w->left->color == BLACK) {
400 w->right->color = BLACK;
401 w->color = RED;
402 left_rotate(tree, w);
403 w = x->parent->left;
404 }
405 w->color = x->parent->color;
406 x->parent->color = BLACK;
407 w->left->color = BLACK;
408 right_rotate(tree, x->parent);
409 x = root;
410 }
411 }
412 }
413
414 x->color = BLACK;
415 return;
416 }
417
418
419 /* Free the nodes in inorder fashion */
420
421 static void
inorder_destroy(opal_rb_tree_t * tree,opal_rb_tree_node_t * node)422 inorder_destroy(opal_rb_tree_t *tree, opal_rb_tree_node_t * node)
423 {
424 opal_free_list_item_t * item;
425
426 if (node == tree->nill) {
427 return;
428 }
429
430 inorder_destroy(tree, node->left);
431
432 if (node->left != tree->nill) {
433 item = (opal_free_list_item_t *) node->left;
434 --tree->tree_size;
435 opal_free_list_return (&tree->free_list, item);
436 }
437
438 inorder_destroy(tree, node->right);
439 if (node->right != tree->nill) {
440 item = (opal_free_list_item_t *) node->right;
441 --tree->tree_size;
442 opal_free_list_return (&tree->free_list, item);
443 }
444 }
445
446 /* Try to access all the elements of the hashmap conditionally */
447
opal_rb_tree_traverse(opal_rb_tree_t * tree,opal_rb_tree_condition_fn_t cond,opal_rb_tree_action_fn_t action)448 int opal_rb_tree_traverse(opal_rb_tree_t *tree,
449 opal_rb_tree_condition_fn_t cond,
450 opal_rb_tree_action_fn_t action)
451 {
452 if ((cond == NULL) || (action == NULL)) {
453 return OPAL_ERROR;
454 }
455
456 inorder_traversal(tree, cond, action, tree->root_ptr->left);
457
458 return OPAL_SUCCESS;
459 }
460
461
inorder_traversal(opal_rb_tree_t * tree,opal_rb_tree_condition_fn_t cond,opal_rb_tree_action_fn_t action,opal_rb_tree_node_t * node)462 static void inorder_traversal(opal_rb_tree_t *tree,
463 opal_rb_tree_condition_fn_t cond,
464 opal_rb_tree_action_fn_t action,
465 opal_rb_tree_node_t * node)
466 {
467 if (node == tree->nill) {
468 return;
469 }
470
471 inorder_traversal(tree, cond, action, node->left);
472
473 if (cond(node->value)) {
474 action(node->key, node->value);
475 }
476
477 inorder_traversal(tree, cond, action, node->right);
478 }
479
480 /* Left rotate the tree */
481 /* basically what we want to do is to make x be the left child
482 * of its right child */
left_rotate(opal_rb_tree_t * tree,opal_rb_tree_node_t * x)483 static void left_rotate(opal_rb_tree_t *tree, opal_rb_tree_node_t * x)
484 {
485 opal_rb_tree_node_t * y;
486
487 y = x->right;
488 /* make the left child of y's parent be x if it is not the sentinal node*/
489 if (y->left != tree->nill) {
490 y->left->parent=x;
491 }
492
493 /* normlly we would have to check to see if we are at the root.
494 * however, the root sentinal takes care of it for us */
495 if (x == x->parent->left) {
496 x->parent->left = y;
497 } else {
498 x->parent->right = y;
499 }
500 /* the old parent of x is now y's parent */
501 y->parent = x->parent;
502 /* x's parent is y */
503 x->parent = y;
504 x->right = y->left;
505 y->left = x;
506
507 return;
508 }
509
510
511 /* Right rotate the tree */
512 /* basically what we want to do is to make x be the right child
513 * of its left child */
right_rotate(opal_rb_tree_t * tree,opal_rb_tree_node_t * x)514 static void right_rotate(opal_rb_tree_t *tree, opal_rb_tree_node_t * x)
515 {
516 opal_rb_tree_node_t * y;
517
518 y = x->left;
519
520 if(y->right != tree->nill) {
521 y->right->parent = x;
522 }
523
524 if (x == x->parent->left) {
525 x->parent->left = y;
526 } else {
527 x->parent->right = y;
528 }
529
530 y->parent = x->parent;
531 x->parent = y;
532 x->left = y->right;
533 y->right = x;
534
535 return;
536 }
537
538
539 /* returns the size of the tree */
opal_rb_tree_size(opal_rb_tree_t * tree)540 int opal_rb_tree_size(opal_rb_tree_t *tree)
541 {
542 return tree->tree_size;
543 }
544
545 /* below are a couple of debugging functions */
546 #if 0
547 #include <stdio.h>
548 static void inorder(opal_rb_tree_t * tree, opal_rb_tree_node_t * node);
549 static void print_inorder(opal_rb_tree_t * tree);
550
551 void inorder(opal_rb_tree_t * tree, opal_rb_tree_node_t * node)
552 {
553 static int level = 0;
554 if (node == tree->nill) {
555 printf("nill\n");
556 return;
557 }
558 level++;
559 inorder(tree, node->left);
560 level--;
561 printf("%d, level: %d\n", *((int *)node->value), level);
562 level++;
563 inorder(tree, node->right);
564 level--;
565 }
566
567
568 void print_inorder(opal_rb_tree_t *tree)
569 {
570 inorder(tree, tree->root_ptr->left);
571 }
572
573 #endif
574