nfs-ganesha 1.4

avl.c

Go to the documentation of this file.
00001 /*
00002  * avltree - Implements an AVL 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 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024 #include <assert.h>
00025 
00026 #include "avltree.h"
00027 
00028 
00029 #if !defined UINTPTR_MAX || UINTPTR_MAX != UINT64_MAX
00030 
00031 static inline int is_root(struct avltree_node *node)
00032 {
00033         return node->parent == NULL;
00034 }
00035 
00036 static inline void INIT_NODE(struct avltree_node *node)
00037 {
00038         node->left = NULL;
00039         node->right = NULL;
00040         node->parent = NULL;
00041         node->balance = 0;
00042 }
00043 
00044 static inline signed get_balance(struct avltree_node *node)
00045 {
00046         return node->balance;
00047 }
00048 
00049 static inline void set_balance(int balance, struct avltree_node *node)
00050 {
00051         node->balance = balance;
00052 }
00053 
00054 static inline int inc_balance(struct avltree_node *node)
00055 {
00056         return ++node->balance;
00057 }
00058 
00059 static inline int dec_balance(struct avltree_node *node)
00060 {
00061         return --node->balance;
00062 }
00063 
00064 static inline struct avltree_node *get_parent(const struct avltree_node *node)
00065 {
00066         return node->parent;
00067 }
00068 
00069 static inline void set_parent(struct avltree_node *parent,
00070                               struct avltree_node *node)
00071 {
00072         node->parent = parent;
00073 }
00074 
00075 #else
00076 
00077 static inline int is_root(struct avltree_node *node)
00078 {
00079         return !(node->parent & ~7UL);
00080 }
00081 
00082 static inline void INIT_NODE(struct avltree_node *node)
00083 {
00084         node->left = NULL;
00085         node->right = NULL;
00086         node->parent = 2;
00087 }
00088 
00089 static inline signed get_balance(struct avltree_node *node)
00090 {
00091         return (int)(node->parent & 7) - 2;
00092 }
00093 
00094 static inline void set_balance(int balance, struct avltree_node *node)
00095 {
00096         node->parent = (node->parent & ~7UL) | (balance + 2);
00097 }
00098 
00099 static inline int inc_balance(struct avltree_node *node)
00100 {
00101         return (int)(++node->parent & 7) - 2;
00102 }
00103 
00104 static inline int dec_balance(struct avltree_node *node)
00105 {
00106         return (int)(--node->parent & 7) - 2;
00107 }
00108 
00109 static inline struct avltree_node *get_parent(const struct avltree_node *node)
00110 {
00111         return (struct avltree_node *)(node->parent & ~7UL);
00112 }
00113 
00114 static inline void set_parent(const struct avltree_node *parent,
00115                               struct avltree_node *node)
00116 {
00117         node->parent = (uintptr_t)parent | (node->parent & 7);
00118 }
00119 
00120 #endif
00121 
00122 /*
00123  * Iterators
00124  */
00125 static inline struct avltree_node *get_first(struct avltree_node *node)
00126 {
00127         while (node->left)
00128                 node = node->left;
00129         return node;
00130 }
00131 
00132 static inline struct avltree_node *get_last(struct avltree_node *node)
00133 {
00134         while (node->right)
00135                 node = node->right;
00136         return node;
00137 }
00138 
00139 struct avltree_node *avltree_first(const struct avltree *tree)
00140 {
00141         return tree->first;
00142 }
00143 
00144 struct avltree_node *avltree_last(const struct avltree *tree)
00145 {
00146         return tree->last;
00147 }
00148 
00149 struct avltree_node *avltree_next(const struct avltree_node *node)
00150 {
00151         struct avltree_node *parent;
00152 
00153         if (node->right)
00154                 return get_first(node->right);
00155 
00156         while ((parent = get_parent(node)) && parent->right == node)
00157                 node = parent;
00158         return parent;
00159 }
00160 
00161 struct avltree_node *avltree_prev(const struct avltree_node *node)
00162 {
00163         struct avltree_node *parent;
00164 
00165         if (node->left)
00166                 return get_last(node->left);
00167 
00168         while ((parent = get_parent(node)) && parent->left == node)
00169                 node = parent;
00170         return parent;
00171 }
00172 
00173 uint64_t avltree_size(const struct avltree *tree)
00174 {
00175     return tree->size;
00176 }
00177 
00178 /*
00179  * The AVL tree is more rigidly balanced than Red-Black trees, leading
00180  * to slower insertion and removal but faster retrieval.
00181  */
00182 
00183 /* node->balance = height(node->right) - height(node->left); */
00184 static void rotate_left(struct avltree_node *node, struct avltree *tree)
00185 {
00186         struct avltree_node *p = node;
00187         struct avltree_node *q = node->right; /* can't be NULL */
00188         struct avltree_node *parent = get_parent(p);
00189 
00190         if (!is_root(p)) {
00191                 if (parent->left == p)
00192                         parent->left = q;
00193                 else
00194                         parent->right = q;
00195         } else
00196                 tree->root = q;
00197         set_parent(parent, q);
00198         set_parent(q, p);
00199 
00200         p->right = q->left;
00201         if (p->right)
00202                 set_parent(p, p->right);
00203         q->left = p;
00204 }
00205 
00206 static void rotate_right(struct avltree_node *node, struct avltree *tree)
00207 {
00208         struct avltree_node *p = node;
00209         struct avltree_node *q = node->left; /* can't be NULL */
00210         struct avltree_node *parent = get_parent(p);
00211 
00212         if (!is_root(p)) {
00213                 if (parent->left == p)
00214                         parent->left = q;
00215                 else
00216                         parent->right = q;
00217         } else
00218                 tree->root = q;
00219         set_parent(parent, q);
00220         set_parent(q, p);
00221 
00222         p->left = q->right;
00223         if (p->left)
00224                 set_parent(p, p->left);
00225         q->right = p;
00226 }
00227 
00228 /*
00229  * 'pparent', 'unbalanced' and 'is_left' are only used for
00230  * insertions. Normally GCC will notice this and get rid of them for
00231  * lookups.
00232  */
00233 static inline struct avltree_node *do_lookup(const struct avltree_node *key,
00234                                              const struct avltree *tree,
00235                                              struct avltree_node **pparent,
00236                                              struct avltree_node **unbalanced,
00237                                              int *is_left)
00238 {
00239         struct avltree_node *node = tree->root;
00240         int res = 0;
00241 
00242         *pparent = NULL;
00243         *unbalanced = node;
00244         *is_left = 0;
00245 
00246         while (node) {
00247                 if (get_balance(node) != 0)
00248                         *unbalanced = node;
00249 
00250                 res = tree->cmp_fn(node, key);
00251                 if (res == 0)
00252                         return node;
00253                 *pparent = node;
00254                 if ((*is_left = res > 0))
00255                         node = node->left;
00256                 else
00257                         node = node->right;
00258         }
00259         return NULL;
00260 }
00261 
00262 struct avltree_node *avltree_lookup(const struct avltree_node *key,
00263                                     const struct avltree *tree)
00264 {
00265         struct avltree_node *parent, *unbalanced;
00266         int is_left;
00267 
00268         return do_lookup(key, tree, &parent, &unbalanced, &is_left);
00269 }
00270 
00271 struct avltree_node *avltree_inf(const struct avltree_node *key,
00272                                  const struct avltree *tree)
00273 {
00274     struct avltree_node *parent __attribute__((unused));
00275     struct avltree_node *lb;
00276     struct avltree_node *unbalanced __attribute__((unused));
00277     struct avltree_node *node = tree->root;
00278     int is_left = 0;
00279     int res = 0;
00280 
00281     lb = avltree_first(tree); /* at worst, the first entry */
00282     unbalanced = node;
00283     parent = NULL;
00284     is_left = 0;
00285 
00286     while (node) {
00287         if (get_balance(node) != 0)
00288             unbalanced = node;
00289         res = tree->cmp_fn(node, key);
00290         if (res == 0) {
00291             /* node is the infimum */
00292             return node;
00293         }
00294         else if (res < 1) /* lb is less than key */
00295             lb = node;
00296         parent = node;
00297         if ((is_left = res > 0))
00298             node = node->left;
00299         else
00300             node = node->right;
00301     } /* while */
00302 
00303     return (lb);
00304 }
00305 
00306 struct avltree_node *avltree_sup(const struct avltree_node *key,
00307                                  const struct avltree *tree)
00308 {
00309     struct avltree_node *parent __attribute__((unused));
00310     struct avltree_node *ub = NULL;
00311     struct avltree_node *unbalanced __attribute__((unused));
00312     struct avltree_node *node = tree->root;
00313     int is_left = 0;
00314     int res = 0;
00315 
00316     unbalanced = node;
00317     parent = NULL;
00318     is_left = 0;
00319     ub = node;
00320     while (node) {
00321         if (get_balance(node) != 0)
00322             unbalanced = node;
00323         res = tree->cmp_fn(node, key);
00324         if (res == 0) {
00325             /* node is the supremum */
00326             return (node);
00327         }
00328         parent = node;
00329         if ((is_left = res > 0))
00330             node = node->left;
00331         else
00332             node = node->right;
00333         if (node) {
00334             res = tree->cmp_fn(node, key);
00335             if(res > 0) /* XXX do we need reciprocal test on ub? */
00336                 ub = node;
00337         }
00338     } /* while */
00339 
00340     return (ub);
00341 }
00342 
00343 static void set_child(struct avltree_node *child,
00344                       struct avltree_node *node, int left)
00345 {
00346         if (left)
00347                 node->left = child;
00348         else
00349                 node->right = child;
00350 }
00351 
00352 /* Insertion never needs more than 2 rotations */
00353 struct avltree_node *avltree_insert(struct avltree_node *node, struct avltree *tree)
00354 {
00355         struct avltree_node *key, *parent, *unbalanced;
00356         int is_left;
00357 
00358         key = do_lookup(node, tree, &parent, &unbalanced, &is_left);
00359         if (key)
00360                 return key;
00361 
00362         INIT_NODE(node);
00363 
00364         if (!parent) {
00365                 tree->root = node;
00366                 tree->first = tree->last = node;
00367                 tree->height++;
00368                 tree->size++;
00369                 return NULL;
00370         }
00371         if (is_left) {
00372                 if (parent == tree->first)
00373                         tree->first = node;
00374         } else {
00375                 if (parent == tree->last)
00376                         tree->last = node;
00377         }
00378         set_parent(parent, node);
00379         set_child(node, parent, is_left);
00380 
00381         for (;;) {
00382                 if (parent->left == node)
00383                         dec_balance(parent);
00384                 else
00385                         inc_balance(parent);
00386 
00387                 if (parent == unbalanced)
00388                         break;
00389                 node = parent;
00390                 parent = get_parent(parent);
00391         }
00392 
00393         /* inserted */
00394         tree->size++;
00395 
00396         switch (get_balance(unbalanced)) {
00397         case  1: case -1:
00398                 tree->height++;
00399                 /* fall through */
00400         case 0:
00401                 break;
00402         case 2: {
00403                 struct avltree_node *right = unbalanced->right;
00404 
00405                 if (get_balance(right) == 1) {
00406                         set_balance(0, unbalanced);
00407                         set_balance(0, right);
00408                 } else {
00409                         switch (get_balance(right->left)) {
00410                         case 1:
00411                                 set_balance(-1, unbalanced);
00412                                 set_balance( 0, right);
00413                                 break;
00414                         case 0:
00415                                 set_balance(0, unbalanced);
00416                                 set_balance(0, right);
00417                                 break;
00418                         case -1:
00419                                 set_balance(0, unbalanced);
00420                                 set_balance(1, right);
00421                                 break;
00422                         }
00423                         set_balance(0, right->left);
00424 
00425                         rotate_right(right, tree);
00426                 }
00427                 rotate_left(unbalanced, tree);
00428                 break;
00429         }
00430         case -2: {
00431                 struct avltree_node *left = unbalanced->left;
00432 
00433                 if (get_balance(left) == -1) {
00434                         set_balance(0, unbalanced);
00435                         set_balance(0, left);
00436                 } else {
00437                         switch (get_balance(left->right)) {
00438                         case 1:
00439                                 set_balance( 0, unbalanced);
00440                                 set_balance(-1, left);
00441                                 break;
00442                         case 0:
00443                                 set_balance(0, unbalanced);
00444                                 set_balance(0, left);
00445                                 break;
00446                         case -1:
00447                                 set_balance(1, unbalanced);
00448                                 set_balance(0, left);
00449                                 break;
00450                         }
00451                         set_balance(0, left->right);
00452 
00453                         rotate_left(left, tree);
00454                 }
00455                 rotate_right(unbalanced, tree);
00456                 break;
00457         }
00458         }
00459         return NULL;
00460 }
00461 
00462 /* Deletion might require up to log(n) rotations */
00463 void avltree_remove(struct avltree_node *node, struct avltree *tree)
00464 {
00465         struct avltree_node *parent = get_parent(node);
00466         struct avltree_node *left = node->left;
00467         struct avltree_node *right = node->right;
00468         struct avltree_node *next;
00469         int is_left = is_left;
00470 
00471         if (node == tree->first)
00472                 tree->first = avltree_next(node);
00473         if (node == tree->last)
00474                 tree->last = avltree_prev(node);
00475 
00476         if (!left)
00477                 next = right;
00478         else if (!right)
00479                 next = left;
00480         else
00481                 next = get_first(right);
00482 
00483         if (parent) {
00484                 is_left = parent->left == node;
00485                 set_child(next, parent, is_left);
00486         } else
00487                 tree->root = next;
00488 
00489         if (left && right) {
00490                 set_balance(get_balance(node), next);
00491 
00492                 next->left = left;
00493                 set_parent(next, left);
00494 
00495                 if (next != right) {
00496                         parent = get_parent(next);
00497                         set_parent(get_parent(node), next);
00498 
00499                         node = next->right;
00500                         parent->left = node;
00501                         is_left = 1;
00502 
00503                         next->right = right;
00504                         set_parent(next, right);
00505                 } else {
00506                         set_parent(parent, next);
00507                         parent = next;
00508                         node = parent->right;
00509                         is_left = 0;
00510                 }
00511                 assert(parent != NULL);
00512         } else
00513                 node = next;
00514 
00515         if (node)
00516                 set_parent(parent, node);
00517 
00518         /* removed */
00519         tree->size--;
00520 
00521         /*
00522          * At this point, 'parent' can only be null, if 'node' is the
00523          * tree's root and has at most one child.
00524          *
00525          * case 1: the subtree is now balanced but its height has
00526          * decreased.
00527          *
00528          * case 2: the subtree is mostly balanced and its height is
00529          * unchanged.
00530          *
00531          * case 3: the subtree is unbalanced and its height may have
00532          * been changed during the rebalancing process, see below.
00533          *
00534          * case 3.1: after a left rotation, the subtree becomes mostly
00535          * balanced and its height is unchanged.
00536          *
00537          * case 3.2: after a left rotation, the subtree becomes
00538          * balanced but its height has decreased.
00539          *
00540          * case 3.3: after a left and a right rotation, the subtree
00541          * becomes balanced or mostly balanced but its height has
00542          * decreased for all cases.
00543          */
00544         while (parent) {
00545                 int balance;
00546                 node   = parent;
00547                 parent = get_parent(parent);
00548 
00549                 if (is_left) {
00550                         is_left = parent && parent->left == node;
00551 
00552                         balance = inc_balance(node);
00553                         if (balance == 0)               /* case 1 */
00554                                 continue;
00555                         if (balance == 1)               /* case 2 */
00556                                 return;
00557                         right = node->right;            /* case 3 */
00558                         switch (get_balance(right)) {
00559                         case 0:                         /* case 3.1 */
00560                                 set_balance( 1, node);
00561                                 set_balance(-1, right);
00562                                 rotate_left(node, tree);
00563                                 return;
00564                         case 1:                         /* case 3.2 */
00565                                 set_balance(0, node);
00566                                 set_balance(0, right);
00567                                 break;
00568                         case -1:                        /* case 3.3 */
00569                                 switch (get_balance(right->left)) {
00570                                 case 1:
00571                                         set_balance(-1, node);
00572                                         set_balance( 0, right);
00573                                         break;
00574                                 case 0:
00575                                         set_balance(0, node);
00576                                         set_balance(0, right);
00577                                         break;
00578                                 case -1:
00579                                         set_balance(0, node);
00580                                         set_balance(1, right);
00581                                         break;
00582                                 }
00583                                 set_balance(0, right->left);
00584 
00585                                 rotate_right(right, tree);
00586                         }
00587                         rotate_left(node, tree);
00588                 } else {
00589                         is_left = parent && parent->left == node;
00590 
00591                         balance = dec_balance(node);
00592                         if (balance == 0)
00593                                 continue;
00594                         if (balance == -1)
00595                                 return;
00596                         left = node->left;
00597                         switch (get_balance(left)) {
00598                         case 0:
00599                                 set_balance(-1, node);
00600                                 set_balance(1, left);
00601                                 rotate_right(node, tree);
00602                                 return;
00603                         case -1:
00604                                 set_balance(0, node);
00605                                 set_balance(0, left);
00606                                 break;
00607                         case 1:
00608                                 switch (get_balance(left->right)) {
00609                                 case 1:
00610                                         set_balance(0, node);
00611                                         set_balance(-1, left);
00612                                         break;
00613                                 case 0:
00614                                         set_balance(0, node);
00615                                         set_balance(0, left);
00616                                         break;
00617                                 case -1:
00618                                         set_balance(1, node);
00619                                         set_balance(0, left);
00620                                         break;
00621                                 }
00622                                 set_balance(0, left->right);
00623 
00624                                 rotate_left(left, tree);
00625                         }
00626                         rotate_right(node, tree);
00627                 }
00628         }
00629         tree->height--;
00630 }
00631 
00632 void avltree_replace(struct avltree_node *old, struct avltree_node *new,
00633                      struct avltree *tree)
00634 {
00635         struct avltree_node *parent = get_parent(old);
00636 
00637         if (parent)
00638                 set_child(parent, new, parent->left == old);
00639         else {
00640             /* I'm skeptical this case should be permitted--this
00641              * says that if old is not in the tree, just make new
00642              * the root of the tree */
00643               tree->root = new;
00644               tree->size++;
00645         }
00646 
00647         if (old->left)
00648                 set_parent(new, old->left);
00649         if (old->right)
00650                 set_parent(new, old->right);
00651 
00652         if (tree->first == old)
00653                 tree->first = new;
00654         if (tree->last == old)
00655                 tree->last = new;
00656 
00657         *new = *old;
00658 }
00659 
00660 int avltree_init(struct avltree *tree, avltree_cmp_fn_t cmp, unsigned long flags)
00661 {
00662         if (flags)
00663                 return -1;
00664         tree->root = NULL;
00665         tree->cmp_fn = cmp;
00666         tree->height = -1;
00667         tree->first = NULL;
00668         tree->last = NULL;
00669         tree->size = 0;
00670         return 0;
00671 }