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