splay.c

00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <errno.h>
00004 
00005 #include "splay.h"
00006 
00007 cp_splaynode *cp_splaynode_create(void *key, void *value, cp_mempool *pool)
00008 {
00009     cp_splaynode *node;
00010     if (pool) 
00011         node = cp_mempool_calloc(pool);
00012     else
00013         node = calloc(1, sizeof(cp_splaynode));
00014     if (node == NULL) return NULL;
00015 
00016     node->key = key;
00017     node->value = value;
00018 
00019     return node;
00020 }
00021     
00022 void cp_splaytree_destroy_node(cp_splaytree *tree, cp_splaynode *node)
00023 {
00024     if (node)
00025     {
00026         if ((tree->mode & COLLECTION_MODE_DEEP))
00027         {
00028             if (tree->key_dtr) (*tree->key_dtr)(node->key);
00029             if ((tree->mode & COLLECTION_MODE_MULTIPLE_VALUES) && node->value)
00030                 cp_vector_destroy_custom(node->value, tree->value_dtr);
00031             else if (tree->value_dtr) 
00032                 (*tree->value_dtr)(node->value);
00033         }
00034         else if ((tree->mode & COLLECTION_MODE_MULTIPLE_VALUES) && node->value)
00035             cp_vector_destroy(node->value);
00036         if (tree->mempool)
00037             cp_mempool_free(tree->mempool, node);
00038         else
00039             free(node);
00040     }
00041 }
00042 
00043 void cp_splaytree_destroy_node_deep(cp_splaytree *tree, cp_splaynode *node)
00044 {
00045     if (node)
00046     {
00047         cp_splaynode *parent;
00048         cp_splaynode *child;
00049 
00050         parent = node;
00051         while (node)
00052         {
00053             if (node->right && node->right != parent)
00054             {
00055                 child = node->right;
00056                 node->right = parent;
00057                 parent = node;
00058                 node = child;
00059             }
00060             else if (node->left && node->left != parent)
00061             {
00062                 child = node->left;
00063                 node->left = node->right;
00064                 node->right = parent;
00065                 parent = node;
00066                 node = child;
00067             }
00068             else
00069             {
00070                 cp_splaytree_destroy_node(tree, node);
00071                 if (node != parent)
00072                 {
00073                     node = parent;
00074                     parent = node->right;
00075                 }
00076                 else
00077                     break;
00078             }
00079         }
00080     }
00081 }
00082 
00083 cp_splaytree *cp_splaytree_create(cp_compare_fn cmp)
00084 {
00085     cp_splaytree *tree = calloc(1, sizeof(cp_splaytree));
00086     if (tree == NULL) return NULL;
00087 
00088     tree->cmp = cmp;
00089     tree->mode = COLLECTION_MODE_NOSYNC;
00090 
00091     return tree;
00092 }
00093 
00094 /*
00095  * complete parameter create function
00096  */
00097 cp_splaytree *
00098     cp_splaytree_create_by_option(int mode, 
00099                                   cp_compare_fn cmp, 
00100                                   cp_copy_fn key_copy, 
00101                                   cp_destructor_fn key_dtr,
00102                                   cp_copy_fn val_copy, 
00103                                   cp_destructor_fn val_dtr)
00104 {
00105     cp_splaytree *tree = cp_splaytree_create(cmp);
00106     if (tree == NULL) return NULL;
00107     
00108     tree->mode = mode;
00109     tree->key_copy = key_copy;
00110     tree->key_dtr = key_dtr;
00111     tree->value_copy = val_copy;
00112     tree->value_dtr = val_dtr;
00113 
00114     if (!(mode & COLLECTION_MODE_NOSYNC))
00115     {
00116         tree->lock = malloc(sizeof(cp_lock));
00117         if (tree->lock == NULL) 
00118         {
00119             cp_splaytree_destroy(tree);
00120             return NULL;
00121         }
00122         if (cp_lock_init(tree->lock, NULL) != 0)
00123         {
00124             cp_splaytree_destroy(tree);
00125             return NULL;
00126         }
00127     }
00128 
00129     return tree;
00130 }
00131 
00132 void cp_splaytree_destroy(cp_splaytree *tree)
00133 {
00134     if (tree)
00135     {
00136         cp_splaytree_destroy_node_deep(tree, tree->root);
00137         if (tree->lock)
00138         {
00139             cp_lock_destroy(tree->lock);
00140             free(tree->lock);
00141         }
00142         free(tree);
00143     }
00144 }
00145 
00146 void cp_splaytree_destroy_custom(cp_splaytree *tree, 
00147                                  cp_destructor_fn key_dtr,
00148                                  cp_destructor_fn val_dtr)
00149 {
00150     tree->mode |= COLLECTION_MODE_DEEP;
00151     tree->key_dtr = key_dtr;
00152     tree->value_dtr = val_dtr;
00153     cp_splaytree_destroy(tree);
00154 }
00155 
00156 static int cp_splaytree_lock_internal(cp_splaytree *tree, int type)
00157 {
00158     int rc;
00159 
00160     switch (type)
00161     {
00162         case COLLECTION_LOCK_READ:
00163             rc = cp_lock_rdlock(tree->lock);
00164             break;
00165 
00166         case COLLECTION_LOCK_WRITE:
00167             rc = cp_lock_wrlock(tree->lock);
00168             break;
00169 
00170         case COLLECTION_LOCK_NONE:
00171             rc = 0;
00172             break;
00173 
00174         default:
00175             rc = EINVAL;
00176             break;
00177     }
00178 
00179     /* api functions may rely on errno to report locking failure */
00180     if (rc) errno = rc;
00181 
00182     return rc;
00183 }
00184 
00185 static int cp_splaytree_unlock_internal(cp_splaytree *tree)
00186 {
00187     return cp_lock_unlock(tree->lock);
00188 }
00189 
00190 int cp_splaytree_txlock(cp_splaytree *tree, int type)
00191 {
00192     /* clear errno to allow applications to detect locking failure */
00193     errno = 0;
00194     
00195     if (tree->mode & COLLECTION_MODE_NOSYNC) return 0;
00196     if (tree->mode & COLLECTION_MODE_IN_TRANSACTION && 
00197         tree->txtype == COLLECTION_LOCK_WRITE)
00198     {
00199         cp_thread self = cp_thread_self();
00200         if (cp_thread_equal(self, tree->txowner)) return 0;
00201     }
00202     return cp_splaytree_lock_internal(tree, type);
00203 }
00204 
00205 int cp_splaytree_txunlock(cp_splaytree *tree)
00206 {
00207     if (tree->mode & COLLECTION_MODE_NOSYNC) return 0;
00208     if (tree->mode & COLLECTION_MODE_IN_TRANSACTION && 
00209         tree->txtype == COLLECTION_LOCK_WRITE)
00210     {
00211         cp_thread self = cp_thread_self();
00212         if (cp_thread_equal(self, tree->txowner)) return 0;
00213     }
00214     return cp_splaytree_unlock_internal(tree);
00215 }
00216 
00217 /* lock and set the transaction indicators */
00218 int cp_splaytree_lock(cp_splaytree *tree, int type)
00219 {
00220     int rc;
00221     if ((tree->mode & COLLECTION_MODE_NOSYNC)) return EINVAL;
00222     if ((rc = cp_splaytree_lock_internal(tree, type))) return rc;
00223     tree->txtype = type;
00224     tree->txowner = cp_thread_self();
00225     tree->mode |= COLLECTION_MODE_IN_TRANSACTION;
00226     return 0;
00227 }
00228 
00229 /* unset the transaction indicators and unlock */
00230 int cp_splaytree_unlock(cp_splaytree *tree)
00231 {
00232     cp_thread self = cp_thread_self();
00233     if (tree->txowner == self)
00234     {
00235         tree->txowner = 0;
00236         tree->txtype = 0;
00237         tree->mode ^= COLLECTION_MODE_IN_TRANSACTION;
00238     }
00239     else if (tree->txtype == COLLECTION_LOCK_WRITE)
00240         return -1;
00241     return cp_splaytree_unlock_internal(tree);
00242 }
00243 
00244 /* set mode bits on the tree mode indicator */
00245 int cp_splaytree_set_mode(cp_splaytree *tree, int mode)
00246 {
00247     int rc;
00248     int nosync; 
00249 
00250     /* can't set NOSYNC in the middle of a transaction */
00251     if ((tree->mode & COLLECTION_MODE_IN_TRANSACTION) && 
00252         (mode & COLLECTION_MODE_NOSYNC)) return EINVAL;
00253     /* COLLECTION_MODE_MULTIPLE_VALUES must be set at creation time */  
00254     if ((mode & COLLECTION_MODE_MULTIPLE_VALUES)) return EINVAL;
00255 
00256     if ((rc = cp_splaytree_txlock(tree, COLLECTION_LOCK_WRITE))) return rc;
00257     
00258     nosync = tree->mode & COLLECTION_MODE_NOSYNC;
00259 
00260     tree->mode |= mode;
00261 
00262     if (!nosync)
00263         cp_splaytree_txunlock(tree);
00264 
00265     return 0;
00266 }
00267 
00268 /* unset mode bits on the tree mode indicator. if unsetting 
00269  * COLLECTION_MODE_NOSYNC and the tree was not previously synchronized, the 
00270  * internal synchronization structure is initalized.
00271  */
00272 int cp_splaytree_unset_mode(cp_splaytree *tree, int mode)
00273 {
00274     int rc;
00275     int nosync;
00276 
00277     /* COLLECTION_MODE_MULTIPLE_VALUES can't be unset */
00278     if ((mode & COLLECTION_MODE_MULTIPLE_VALUES)) return EINVAL;
00279 
00280     if ((rc = cp_splaytree_txlock(tree, COLLECTION_LOCK_WRITE))) return rc;
00281     
00282     nosync = tree->mode & COLLECTION_MODE_NOSYNC;
00283 
00284     /* handle the special case of unsetting COLLECTION_MODE_NOSYNC */
00285     if ((mode & COLLECTION_MODE_NOSYNC) && tree->lock == NULL)
00286     {
00287         /* tree can't be locked in this case, no need to unlock on failure */
00288         if ((tree->lock = malloc(sizeof(cp_lock))) == NULL)
00289             return -1; 
00290         if (cp_lock_init(tree->lock, NULL))
00291             return -1;
00292     }
00293     
00294     /* unset specified bits */
00295     tree->mode &= tree->mode ^ mode;
00296     if (!nosync)
00297         cp_splaytree_txunlock(tree);
00298 
00299     return 0;
00300 }
00301 
00302 int cp_splaytree_get_mode(cp_splaytree *tree)
00303 {
00304     return tree->mode;
00305 }
00306 
00307 
00308 /*  right_rotate - the splay 'zig' operation
00309  * 
00310  *       (P)                (Q)
00311  *      /   \              /   \
00312  *    (Q)    3    ==>     1    (P)  
00313  *   /   \                    /   \
00314  *  1     2                  2     3
00315  *
00316  */
00317 void right_rotate(cp_splaynode **node)
00318 {
00319     cp_splaynode *p = *node;
00320     cp_splaynode *q = p->left;
00321     p->left = q->right;
00322     q->right = p;
00323     *node = q;
00324 }
00325 
00326 /*  left_rotate - the splay 'zag' operation
00327  * 
00328  *    (P)                (Q)
00329  *   /   \              /   \
00330  *  1    (Q)    ==>   (P)    3
00331  *      /   \        /   \
00332  *     2     3      1     2
00333  *
00334  */
00335 void left_rotate(cp_splaynode **node)
00336 {
00337     cp_splaynode *p = *node;
00338     cp_splaynode *q = p->right;
00339 
00340     p->right = q->left;
00341     q->left = p;
00342     *node = q;
00343 }
00344 
00345 /*  left-right rotate - the splay 'zig-zag' operation
00346  * 
00347  *          (P)                (R)
00348  *         /   \              /   \
00349  *      (Q)     4   ==>     (Q)    (P)  
00350  *      / \                /  \    /  \
00351  *     1  (R)             1    2  3    4
00352  *        / \
00353  *       2   3
00354  *
00355  */
00356 static void left_right_rotate(cp_splaynode **node)
00357 {
00358     cp_splaynode *p = *node;
00359     cp_splaynode *q = (*node)->left;
00360     cp_splaynode *r = q->right;
00361 
00362     q->right = r->left;
00363     p->left = r->right;
00364     r->right = p;
00365     r->left = q;
00366 
00367     *node = r;
00368 }
00369 
00370 /*  right-left rotate - the splay 'zag-zig' operation
00371  * 
00372  *          (P)                   (R)
00373  *         /   \                 /   \
00374  *        1     (Q)     ==>    (P)    (Q)  
00375  *             /  \           /  \    /  \
00376  *           (R)   4         1    2  3    4
00377  *           / \
00378  *          2   3
00379  *
00380  */
00381 static void right_left_rotate(cp_splaynode **node)
00382 {
00383     cp_splaynode *p = *node;
00384     cp_splaynode *q = (*node)->right;
00385     cp_splaynode *r = q->left;
00386 
00387     q->left = r->right;
00388     p->right = r->left;
00389     r->left = p;
00390     r->right = q;
00391 
00392     *node = r;
00393 }
00394 
00395 /* implement COLLECTION_MODE_COPY, COLLECTION_MODE_MULTIPLE_VALUES if set */
00396 static cp_splaynode *
00397     create_splaynode(cp_splaytree *tree, void *key, void *value)
00398 {
00399     cp_splaynode *node = NULL;
00400 
00401     if (tree->mode & COLLECTION_MODE_COPY)
00402     {
00403         void *k = tree->key_copy ? (*tree->key_copy)(key) : key;
00404         if (k)
00405         {
00406             void *v = tree->value_copy ? (*tree->value_copy)(value) : value;
00407             if (v)
00408                 node = cp_splaynode_create(k, v, tree->mempool);
00409         }
00410     }
00411     else
00412         node = cp_splaynode_create(key, value, tree->mempool);
00413 
00414     if (node && (tree->mode & COLLECTION_MODE_MULTIPLE_VALUES))
00415     {
00416         cp_vector *m = cp_vector_create(1);
00417         if (m == NULL) 
00418         {
00419             cp_splaytree_destroy_node(tree, node);
00420             return NULL;
00421         }
00422 
00423         cp_vector_add_element(m, node->value);
00424         node->value = m;
00425     }
00426 
00427     return node;
00428 }
00429 
00430 /* update_splaynode - implement COLLECTION_MODE_COPY, COLLECTION_MODE_DEEP and
00431  * COLLECTION_MODE_MULTIPLE_VALUES when inserting a value for an existing key
00432  */
00433 static void *
00434     update_splaynode(cp_splaytree *tree, 
00435                      cp_splaynode *node, 
00436                      void *key, void *value)
00437 {
00438     void *new_key = key;
00439     void *new_value = value;
00440 
00441     if (tree->mode & COLLECTION_MODE_COPY)
00442     {
00443         if (tree->key_copy) 
00444         {
00445             new_key = (*tree->key_copy)(key);
00446             if (new_key == NULL) return NULL;
00447         }
00448         if (tree->value_copy)
00449         {
00450             new_value = (*tree->value_copy)(value);
00451             if (new_value == NULL) return NULL;
00452         }
00453     }
00454 
00455     if (tree->mode & COLLECTION_MODE_DEEP)
00456     {
00457         if (tree->key_dtr)
00458             (*tree->key_dtr)(node->key);
00459         if (tree->value_dtr && !(tree->mode & COLLECTION_MODE_MULTIPLE_VALUES))
00460             (*tree->value_dtr)(node->value);
00461     }
00462         
00463     node->key = new_key;
00464     if ((tree->mode & COLLECTION_MODE_MULTIPLE_VALUES))
00465     {
00466         cp_vector_add_element(node->value, new_value);
00467         return node->value;
00468     }
00469     else
00470         node->value = new_value;
00471 
00472     return new_value;
00473 }
00474 
00475 
00476 /* desplay - the splay balancing act on recursion fold 
00477  *
00478  * cp_splaytree divides the implementation of the splay operation between
00479  * the tree operations, which recursively walk the tree down to the object 
00480  * node, and the de-splay function, which performs splay rotations on the way
00481  * out of the recursion
00482  */
00483 static void desplay(cp_splaynode **node, int *splay_factor, int op)
00484 {
00485     switch (*splay_factor)
00486     {
00487         case 0: 
00488             *splay_factor += op;
00489             break;
00490 
00491         case -1:
00492             if (op == 0)
00493                 right_rotate(node);
00494             else
00495             {
00496                 if (op == -1)
00497                 {
00498                     right_rotate(node);
00499                     right_rotate(node);
00500                 }
00501                 else
00502                     right_left_rotate(node);
00503                 *splay_factor = 0;
00504             }
00505             break;
00506             
00507         case 1:
00508             if (op == 0)
00509                 left_rotate(node);
00510             else
00511             {
00512                 if (op == 1)
00513                 {
00514                     left_rotate(node);
00515                     left_rotate(node);
00516                 }
00517                 else
00518                     left_right_rotate(node);
00519                 *splay_factor = 0;
00520             }
00521             break;
00522     }
00523 }
00524 
00525 static void *
00526     splay_insert(cp_splaytree *tree, 
00527                  cp_splaynode **node, 
00528                  void *key, void *value,
00529                  int *splay_factor)
00530 {
00531     int cmp;
00532     void *res;
00533     
00534     if (*node == NULL)
00535     {
00536         *node = create_splaynode(tree, key, value);
00537         if (*node) 
00538         {
00539             tree->items++;
00540             return (*node)->value;
00541         }
00542         return NULL;
00543     }
00544 
00545     res = (*node)->value;
00546         
00547     cmp = tree->cmp((*node)->key, key);
00548     if (cmp == 0)   /* replace */
00549     {
00550         *splay_factor = 0;
00551         return update_splaynode(tree, *node, key, value);
00552     }
00553     else if (cmp > 0) /* go left */
00554     {
00555         res = splay_insert(tree, &(*node)->left, key, value, splay_factor);
00556         desplay(node, splay_factor, -1);
00557     }
00558     else /* go right*/
00559     {
00560         res = splay_insert(tree, &(*node)->right, key, value, splay_factor);
00561         desplay(node, splay_factor, 1);
00562     }
00563     
00564     return res;
00565 }
00566 
00567 void *cp_splaytree_insert(cp_splaytree *tree, void *key, void *value)
00568 {
00569     void *res;
00570     int splay_factor = 0;
00571     
00572     /* lock unless COLLECTION_MODE_NOSYNC is set or this thread owns the tx */
00573     if (cp_splaytree_txlock(tree, COLLECTION_LOCK_WRITE)) return NULL;
00574     
00575     res = splay_insert(tree, &tree->root, key, value, &splay_factor);
00576     desplay(&tree->root, &splay_factor, 0);
00577 
00578     /* unlock unless COLLECTION_MODE_NOSYNC set or this thread owns the tx */
00579     cp_splaytree_txunlock(tree);
00580     
00581     return res;
00582 }
00583 
00584 static void *
00585     splay_get(cp_splaytree *tree, 
00586               cp_splaynode **node, 
00587               void *key, 
00588               int *splay_factor)
00589 {
00590     int cmp;
00591     void *res;
00592     
00593     if (*node == NULL) return NULL;
00594 
00595     cmp = tree->cmp((*node)->key, key);
00596     if (cmp == 0)   /* found */
00597     {
00598         *splay_factor = 0;
00599         res = (*node)->value;
00600     }
00601     else if (cmp > 0) /* go left */
00602     {
00603         if ((res = splay_get(tree, &(*node)->left, key, splay_factor)))
00604             desplay(node, splay_factor, -1);
00605     }
00606     else /* go right*/
00607     {
00608         if ((res = splay_get(tree, &(*node)->right, key, splay_factor)))
00609             desplay(node, splay_factor, 1);
00610     }
00611     
00612     return res;
00613 }
00614 
00615 void *cp_splaytree_get(cp_splaytree *tree, void *key)
00616 {
00617     int splay_factor = 0;
00618     cp_splaynode **node = &tree->root;
00619     void *res = NULL;
00620 
00621     /* the search operation on a splay tree brings the requested mapping to
00622      * the root of the tree - this being the point to the splay tree data
00623      * structure. Since the tree structure may change, the tree must be locked
00624      * for writing here (unless COLLECTION_MODE_NOSYNC is set).
00625      */
00626     if (cp_splaytree_txlock(tree, COLLECTION_LOCK_WRITE)) return NULL;
00627 
00628     res = splay_get(tree, node, key, &splay_factor);
00629     desplay(node, &splay_factor, 0);
00630 
00631     /* unlock unless COLLECTION_MODE_NOSYNC set or this thread owns the tx */
00632     cp_splaytree_txunlock(tree);
00633 
00634     return res;
00635 }
00636     
00637 static void *
00638     splaytree_find_internal(cp_splaytree *tree, 
00639                             cp_splaynode *curr, 
00640                             void *key, 
00641                             cp_op op)
00642 {
00643     void *res = NULL;
00644 
00645     if (curr)
00646     {
00647         int cmp = tree->cmp(key, curr->key);
00648         if (cmp == 0)
00649         {
00650             if (op == CP_OP_NE)
00651             {
00652                 if (curr->right) return curr->right->value;
00653                 if (curr->left) return curr->left->value;
00654             }
00655 
00656             if (op == CP_OP_GT)
00657             {
00658                 if (curr->right)
00659                 {
00660                     curr = curr->right;
00661                     while (curr->left) curr = curr->left;
00662                 }
00663                 else
00664                     return NULL;
00665             }
00666 
00667             if (op == CP_OP_LT)
00668             {
00669                 if (curr->left)
00670                 {
00671                     curr = curr->left;
00672                     while (curr->right) curr = curr->right;
00673                 }
00674                 else
00675                     return NULL;
00676             }
00677 
00678             return curr->value;
00679         }
00680         else
00681         {
00682             if (op == CP_OP_NE) return curr->value;
00683             if (cmp > 0) 
00684                 res = splaytree_find_internal(tree, curr->right, key, op);
00685             else
00686                 res = splaytree_find_internal(tree, curr->left, key, op);
00687 
00688             if (res == NULL)
00689             {
00690                 if ((cmp > 0 && (op == CP_OP_LT || op == CP_OP_LE)) ||
00691                     (cmp < 0 && (op == CP_OP_GE || op == CP_OP_GT)))
00692                         res = curr->value;
00693             }
00694         }
00695     }
00696 
00697     return res;
00698 }
00699 
00700 void *cp_splaytree_find(cp_splaytree *tree, void *key, cp_op op)
00701 {
00702     void *res = NULL;
00703     if (op == CP_OP_EQ) return cp_splaytree_get(tree, key);
00704 
00705     /* lock unless COLLECTION_MODE_NOSYNC is set or this thread owns the tx */
00706     if (cp_splaytree_txlock(tree, COLLECTION_LOCK_READ)) return NULL;
00707 
00708     res = splaytree_find_internal(tree, tree->root, key, op);
00709 
00710     /* unlock unless COLLECTION_MODE_NOSYNC set or this thread owns the tx */
00711     cp_splaytree_txunlock(tree);
00712 
00713     return res;
00714 }
00715 
00716 int cp_splaytree_contains(cp_splaytree *tree, void *key)
00717 {
00718     return (cp_splaytree_get(tree, key) != NULL);
00719 }
00720 
00721 /* helper function for deletion */
00722 static void swap_node_content(cp_splaynode *a, cp_splaynode *b)
00723 {
00724     void *tmpkey, *tmpval;
00725 
00726     tmpkey = a->key;
00727     a->key = b->key;
00728     b->key = tmpkey;
00729     
00730     tmpval = a->value;
00731     a->value = b->value;
00732     b->value = tmpval;
00733 }
00734 
00735 static void *
00736     splay_delete(cp_splaytree *tree, 
00737                  cp_splaynode **node,
00738                  void *key, 
00739                  int *splay_factor)
00740 {
00741     void *res;
00742     int cmp;
00743     
00744     if ((*node) == NULL) 
00745     {
00746         *splay_factor = 0;
00747         return NULL;
00748     }
00749     
00750     cmp = (*tree->cmp)((*node)->key, key);
00751     if (cmp == 0)
00752     {
00753         cp_splaynode *x;
00754         res = (*node)->value;
00755         tree->items--;
00756         
00757         if ((*node)->right && (*node)->left)
00758         {
00759             cp_splaynode *surrogate = *node;
00760             node = &(*node)->right;
00761             while ((*node)->left) node = &(*node)->left;
00762             swap_node_content(*node, surrogate);
00763         }
00764 
00765         x = *node;
00766         if ((*node)->right)
00767             *node = (*node)->right;
00768         else
00769             *node = (*node)->left;
00770         cp_splaytree_destroy_node(tree, x);
00771         
00772         *splay_factor = 0;
00773     }
00774     else if (cmp > 0)
00775     {
00776         res = splay_delete(tree, &(*node)->left, key, splay_factor);
00777         desplay(node, splay_factor, -1);
00778     }
00779     else
00780     {
00781         res = splay_delete(tree, &(*node)->right, key, splay_factor);
00782         desplay(node, splay_factor, 1);
00783     }
00784 
00785     return res;
00786 }
00787                  
00788 void *cp_splaytree_delete(cp_splaytree *tree, void *key)
00789 {
00790     void *res = NULL;
00791     int splay_factor = 0;
00792     cp_splaynode **node;
00793 
00794     if (cp_splaytree_txlock(tree, COLLECTION_LOCK_WRITE)) return NULL;
00795     
00796     node = &tree->root;
00797 
00798     res = splay_delete(tree, node, key, &splay_factor);
00799     desplay(node, &splay_factor, 0);
00800 
00801     cp_splaytree_txunlock(tree);
00802     
00803     return res;
00804 }
00805 
00806 
00807 static int 
00808     splay_scan_pre_order(cp_splaynode *node, 
00809                          cp_callback_fn callback, 
00810                          void *prm)
00811 {
00812     int rc;
00813     
00814     if (node) 
00815     {
00816         if ((rc = (*callback)(node, prm))) return rc;
00817         if ((rc = splay_scan_pre_order(node->right, callback, prm))) return rc;
00818         if ((rc = splay_scan_pre_order(node->left, callback, prm))) return rc;
00819     }
00820 
00821     return 0;
00822 }
00823 
00824 int cp_splaytree_callback_preorder(cp_splaytree *tree, 
00825                                    cp_callback_fn callback, 
00826                                    void *prm)
00827 {
00828     int rc;
00829 
00830     if ((rc = cp_splaytree_txlock(tree, COLLECTION_LOCK_READ))) return rc;
00831     rc = splay_scan_pre_order(tree->root, callback, prm);
00832     cp_splaytree_txunlock(tree);
00833 
00834     return rc;
00835 }
00836 
00837 static int 
00838     splay_scan_in_order(cp_splaynode *node, cp_callback_fn callback, void *prm)
00839 {
00840     int rc;
00841     
00842     if (node) 
00843     {
00844         if ((rc = splay_scan_in_order(node->right, callback, prm))) return rc;
00845         if ((rc = (*callback)(node, prm))) return rc;
00846         if ((rc = splay_scan_in_order(node->left, callback, prm))) return rc;
00847     }
00848 
00849     return 0;
00850 }
00851 
00852 int cp_splaytree_callback(cp_splaytree *tree, 
00853                           cp_callback_fn callback, 
00854                           void *prm)
00855 {
00856     int rc;
00857 
00858     if ((rc = cp_splaytree_txlock(tree, COLLECTION_LOCK_READ))) return rc;
00859     rc = splay_scan_in_order(tree->root, callback, prm);
00860     cp_splaytree_txunlock(tree);
00861 
00862     return rc;
00863 }
00864 
00865 static int 
00866     splay_scan_post_order(cp_splaynode *node, 
00867                           cp_callback_fn callback, 
00868                           void *prm)
00869 {
00870     int rc;
00871     
00872     if (node) 
00873     {
00874         if ((rc = splay_scan_post_order(node->right, callback, prm))) return rc;
00875         if ((rc = splay_scan_post_order(node->left, callback, prm))) return rc;
00876         if ((rc = (*callback)(node, prm))) return rc;
00877     }
00878 
00879     return 0;
00880 }
00881 
00882 int cp_splaytree_callback_postorder(cp_splaytree *tree, 
00883                                     cp_callback_fn callback, 
00884                                     void *prm)
00885 {
00886     int rc;
00887 
00888     if ((rc = cp_splaytree_txlock(tree, COLLECTION_LOCK_READ))) return rc;
00889     rc = splay_scan_post_order(tree->root, callback, prm);
00890     cp_splaytree_txunlock(tree);
00891 
00892     return rc;
00893 }
00894 
00895 int cp_splaytree_count(cp_splaytree *tree)
00896 {
00897     return tree->items;
00898 }
00899 
00900 
00901 void cp_splaynode_print(cp_splaynode *node, int level)
00902 {
00903     int i;
00904     if (node->right) cp_splaynode_print(node->right, level + 1);
00905     for (i = 0; i < level; i++) printf("  . ");
00906     printf("[%s => %s]\n", (char *) node->key, (char *) node->value);
00907     if (node->left) cp_splaynode_print(node->left, level + 1);
00908 }
00909 
00910 void cp_splaynode_multi_print(cp_splaynode *node, int level)
00911 {
00912     int i;
00913     cp_vector *v = node->value;
00914     if (node->right) cp_splaynode_multi_print(node->right, level + 1);
00915     
00916     for (i = 0; i < level; i++) printf("  . ");
00917     printf("[%s => ", (char *) node->key);
00918 
00919     for (i = 0; i < cp_vector_size(v); i++)
00920         printf("%s; ", (char *) cp_vector_element_at(v, i));
00921 
00922     printf("]\n");
00923 
00924     if (node->left) cp_splaynode_multi_print(node->left, level + 1);
00925 }
00926 
00927 void cp_splaytree_dump(cp_splaytree *tree)
00928 {
00929     if (tree->root) 
00930     {
00931         if ((tree->mode & COLLECTION_MODE_MULTIPLE_VALUES))
00932             cp_splaynode_multi_print(tree->root, 0);
00933         else
00934             cp_splaynode_print(tree->root, 0);
00935     }
00936 }
00937 
00938 /* set tree to use given mempool or allocate a new one if pool is NULL */
00939 int cp_splaytree_use_mempool(cp_splaytree *tree, cp_mempool *pool)
00940 {
00941     int rc = 0;
00942     
00943     if ((rc = cp_splaytree_txlock(tree, COLLECTION_LOCK_WRITE))) return rc;
00944     
00945     if (pool)
00946     {
00947         if (pool->item_size < sizeof(cp_splaynode))
00948         {
00949             rc = EINVAL;
00950             goto DONE;
00951         }
00952         if (tree->mempool) 
00953         {
00954             if (tree->items) 
00955             {
00956                 rc = ENOTEMPTY;
00957                 goto DONE;
00958             }
00959             cp_mempool_destroy(tree->mempool);
00960         }
00961         cp_mempool_inc_refcount(pool);
00962         tree->mempool = pool;
00963     }
00964     else
00965     {
00966         tree->mempool = 
00967             cp_mempool_create_by_option(COLLECTION_MODE_NOSYNC, 
00968                                         sizeof(cp_splaynode), 0);
00969         if (tree->mempool == NULL) 
00970         {
00971             rc = ENOMEM;
00972             goto DONE;
00973         }
00974     }
00975 
00976 DONE:
00977     cp_splaytree_txunlock(tree);
00978     return rc;
00979 }
00980 
00981 
00982 /* set tree to use a shared memory pool */
00983 int cp_splaytree_share_mempool(cp_splaytree *tree, cp_shared_mempool *pool)
00984 {
00985     int rc;
00986 
00987     if ((rc = cp_splaytree_txlock(tree, COLLECTION_LOCK_WRITE))) return rc;
00988 
00989     if (tree->mempool)
00990     {
00991         if (tree->items)
00992         {
00993             rc = ENOTEMPTY;
00994             goto DONE;
00995         }
00996 
00997         cp_mempool_destroy(tree->mempool);
00998     }
00999 
01000     tree->mempool = cp_shared_mempool_register(pool, sizeof(cp_splaynode));
01001     if (tree->mempool == NULL) 
01002     {
01003         rc = ENOMEM;
01004         goto DONE;
01005     }
01006     
01007 DONE:
01008     cp_splaytree_txunlock(tree);
01009     return rc;
01010 }
01011 

Generated on Mon Dec 5 23:00:22 2011 for cprops by  doxygen 1.4.7