nfs-ganesha 1.4

rb.c

Go to the documentation of this file.
00001 /*
00002  * rbtree - Implements a red-black tree with parent pointers.
00003  *
00004  * Copyright (C) 2010 Franck Bui-Huu <fbuihuu@gmail.com>
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public License
00008  * as published by the Free Software Foundation; version 2 of the
00009  * License.
00010  *
00011  * This library is distributed in the hope that it will be useful, but
00012  * WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00019  * USA
00020  */
00021 
00022 /*
00023  * For recall a red-black tree has the following properties:
00024  *
00025  *     1. All nodes are either BLACK or RED
00026  *     2. Leafs are BLACK
00027  *     3. A RED node has BLACK children only
00028  *     4. Path from a node to any leafs has the same number of BLACK nodes.
00029  *
00030  */
00031 #ifdef HAVE_CONFIG_H
00032 #include "config.h"
00033 #endif
00034 #include "avltree.h"
00035 
00036 /*
00037  * Some helpers
00038  */
00039 #ifdef UINTPTR_MAX
00040 
00041 static inline enum rb_color get_color(const struct rbtree_node *node)
00042 {
00043         return node->parent & 1;
00044 }
00045 
00046 static inline void set_color(enum rb_color color, struct rbtree_node *node)
00047 {
00048         node->parent = (node->parent & ~1UL) | color;
00049 }
00050 
00051 static inline struct rbtree_node *get_parent(const struct rbtree_node *node)
00052 {
00053         return (struct rbtree_node *)(node->parent & ~1UL);
00054 }
00055 
00056 static inline void set_parent(struct rbtree_node *parent, struct rbtree_node *node)
00057 {
00058         node->parent = (uintptr_t)parent | (node->parent & 1);
00059 }
00060 
00061 #else
00062 
00063 static inline enum rb_color get_color(const struct rbtree_node *node)
00064 {
00065         return node->color;
00066 }
00067 
00068 static inline void set_color(enum rb_color color, struct rbtree_node *node)
00069 {
00070         node->color = color;
00071 }
00072 
00073 static inline struct rbtree_node *get_parent(const struct rbtree_node *node)
00074 {
00075         return node->parent;
00076 }
00077 
00078 static inline void set_parent(struct rbtree_node *parent, struct rbtree_node *node)
00079 {
00080         node->parent = parent;
00081 }
00082 
00083 #endif  /* UINTPTR_MAX */
00084 
00085 static inline int is_root(struct rbtree_node *node)
00086 {
00087         return get_parent(node) == NULL;
00088 }
00089 
00090 static inline int is_black(struct rbtree_node *node)
00091 {
00092         return get_color(node) == RB_BLACK;
00093 }
00094 
00095 static inline int is_red(struct rbtree_node *node)
00096 {
00097         return !is_black(node);
00098 }
00099 
00100 /*
00101  * Iterators
00102  */
00103 static inline struct rbtree_node *get_first(struct rbtree_node *node)
00104 {
00105         while (node->left)
00106                 node = node->left;
00107         return node;
00108 }
00109 
00110 static inline struct rbtree_node *get_last(struct rbtree_node *node)
00111 {
00112         while (node->right)
00113                 node = node->right;
00114         return node;
00115 }
00116 
00117 struct rbtree_node *rbtree_first(const struct rbtree *tree)
00118 {
00119         return tree->first;
00120 }
00121 
00122 struct rbtree_node *rbtree_last(const struct rbtree *tree)
00123 {
00124         return tree->last;
00125 }
00126 
00127 struct rbtree_node *rbtree_next(const struct rbtree_node *node)
00128 {
00129         struct rbtree_node *parent;
00130 
00131         if (node->right)
00132                 return get_first(node->right);
00133 
00134         while ((parent = get_parent(node)) && parent->right == node)
00135                 node = parent;
00136         return parent;
00137 }
00138 
00139 struct rbtree_node *rbtree_prev(const struct rbtree_node *node)
00140 {
00141         struct rbtree_node *parent;
00142 
00143         if (node->left)
00144                 return get_last(node->left);
00145 
00146         while ((parent = get_parent(node)) && parent->left == node)
00147                 node = parent;
00148         return parent;
00149 }
00150 
00151 /*
00152  * 'pparent' and 'is_left' are only used for insertions. Normally GCC
00153  * will notice this and get rid of them for lookups.
00154  */
00155 static inline struct rbtree_node *do_lookup(const struct rbtree_node *key,
00156                                             const struct rbtree *tree,
00157                                             struct rbtree_node **pparent,
00158                                             int *is_left)
00159 {
00160         struct rbtree_node *node = tree->root;
00161 
00162         *pparent = NULL;
00163         *is_left = 0;
00164 
00165         while (node) {
00166                 int res = tree->cmp_fn(node, key);
00167                 if (res == 0)
00168                         return node;
00169                 *pparent = node;
00170                 if ((*is_left = res > 0))
00171                         node = node->left;
00172                 else
00173                         node = node->right;
00174         }
00175         return NULL;
00176 }
00177 
00178 /*
00179  * Rotate operations (They preserve the binary search tree property,
00180  * assuming that the keys are unique).
00181  */
00182 static void rotate_left(struct rbtree_node *node, struct rbtree *tree)
00183 {
00184         struct rbtree_node *p = node;
00185         struct rbtree_node *q = node->right; /* can't be NULL */
00186         struct rbtree_node *parent = get_parent(p);
00187 
00188         if (!is_root(p)) {
00189                 if (parent->left == p)
00190                         parent->left = q;
00191                 else
00192                         parent->right = q;
00193         } else
00194                 tree->root = q;
00195         set_parent(parent, q);
00196         set_parent(q, p);
00197 
00198         p->right = q->left;
00199         if (p->right)
00200                 set_parent(p, p->right);
00201         q->left = p;
00202 }
00203 
00204 static void rotate_right(struct rbtree_node *node, struct rbtree *tree)
00205 {
00206         struct rbtree_node *p = node;
00207         struct rbtree_node *q = node->left; /* can't be NULL */
00208         struct rbtree_node *parent = get_parent(p);
00209 
00210         if (!is_root(p)) {
00211                 if (parent->left == p)
00212                         parent->left = q;
00213                 else
00214                         parent->right = q;
00215         } else
00216                 tree->root = q;
00217         set_parent(parent, q);
00218         set_parent(q, p);
00219 
00220         p->left = q->right;
00221         if (p->left)
00222                 set_parent(p, p->left);
00223         q->right = p;
00224 }
00225 
00226 struct rbtree_node *rbtree_lookup(const struct rbtree_node *key,
00227                                   const struct rbtree *tree)
00228 {
00229         struct rbtree_node *parent;
00230         int is_left;
00231 
00232         return do_lookup(key, tree, &parent, &is_left);
00233 }
00234 
00235 static void set_child(struct rbtree_node *child, struct rbtree_node *node, int left)
00236 {
00237         if (left)
00238                 node->left = child;
00239         else
00240                 node->right = child;
00241 }
00242 
00243 struct rbtree_node *rbtree_insert(struct rbtree_node *node, struct rbtree *tree)
00244 {
00245         struct rbtree_node *key, *parent;
00246         int is_left;
00247 
00248         key = do_lookup(node, tree, &parent, &is_left);
00249         if (key)
00250                 return key;
00251 
00252         node->left = NULL;
00253         node->right = NULL;
00254         set_color(RB_RED, node);
00255         set_parent(parent, node);
00256 
00257         if (parent) {
00258                 if (is_left) {
00259                         if (parent == tree->first)
00260                                 tree->first = node;
00261                 } else {
00262                         if (parent == tree->last)
00263                                 tree->last = node;
00264                 }
00265                 set_child(node, parent, is_left);
00266         } else {
00267                 tree->root = node;
00268                 tree->first = node;
00269                 tree->last = node;
00270         }
00271 
00272         /*
00273          * Fixup the modified tree by recoloring nodes and performing
00274          * rotations (2 at most) hence the red-black tree properties are
00275          * preserved.
00276          */
00277         while ((parent = get_parent(node)) && is_red(parent)) {
00278                 struct rbtree_node *grandpa = get_parent(parent);
00279 
00280                 if (parent == grandpa->left) {
00281                         struct rbtree_node *uncle = grandpa->right;
00282 
00283                         if (uncle && is_red(uncle)) {
00284                                 set_color(RB_BLACK, parent);
00285                                 set_color(RB_BLACK, uncle);
00286                                 set_color(RB_RED, grandpa);
00287                                 node = grandpa;
00288                         } else {
00289                                 if (node == parent->right) {
00290                                         rotate_left(parent, tree);
00291                                         node = parent;
00292                                         parent = get_parent(node);
00293                                 }
00294                                 set_color(RB_BLACK, parent);
00295                                 set_color(RB_RED, grandpa);
00296                                 rotate_right(grandpa, tree);
00297                         }
00298                 } else {
00299                         struct rbtree_node *uncle = grandpa->left;
00300 
00301                         if (uncle && is_red(uncle)) {
00302                                 set_color(RB_BLACK, parent);
00303                                 set_color(RB_BLACK, uncle);
00304                                 set_color(RB_RED, grandpa);
00305                                 node = grandpa;
00306                         } else {
00307                                 if (node == parent->left) {
00308                                         rotate_right(parent, tree);
00309                                         node = parent;
00310                                         parent = get_parent(node);
00311                                 }
00312                                 set_color(RB_BLACK, parent);
00313                                 set_color(RB_RED, grandpa);
00314                                 rotate_left(grandpa, tree);
00315                         }
00316                 }
00317         }
00318         set_color(RB_BLACK, tree->root);
00319         return NULL;
00320 }
00321 
00322 void rbtree_remove(struct rbtree_node *node, struct rbtree *tree)
00323 {
00324         struct rbtree_node *parent = get_parent(node);
00325         struct rbtree_node *left = node->left;
00326         struct rbtree_node *right = node->right;
00327         struct rbtree_node *next;
00328         enum rb_color color;
00329 
00330         if (node == tree->first)
00331                 tree->first = rbtree_next(node);
00332         if (node == tree->last)
00333                 tree->last = rbtree_prev(node);
00334 
00335         if (!left)
00336                 next = right;
00337         else if (!right)
00338                 next = left;
00339         else
00340                 next = get_first(right);
00341 
00342         if (parent)
00343                 set_child(next, parent, parent->left == node);
00344         else
00345                 tree->root = next;
00346 
00347         if (left && right) {
00348                 color = get_color(next);
00349                 set_color(get_color(node), next);
00350 
00351                 next->left = left;
00352                 set_parent(next, left);
00353 
00354                 if (next != right) {
00355                         parent = get_parent(next);
00356                         set_parent(get_parent(node), next);
00357 
00358                         node = next->right;
00359                         parent->left = node;
00360 
00361                         next->right = right;
00362                         set_parent(next, right);
00363                 } else {
00364                         set_parent(parent, next);
00365                         parent = next;
00366                         node = next->right;
00367                 }
00368         } else {
00369                 color = get_color(node);
00370                 node = next;
00371         }
00372         /*
00373          * 'node' is now the sole successor's child and 'parent' its
00374          * new parent (since the successor can have been moved).
00375          */
00376         if (node)
00377                 set_parent(parent, node);
00378 
00379         /*
00380          * The 'easy' cases.
00381          */
00382         if (color == RB_RED)
00383                 return;
00384         if (node && is_red(node)) {
00385                 set_color(RB_BLACK, node);
00386                 return;
00387         }
00388 
00389         do {
00390                 if (node == tree->root)
00391                         break;
00392 
00393                 if (node == parent->left) {
00394                         struct rbtree_node *sibling = parent->right;
00395 
00396                         if (is_red(sibling)) {
00397                                 set_color(RB_BLACK, sibling);
00398                                 set_color(RB_RED, parent);
00399                                 rotate_left(parent, tree);
00400                                 sibling = parent->right;
00401                         }
00402                         if ((!sibling->left  || is_black(sibling->left)) &&
00403                             (!sibling->right || is_black(sibling->right))) {
00404                                 set_color(RB_RED, sibling);
00405                                 node = parent;
00406                                 parent = get_parent(parent);
00407                                 continue;
00408                         }
00409                         if (!sibling->right || is_black(sibling->right)) {
00410                                 set_color(RB_BLACK, sibling->left);
00411                                 set_color(RB_RED, sibling);
00412                                 rotate_right(sibling, tree);
00413                                 sibling = parent->right;
00414                         }
00415                         set_color(get_color(parent), sibling);
00416                         set_color(RB_BLACK, parent);
00417                         set_color(RB_BLACK, sibling->right);
00418                         rotate_left(parent, tree);
00419                         node = tree->root;
00420                         break;
00421                 } else {
00422                         struct rbtree_node *sibling = parent->left;
00423 
00424                         if (is_red(sibling)) {
00425                                 set_color(RB_BLACK, sibling);
00426                                 set_color(RB_RED, parent);
00427                                 rotate_right(parent, tree);
00428                                 sibling = parent->left;
00429                         }
00430                         if ((!sibling->left  || is_black(sibling->left)) &&
00431                             (!sibling->right || is_black(sibling->right))) {
00432                                 set_color(RB_RED, sibling);
00433                                 node = parent;
00434                                 parent = get_parent(parent);
00435                                 continue;
00436                         }
00437                         if (!sibling->left || is_black(sibling->left)) {
00438                                 set_color(RB_BLACK, sibling->right);
00439                                 set_color(RB_RED, sibling);
00440                                 rotate_left(sibling, tree);
00441                                 sibling = parent->left;
00442                         }
00443                         set_color(get_color(parent), sibling);
00444                         set_color(RB_BLACK, parent);
00445                         set_color(RB_BLACK, sibling->left);
00446                         rotate_right(parent, tree);
00447                         node = tree->root;
00448                         break;
00449                 }
00450         } while (is_black(node));
00451 
00452         if (node)
00453                 set_color(RB_BLACK, node);
00454 }
00455 
00456 void rbtree_replace(struct rbtree_node *old, struct rbtree_node *new,
00457                     struct rbtree *tree)
00458 {
00459         struct rbtree_node *parent = get_parent(old);
00460 
00461         if (parent)
00462                 set_child(parent, new, parent->left == old);
00463         else
00464                 tree->root = new;
00465 
00466         if (old->left)
00467                 set_parent(new, old->left);
00468         if (old->right)
00469                 set_parent(new, old->right);
00470 
00471         if (tree->first == old)
00472                 tree->first = new;
00473         if (tree->last == old)
00474                 tree->last = new;
00475 
00476         *new = *old;
00477 }
00478 
00479 int rbtree_init(struct rbtree *tree, rbtree_cmp_fn_t fn, unsigned long flags)
00480 {
00481         if (flags)
00482                 return -1;
00483         tree->root = NULL;
00484         tree->cmp_fn = fn;
00485         tree->first = NULL;
00486         tree->last = NULL;
00487         return 0;
00488 }