00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <errno.h>
00004
00005 #include "collection.h"
00006 #include "vector.h"
00007 #include "sorted_hash.h"
00008
00009 cp_sh_entry *cp_sh_entry_create(void *key, void *value, cp_mempool *pool)
00010 {
00011 cp_sh_entry *node;
00012
00013 if (pool)
00014 node = (cp_sh_entry *) cp_mempool_calloc(pool);
00015 else
00016 node = (cp_sh_entry *) calloc(1, sizeof(cp_sh_entry));
00017
00018 if (node == NULL) return NULL;
00019
00020 node->key = key;
00021 node->value = value;
00022
00023 return node;
00024 }
00025
00026
00027 static cp_sh_entry *create_sh_entry(cp_sorted_hash *tree, void *key, void *value)
00028 {
00029 if (tree->mode & COLLECTION_MODE_COPY)
00030 {
00031 void *k, *v;
00032 k = tree->key_copy ? (*tree->key_copy)(key) : key;
00033 if (k)
00034 {
00035 v = tree->value_copy ? (*tree->value_copy)(value) : value;
00036 if (v)
00037 {
00038 if (tree->mode & COLLECTION_MODE_MULTIPLE_VALUES)
00039 {
00040 cp_vector *m = cp_vector_create(1);
00041 if (m == NULL) return NULL;
00042 cp_vector_add_element(m, v);
00043 v = m;
00044 }
00045 return cp_sh_entry_create(k, v, tree->mempool);
00046 }
00047 }
00048 }
00049 else if (tree->mode & COLLECTION_MODE_MULTIPLE_VALUES)
00050 {
00051 cp_vector *m = cp_vector_create(1);
00052 if (m == NULL) return NULL;
00053 cp_vector_add_element(m, value);
00054 return cp_sh_entry_create(key, m, tree->mempool);
00055 }
00056 else
00057 return cp_sh_entry_create(key, value, tree->mempool);
00058
00059 return NULL;
00060 }
00061
00062 void cp_sorted_hash_destroy_entry_deep(cp_sorted_hash *owner, cp_sh_entry *node)
00063 {
00064 while (node)
00065 {
00066 if (node->right)
00067 {
00068 node = node->right;
00069 node->up->right = NULL;
00070 }
00071 else if (node->left)
00072 {
00073 node = node->left;
00074 node->up->left = NULL;
00075 }
00076 else
00077 {
00078 cp_sh_entry *tmp = node;
00079 if (node->multiple)
00080 {
00081 cp_sh_entry *m = node->multiple;
00082 cp_sh_entry *n;
00083 do
00084 {
00085 n = m->multiple;
00086 cp_sorted_hash_destroy_entry(owner, m);
00087 m = n;
00088 } while (m);
00089 }
00090 node = node->up;
00091 cp_sorted_hash_destroy_entry(owner, tmp);
00092 }
00093 }
00094 }
00095
00096 void cp_sorted_hash_destroy_entry(cp_sorted_hash *tree, cp_sh_entry *node)
00097 {
00098 if (node)
00099 {
00100 if ((tree->mode & COLLECTION_MODE_DEEP))
00101 {
00102 if (tree->key_dtr) (*tree->key_dtr)(node->key);
00103 if (tree->mode & COLLECTION_MODE_MULTIPLE_VALUES)
00104 {
00105 if (node->value)
00106 cp_vector_destroy_custom(node->value, tree->value_dtr);
00107 }
00108 else if (tree->value_dtr)
00109 (*tree->value_dtr)(node->value);
00110 }
00111 else if ((tree->mode & COLLECTION_MODE_MULTIPLE_VALUES) && node->value)
00112 cp_vector_destroy(node->value);
00113 if (tree->mempool)
00114 cp_mempool_free(tree->mempool, node);
00115 else
00116 free(node);
00117 }
00118 }
00119
00120
00121 cp_sorted_hash *cp_sorted_hash_create(cp_hashfunction hash,
00122 cp_compare_fn cmp_key,
00123 cp_mapping_cmp_fn cmp_mapping)
00124 {
00125 cp_sorted_hash *tree = calloc(1, sizeof(cp_sorted_hash));
00126 if (tree == NULL) return NULL;
00127
00128 tree->size = 11;
00129 tree->table = (cp_sh_entry **) calloc(tree->size, sizeof(cp_sh_entry));
00130 if (tree->table == NULL)
00131 {
00132 free(tree);
00133 return NULL;
00134 }
00135
00136 tree->mode = COLLECTION_MODE_NOSYNC;
00137 tree->hash = hash;
00138 tree->cmp_key = cmp_key;
00139 tree->cmp_mapping = cmp_mapping;
00140
00141 return tree;
00142 }
00143
00144
00145
00146
00147 cp_sorted_hash *
00148 cp_sorted_hash_create_by_option(int mode,
00149 unsigned long size_hint,
00150 cp_hashfunction hash,
00151 cp_compare_fn cmp_key,
00152 cp_mapping_cmp_fn cmp_mapping,
00153 cp_copy_fn key_copy,
00154 cp_destructor_fn key_dtr,
00155 cp_copy_fn val_copy,
00156 cp_destructor_fn val_dtr)
00157 {
00158 cp_sorted_hash *tree = calloc(1, sizeof(cp_sorted_hash));
00159 if (tree == NULL) return NULL;
00160
00161 tree->size = cp_hashtable_choose_size(size_hint);
00162 tree->table = (cp_sh_entry **) calloc(tree->size, sizeof(cp_sh_entry));
00163 if (tree->table == NULL)
00164 {
00165 free(tree);
00166 return NULL;
00167 }
00168
00169 tree->mode = COLLECTION_MODE_NOSYNC;
00170 tree->hash = hash;
00171 tree->cmp_key = cmp_key;
00172 tree->cmp_mapping = cmp_mapping;
00173
00174 tree->mode = mode;
00175 tree->key_copy = key_copy;
00176 tree->key_dtr = key_dtr;
00177 tree->value_copy = val_copy;
00178 tree->value_dtr = val_dtr;
00179
00180 if (!(mode & COLLECTION_MODE_NOSYNC))
00181 {
00182 tree->lock = malloc(sizeof(cp_lock));
00183 if (tree->lock == NULL)
00184 {
00185 cp_sorted_hash_destroy(tree);
00186 return NULL;
00187 }
00188 if (cp_lock_init(tree->lock, NULL) != 0)
00189 {
00190 cp_sorted_hash_destroy(tree);
00191 return NULL;
00192 }
00193 }
00194
00195 return tree;
00196 }
00197
00198
00199 void cp_sorted_hash_destroy(cp_sorted_hash *tree)
00200 {
00201 if (tree)
00202 {
00203 cp_sorted_hash_destroy_entry_deep(tree, tree->root);
00204 if (tree->lock)
00205 {
00206 cp_lock_destroy(tree->lock);
00207 free(tree->lock);
00208 }
00209 free(tree->table);
00210 free(tree);
00211 }
00212 }
00213
00214 void cp_sorted_hash_destroy_custom(cp_sorted_hash *tree,
00215 cp_destructor_fn key_dtr,
00216 cp_destructor_fn val_dtr)
00217 {
00218 tree->mode |= COLLECTION_MODE_DEEP;
00219 tree->key_dtr = key_dtr;
00220 tree->value_dtr = val_dtr;
00221 cp_sorted_hash_destroy(tree);
00222 }
00223
00224 static int cp_sorted_hash_lock_internal(cp_sorted_hash *tree, int type)
00225 {
00226 int rc;
00227
00228 switch (type)
00229 {
00230 case COLLECTION_LOCK_READ:
00231 rc = cp_lock_rdlock(tree->lock);
00232 break;
00233
00234 case COLLECTION_LOCK_WRITE:
00235 rc = cp_lock_wrlock(tree->lock);
00236 break;
00237
00238 case COLLECTION_LOCK_NONE:
00239 rc = 0;
00240 break;
00241
00242 default:
00243 rc = EINVAL;
00244 break;
00245 }
00246
00247
00248 if (rc) errno = rc;
00249
00250 return rc;
00251 }
00252
00253 static int cp_sorted_hash_unlock_internal(cp_sorted_hash *tree)
00254 {
00255 return cp_lock_unlock(tree->lock);
00256 }
00257
00258 int cp_sorted_hash_txlock(cp_sorted_hash *tree, int type)
00259 {
00260
00261
00262
00263
00264 if (tree->mode & COLLECTION_MODE_NOSYNC) return 0;
00265 if (tree->mode & COLLECTION_MODE_IN_TRANSACTION &&
00266 tree->txtype == COLLECTION_LOCK_WRITE)
00267 {
00268 cp_thread self = cp_thread_self();
00269 if (cp_thread_equal(self, tree->txowner)) return 0;
00270 }
00271 errno = 0;
00272 return cp_sorted_hash_lock_internal(tree, type);
00273 }
00274
00275 int cp_sorted_hash_txunlock(cp_sorted_hash *tree)
00276 {
00277 if (tree->mode & COLLECTION_MODE_NOSYNC) return 0;
00278 if (tree->mode & COLLECTION_MODE_IN_TRANSACTION &&
00279 tree->txtype == COLLECTION_LOCK_WRITE)
00280 {
00281 cp_thread self = cp_thread_self();
00282 if (cp_thread_equal(self, tree->txowner)) return 0;
00283 }
00284 return cp_sorted_hash_unlock_internal(tree);
00285 }
00286
00287
00288 int cp_sorted_hash_lock(cp_sorted_hash *tree, int type)
00289 {
00290 int rc;
00291 if ((tree->mode & COLLECTION_MODE_NOSYNC)) return EINVAL;
00292 if ((rc = cp_sorted_hash_lock_internal(tree, type))) return rc;
00293 tree->txtype = type;
00294 tree->txowner = cp_thread_self();
00295 tree->mode |= COLLECTION_MODE_IN_TRANSACTION;
00296 return 0;
00297 }
00298
00299
00300 int cp_sorted_hash_unlock(cp_sorted_hash *tree)
00301 {
00302 cp_thread self = cp_thread_self();
00303 if (tree->txowner == self)
00304 {
00305 tree->txowner = 0;
00306 tree->txtype = 0;
00307 tree->mode ^= COLLECTION_MODE_IN_TRANSACTION;
00308 }
00309 else if (tree->txtype == COLLECTION_LOCK_WRITE)
00310 return -1;
00311 return cp_sorted_hash_unlock_internal(tree);
00312 }
00313
00314
00315 int cp_sorted_hash_set_mode(cp_sorted_hash *tree, int mode)
00316 {
00317 int rc;
00318 int nosync;
00319
00320
00321 if ((tree->mode & COLLECTION_MODE_IN_TRANSACTION) &&
00322 (mode & COLLECTION_MODE_NOSYNC)) return EINVAL;
00323
00324 if (mode & COLLECTION_MODE_MULTIPLE_VALUES) return EINVAL;
00325
00326 if ((rc = cp_sorted_hash_txlock(tree, COLLECTION_LOCK_WRITE))) return rc;
00327
00328 nosync = tree->mode & COLLECTION_MODE_NOSYNC;
00329
00330 tree->mode |= mode;
00331
00332 if (!nosync)
00333 cp_sorted_hash_txunlock(tree);
00334
00335 return 0;
00336 }
00337
00338
00339
00340
00341
00342 int cp_sorted_hash_unset_mode(cp_sorted_hash *tree, int mode)
00343 {
00344 int rc;
00345 int nosync;
00346
00347
00348 if (mode & COLLECTION_MODE_MULTIPLE_VALUES) return EINVAL;
00349
00350 if ((rc = cp_sorted_hash_txlock(tree, COLLECTION_LOCK_WRITE))) return rc;
00351
00352 nosync = tree->mode & COLLECTION_MODE_NOSYNC;
00353
00354
00355 if ((mode & COLLECTION_MODE_NOSYNC) && tree->lock == NULL)
00356 {
00357
00358 if ((tree->lock = malloc(sizeof(cp_lock))) == NULL)
00359 return -1;
00360 if (cp_lock_init(tree->lock, NULL))
00361 return -1;
00362 }
00363
00364
00365 tree->mode &= tree->mode ^ mode;
00366 if (!nosync)
00367 cp_sorted_hash_txunlock(tree);
00368
00369 return 0;
00370 }
00371
00372 int cp_sorted_hash_get_mode(cp_sorted_hash *tree)
00373 {
00374 return tree->mode;
00375 }
00376
00377
00378 static cp_sh_entry *sibling(cp_sh_entry *node)
00379 {
00380 return node == node->up->left ? node->up->right : node->up->left;
00381 }
00382
00383 static int is_right_child(cp_sh_entry *node)
00384 {
00385 return (node->up->right == node);
00386 }
00387
00388 static int is_left_child(cp_sh_entry *node)
00389 {
00390 return (node->up->left == node);
00391 }
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402 static void left_rotate(cp_sorted_hash *tree, cp_sh_entry *p)
00403 {
00404 cp_sh_entry *q = p->right;
00405 cp_sh_entry **sup;
00406
00407 if (p->up)
00408 sup = is_left_child(p) ? &(p->up->left) : &(p->up->right);
00409 else
00410 sup = &tree->root;
00411
00412 p->right = q->left;
00413 if (p->right) p->right->up = p;
00414 q->left = p;
00415 q->up = p->up;
00416 p->up = q;
00417 *sup = q;
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429 static void right_rotate(cp_sorted_hash *tree, cp_sh_entry *p)
00430 {
00431 cp_sh_entry *q = p->left;
00432 cp_sh_entry **sup;
00433
00434 if (p->up)
00435 sup = is_left_child(p) ? &(p->up->left) : &(p->up->right);
00436 else
00437 sup = &tree->root;
00438
00439 p->left = q->right;
00440 if (p->left) p->left->up = p;
00441 q->right = p;
00442 q->up = p->up;
00443 p->up = q;
00444 *sup = q;
00445 }
00446
00447
00448
00449
00450
00451 static void rebalance(cp_sorted_hash *tree, cp_sh_entry *node)
00452 {
00453 cp_sh_entry *up = node->up;
00454 if (up == NULL || up->color == RB_BLACK) return;
00455 if (sibling(up) && sibling(up)->color == RB_RED)
00456 {
00457 up->color = RB_BLACK;
00458 sibling(up)->color = RB_BLACK;
00459 if (up->up->up)
00460 {
00461 up->up->color = RB_RED;
00462 rebalance(tree, up->up);
00463 }
00464 }
00465 else
00466 {
00467 if (is_left_child(node) && is_right_child(up))
00468 {
00469 right_rotate(tree, up);
00470 node = node->right;
00471 }
00472 else if (is_right_child(node) && is_left_child(up))
00473 {
00474 left_rotate(tree, up);
00475 node = node->left;
00476 }
00477
00478 node->up->color = RB_BLACK;
00479 node->up->up->color = RB_RED;
00480
00481 if (is_left_child(node))
00482 right_rotate(tree, node->up->up);
00483 else
00484 left_rotate(tree, node->up->up);
00485 }
00486 }
00487
00488
00489
00490
00491 static void *
00492 update_sh_entry(cp_sorted_hash *tree, cp_sh_entry *node, void *key, void *value)
00493 {
00494 void *new_key = key;
00495 void *new_value = value;
00496
00497 if (tree->mode & COLLECTION_MODE_COPY)
00498 {
00499 if (tree->key_copy)
00500 {
00501 new_key = (*tree->key_copy)(key);
00502 if (new_key == NULL) return NULL;
00503 }
00504 if (tree->value_copy)
00505 {
00506 new_value = (*tree->value_copy)(value);
00507 if (new_value == NULL) return NULL;
00508 }
00509 }
00510
00511 if (tree->mode & COLLECTION_MODE_DEEP)
00512 {
00513 if (tree->key_dtr)
00514 (*tree->key_dtr)(node->key);
00515 if (tree->value_dtr && !(tree->mode & COLLECTION_MODE_MULTIPLE_VALUES))
00516 (*tree->value_dtr)(node->value);
00517 }
00518
00519 node->key = new_key;
00520 if (tree->mode & COLLECTION_MODE_MULTIPLE_VALUES)
00521 {
00522 cp_vector_add_element(node->value, new_value);
00523 return node->value;
00524 }
00525 else
00526 node->value = new_value;
00527
00528 return new_value;
00529 }
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539 void *cp_sorted_hash_insert(cp_sorted_hash *tree, void *key, void *value)
00540 {
00541 void *res = NULL;
00542 cp_sh_entry *entry, **curr;
00543 void *ikey, *ivalue;
00544 unsigned long index;
00545
00546 if (cp_sorted_hash_txlock(tree, COLLECTION_LOCK_WRITE)) return NULL;
00547
00548 if (tree->mode & COLLECTION_MODE_COPY)
00549 {
00550 ikey = tree->key_copy ? (*tree->key_copy)(key) : key;
00551 ivalue = tree->value_copy ? (*tree->value_copy)(value) : value;
00552 }
00553 else
00554 {
00555 ikey = key;
00556 ivalue = value;
00557 }
00558
00559 entry = cp_sh_entry_create(ikey, ivalue, tree->mempool);
00560 if (entry == NULL) goto INSERT_DONE;
00561
00562 entry->code = (*tree->hash)(key);
00563 index = entry->code % tree->size;
00564
00565 curr = &tree->table[index];
00566 while (*curr)
00567 {
00568 if (!(tree->mode & COLLECTION_MODE_MULTIPLE_VALUES) &&
00569 (*tree->cmp_key)(key, (*curr)->key) == 0)
00570 {
00571 if (tree->mode & COLLECTION_MODE_DEEP)
00572 {
00573 if (tree->key_dtr) (*tree->key_dtr)((*curr)->key);
00574 if (tree->value_dtr) (*tree->value_dtr)((*curr)->value);
00575 }
00576 (*curr)->key = ikey;
00577 (*curr)->value = ivalue;
00578 cp_sorted_hash_destroy_entry(tree, entry);
00579 break;
00580 }
00581 curr = &(*curr)->bucket;
00582 }
00583
00584 if (*curr == NULL) *curr = entry;
00585
00586 if (tree->root == NULL)
00587 {
00588 tree->root = entry;
00589 res = value;
00590 tree->root->color = RB_BLACK;
00591 tree->items++;
00592 }
00593 else
00594 {
00595 int cmp;
00596 cp_sh_entry *prev = NULL;
00597 curr = &tree->root;
00598
00599 while (*curr)
00600 {
00601 prev = *curr;
00602 if (tree->cmp_mapping)
00603 {
00604 cmp = (*tree->cmp_mapping)((cp_mapping *) *curr,
00605 (cp_mapping *) entry);
00606 }
00607 else
00608 {
00609 cmp = (*tree->cmp_key)((*curr)->key, entry->key);
00610 }
00611
00612 if (cmp < 0)
00613 curr = &(*curr)->right;
00614 else if (cmp > 0)
00615 curr = &(*curr)->left;
00616 else
00617 {
00618 prev = *curr;
00619 curr = &(*curr)->multiple;
00620 while (*curr)
00621 {
00622 (*curr)->multiple_prev = prev;
00623 prev = *curr;
00624 curr = &(*curr)->multiple;
00625 }
00626 *curr = entry;
00627 entry->multiple_prev = NULL;
00628 res = entry->value;
00629 tree->items++;
00630 break;
00631 }
00632 }
00633
00634 if (*curr == NULL)
00635 {
00636 *curr = entry;
00637 if (*curr == NULL) goto INSERT_DONE;
00638 res = (*curr)->value;
00639 tree->items++;
00640 (*curr)->up = prev;
00641 rebalance(tree, *curr);
00642 }
00643 }
00644
00645 INSERT_DONE:
00646 cp_sorted_hash_txunlock(tree);
00647 return res;
00648 }
00649
00650
00651
00652
00653
00654 void *cp_sorted_hash_get(cp_sorted_hash *tree, void *key)
00655 {
00656 int c;
00657 unsigned long index;
00658 cp_sh_entry *curr;
00659 void *value = NULL;
00660
00661 if (cp_sorted_hash_txlock(tree, COLLECTION_LOCK_READ)) return NULL;
00662
00663 index = (*tree->hash)(key) % tree->size;
00664 curr = tree->table[index];
00665
00666 while (curr)
00667 {
00668 c = tree->cmp_key(curr->key, key);
00669 if (c == 0)
00670 {
00671 value = curr->value;
00672 break;
00673 }
00674 curr = curr->bucket;
00675 }
00676
00677 cp_sorted_hash_txunlock(tree);
00678 return value;;
00679 }
00680
00681
00682
00683
00684
00685 CPROPS_DLL
00686 void *cp_sorted_hash_find(cp_sorted_hash *tree, cp_mapping *mapping, cp_op op)
00687 {
00688 int cmp;
00689 unsigned long index;
00690 cp_sh_entry **curr;
00691 cp_sh_entry *prev;
00692 cp_sh_entry *res = NULL;
00693
00694 if (tree->root == NULL) return NULL;
00695
00696 if (cp_sorted_hash_txlock(tree, COLLECTION_LOCK_READ)) return NULL;
00697
00698 curr = &tree->root;
00699 while (*curr)
00700 {
00701 prev = *curr;
00702 if (tree->cmp_mapping)
00703 {
00704 cmp = (*tree->cmp_mapping)((cp_mapping *) *curr, mapping);
00705 }
00706 else
00707 {
00708 cmp = (*tree->cmp_key)((*curr)->key, mapping->key);
00709 }
00710
00711 if (cmp == 0) break;
00712 if (op == CP_OP_NE)
00713 {
00714 res = *curr;
00715 goto FIND_DONE;
00716 }
00717
00718 if (cmp < 0)
00719 curr = &(*curr)->right;
00720 else
00721 curr = &(*curr)->left;
00722 }
00723
00724 if (*curr)
00725 {
00726 if (op == CP_OP_EQ || op == CP_OP_LE || op == CP_OP_GE)
00727 {
00728 res = *curr;
00729 goto FIND_DONE;
00730 }
00731
00732 if (op == CP_OP_GT)
00733 {
00734 if ((*curr)->right)
00735 {
00736 curr = &(*curr)->right;
00737 while ((*curr)->left) curr = &(*curr)->left;
00738 res = *curr;
00739 }
00740 else
00741 {
00742 while ((*curr)->up)
00743 {
00744 prev = *curr;
00745 curr = &(*curr)->up;
00746 if ((*curr)->left == prev)
00747 {
00748 res = *curr;
00749 break;
00750 }
00751 }
00752 }
00753 }
00754 else
00755 {
00756 if ((*curr)->left)
00757 {
00758 curr = &(*curr)->left;
00759 while ((*curr)->right) curr = &(*curr)->right;
00760 res = *curr;
00761 }
00762 else
00763 {
00764 while ((*curr)->up)
00765 {
00766 prev = *curr;
00767 curr = &(*curr)->up;
00768 if ((*curr)->right == prev)
00769 {
00770 res = *curr;
00771 break;
00772 }
00773 }
00774 }
00775 }
00776
00777 goto FIND_DONE;
00778 }
00779
00780
00781 if (op == CP_OP_EQ) goto FIND_DONE;
00782
00783 if (op == CP_OP_LT || op == CP_OP_LE)
00784 {
00785 if (curr == &prev->right)
00786 {
00787 res = prev;
00788 goto FIND_DONE;
00789 }
00790
00791 while (prev)
00792 {
00793 if (prev->up && prev->up->right == prev)
00794 {
00795 res = prev->up;
00796 break;
00797 }
00798 prev = prev->up;
00799 }
00800 }
00801 else
00802 {
00803 if (curr == &prev->left)
00804 {
00805 res = prev;
00806 goto FIND_DONE;
00807 }
00808
00809 while (prev)
00810 {
00811 if (prev->up && prev->up->left == prev)
00812 {
00813 res = prev->up;
00814 break;
00815 }
00816 prev = prev->up;
00817 }
00818 }
00819
00820 FIND_DONE:
00821 cp_sorted_hash_txunlock(tree);
00822 return res->value;
00823 }
00824
00825 int cp_sorted_hash_contains(cp_sorted_hash *tree, void *key)
00826 {
00827 return (cp_sorted_hash_get(tree, key) != NULL);
00828 }
00829
00830
00831 static void swap_node_content(cp_sh_entry *a, cp_sh_entry *b)
00832 {
00833 void *tmpkey, *tmpval;
00834
00835 tmpkey = a->key;
00836 a->key = b->key;
00837 b->key = tmpkey;
00838
00839 tmpval = a->value;
00840 a->value = b->value;
00841 b->value = tmpval;
00842 }
00843
00844
00845
00846
00847
00848 static void rb_unlink(cp_sorted_hash *tree, cp_sh_entry *node)
00849 {
00850 if (node->multiple) node->multiple->multiple_prev = node->multiple_prev;
00851 if (node->multiple_prev) node->multiple_prev->multiple = node->multiple;
00852
00853 if (node->left)
00854 {
00855 node->left->up = node->up;
00856 if (node->up)
00857 {
00858 if (is_left_child(node))
00859 node->up->left = node->left;
00860 else
00861 node->up->right = node->left;
00862 }
00863 else
00864 tree->root = node->left;
00865 }
00866 else
00867 {
00868 if (node->right) node->right->up = node->up;
00869 if (node->up)
00870 {
00871 if (is_left_child(node))
00872 node->up->left = node->right;
00873 else
00874 node->up->right = node->right;
00875 }
00876 else
00877 tree->root = node->right;
00878 }
00879 }
00880
00881
00882 static void delete_rebalance(cp_sorted_hash *tree, cp_sh_entry *n)
00883 {
00884 if (n->up)
00885 {
00886 cp_sh_entry *sibl = sibling(n);
00887
00888 if (sibl->color == RB_RED)
00889 {
00890 n->up->color = RB_RED;
00891 sibl->color = RB_BLACK;
00892 if (is_left_child(n))
00893 left_rotate(tree, n->up);
00894 else
00895 right_rotate(tree, n->up);
00896 sibl = sibling(n);
00897 }
00898
00899 if (n->up->color == RB_BLACK &&
00900 sibl->color == RB_BLACK &&
00901 (sibl->left == NULL || sibl->left->color == RB_BLACK) &&
00902 (sibl->right == NULL || sibl->right->color == RB_BLACK))
00903 {
00904 sibl->color = RB_RED;
00905 delete_rebalance(tree, n->up);
00906 }
00907 else
00908 {
00909 if (n->up->color == RB_RED &&
00910 sibl->color == RB_BLACK &&
00911 (sibl->left == NULL || sibl->left->color == RB_BLACK) &&
00912 (sibl->right == NULL || sibl->right->color == RB_BLACK))
00913 {
00914 sibl->color = RB_RED;
00915 n->up->color = RB_BLACK;
00916 }
00917 else
00918 {
00919 if (is_left_child(n) &&
00920 sibl->color == RB_BLACK &&
00921 sibl->left && sibl->left->color == RB_RED &&
00922 (sibl->right == NULL || sibl->right->color == RB_BLACK))
00923 {
00924 sibl->color = RB_RED;
00925 sibl->left->color = RB_BLACK;
00926 right_rotate(tree, sibl);
00927
00928 sibl = sibling(n);
00929 }
00930 else if (is_right_child(n) &&
00931 sibl->color == RB_BLACK &&
00932 sibl->right && sibl->right->color == RB_RED &&
00933 (sibl->left == NULL || sibl->left->color == RB_BLACK))
00934 {
00935 sibl->color = RB_RED;
00936 sibl->right->color = RB_BLACK;
00937 left_rotate(tree, sibl);
00938
00939 sibl = sibling(n);
00940 }
00941
00942 sibl->color = n->up->color;
00943 n->up->color = RB_BLACK;
00944 if (is_left_child(n))
00945 {
00946 sibl->right->color = RB_BLACK;
00947 left_rotate(tree, n->up);
00948 }
00949 else
00950 {
00951 sibl->left->color = RB_BLACK;
00952 right_rotate(tree, n->up);
00953 }
00954 }
00955 }
00956 }
00957 }
00958
00959
00960 void *cp_sorted_hash_delete_impl(cp_sorted_hash *tree, void *key)
00961 {
00962 void *res = NULL;
00963 cp_sh_entry **table_node;
00964 unsigned long index;
00965 cp_sh_entry *node;
00966 int cmp;
00967
00968
00969 index = (*tree->hash)(key) % tree->size;
00970 table_node = &tree->table[index];
00971 while (*table_node && (*tree->cmp_key)((*table_node)->key, key))
00972 table_node = &(*table_node)->bucket;
00973
00974 node = *table_node;
00975
00976 if (node)
00977 {
00978 cp_sh_entry *child;
00979 res = node->value;
00980 tree->items--;
00981
00982 if (node->right && node->left)
00983 {
00984 cp_sh_entry *surrogate = node;
00985 node = node->right;
00986 while (node->left) node = node->left;
00987 swap_node_content(node, surrogate);
00988 }
00989 child = node->right ? node->right : node->left;
00990
00991
00992 if (node->color == RB_BLACK)
00993 {
00994 if (child)
00995 {
00996
00997 if (child->color == RB_RED)
00998 child->color = RB_BLACK;
00999 else
01000 delete_rebalance(tree, child);
01001 }
01002 else
01003 delete_rebalance(tree, node);
01004 }
01005
01006 *table_node = (*table_node)->bucket;
01007 rb_unlink(tree, node);
01008 cp_sorted_hash_destroy_entry(tree, node);
01009
01010 }
01011
01012 return res;
01013 }
01014
01015
01016
01017
01018 void *cp_sorted_hash_delete(cp_sorted_hash *tree, void *key)
01019 {
01020 void *res = NULL;
01021
01022 if (cp_sorted_hash_txlock(tree, COLLECTION_LOCK_WRITE)) return NULL;
01023
01024 res = cp_sorted_hash_delete_impl(tree, key);
01025
01026 cp_sorted_hash_txunlock(tree);
01027 return res;
01028 }
01029
01030 static int
01031 rb_scan_pre_order(cp_sh_entry *node, cp_callback_fn callback, void *prm)
01032 {
01033 int rc;
01034
01035 if (node)
01036 {
01037 if ((rc = (*callback)(node, prm))) return rc;
01038 if (node->multiple)
01039 {
01040 cp_sh_entry *multiple = node->multiple;
01041 do
01042 {
01043 if ((rc = (*callback)(multiple, prm))) return rc;
01044 multiple = multiple->multiple;
01045 } while (multiple);
01046 }
01047 if ((rc = rb_scan_pre_order(node->left, callback, prm))) return rc;
01048 if ((rc = rb_scan_pre_order(node->right, callback, prm))) return rc;
01049 }
01050
01051 return 0;
01052 }
01053
01054 int cp_sorted_hash_callback_preorder(cp_sorted_hash *tree,
01055 cp_callback_fn callback,
01056 void *prm)
01057 {
01058 int rc;
01059
01060 if ((rc = cp_sorted_hash_txlock(tree, COLLECTION_LOCK_READ))) return rc;
01061 rc = rb_scan_pre_order(tree->root, callback, prm);
01062 cp_sorted_hash_txunlock(tree);
01063
01064 return rc;
01065 }
01066
01067 static int
01068 rb_scan_in_order(cp_sh_entry *node, cp_callback_fn callback, void *prm)
01069 {
01070 int rc;
01071
01072 if (node)
01073 {
01074 if ((rc = rb_scan_in_order(node->left, callback, prm))) return rc;
01075 if ((rc = (*callback)(node, prm))) return rc;
01076 if (node->multiple)
01077 {
01078 cp_sh_entry *multiple = node->multiple;
01079 do
01080 {
01081 if ((rc = (*callback)(multiple, prm))) return rc;
01082 multiple = multiple->multiple;
01083 } while (multiple);
01084 }
01085 if ((rc = rb_scan_in_order(node->right, callback, prm))) return rc;
01086 }
01087
01088 return 0;
01089 }
01090
01091 int cp_sorted_hash_callback(cp_sorted_hash *tree,
01092 cp_callback_fn callback,
01093 void *prm)
01094 {
01095 int rc;
01096
01097 if ((rc = cp_sorted_hash_txlock(tree, COLLECTION_LOCK_READ))) return rc;
01098 rc = rb_scan_in_order(tree->root, callback, prm);
01099 cp_sorted_hash_txunlock(tree);
01100
01101 return rc;
01102 }
01103
01104 static int
01105 rb_scan_post_order(cp_sh_entry *node, cp_callback_fn callback, void *prm)
01106 {
01107 int rc;
01108
01109 if (node)
01110 {
01111 if ((rc = rb_scan_post_order(node->left, callback, prm))) return rc;
01112 if ((rc = rb_scan_post_order(node->right, callback, prm))) return rc;
01113 if ((rc = (*callback)(node, prm))) return rc;
01114 if (node->multiple)
01115 {
01116 cp_sh_entry *multiple = node->multiple;
01117 do
01118 {
01119 if ((rc = (*callback)(multiple, prm))) return rc;
01120 multiple = multiple->multiple;
01121 } while (multiple);
01122 }
01123 }
01124
01125 return 0;
01126 }
01127
01128 int cp_sorted_hash_callback_postorder(cp_sorted_hash *tree,
01129 cp_callback_fn callback,
01130 void *prm)
01131 {
01132 int rc;
01133
01134 if ((rc = cp_sorted_hash_txlock(tree, COLLECTION_LOCK_READ))) return rc;
01135 rc = rb_scan_post_order(tree->root, callback, prm);
01136 cp_sorted_hash_txunlock(tree);
01137
01138 return rc;
01139 }
01140
01141 int cp_sorted_hash_count(cp_sorted_hash *tree)
01142 {
01143 return tree->items;
01144 }
01145
01146
01147 void cp_sh_entry_print(cp_sh_entry *node, int level)
01148 {
01149 int i;
01150 if (node->right) cp_sh_entry_print(node->right, level + 1);
01151 for (i = 0; i < level; i++) printf(" . ");
01152 printf("(%d) [%s => %s]\n", node->color, (char *) node->key, (char *) node->value);
01153 if (node->left) cp_sh_entry_print(node->left, level + 1);
01154 }
01155
01156 void cp_sh_entry_multi_print(cp_sh_entry *node, int level)
01157 {
01158 int i;
01159 cp_vector *v = node->value;
01160 if (node->right) cp_sh_entry_multi_print(node->right, level + 1);
01161
01162 for (i = 0; i < level; i++) printf(" . ");
01163 printf("(%d) [%s => ", node->color, (char *) node->key);
01164
01165 for (i = 0; i < cp_vector_size(v); i++)
01166 printf("%s; ", (char *) cp_vector_element_at(v, i));
01167
01168 printf("]\n");
01169
01170 if (node->left) cp_sh_entry_multi_print(node->left, level + 1);
01171 }
01172
01173 void cp_sorted_hash_dump(cp_sorted_hash *tree)
01174 {
01175 if (tree->root)
01176 {
01177 if (tree->mode & COLLECTION_MODE_MULTIPLE_VALUES)
01178 cp_sh_entry_multi_print(tree->root, 0);
01179 else
01180 cp_sh_entry_print(tree->root, 0);
01181 }
01182 }
01183
01184
01185 int cp_sorted_hash_use_mempool(cp_sorted_hash *tree, cp_mempool *pool)
01186 {
01187 int rc = 0;
01188
01189 if ((rc = cp_sorted_hash_txlock(tree, COLLECTION_LOCK_WRITE))) return rc;
01190
01191 if (pool)
01192 {
01193 if (pool->item_size < sizeof(cp_sh_entry))
01194 {
01195 rc = EINVAL;
01196 goto DONE;
01197 }
01198 if (tree->mempool)
01199 {
01200 if (tree->items)
01201 {
01202 rc = ENOTEMPTY;
01203 goto DONE;
01204 }
01205 cp_mempool_destroy(tree->mempool);
01206 }
01207 cp_mempool_inc_refcount(pool);
01208 tree->mempool = pool;
01209 }
01210 else
01211 {
01212 tree->mempool =
01213 cp_mempool_create_by_option(COLLECTION_MODE_NOSYNC,
01214 sizeof(cp_sh_entry), 0);
01215 if (tree->mempool == NULL)
01216 {
01217 rc = ENOMEM;
01218 goto DONE;
01219 }
01220 }
01221
01222 DONE:
01223 cp_sorted_hash_txunlock(tree);
01224 return rc;
01225 }
01226
01227
01228
01229 int cp_sorted_hash_share_mempool(cp_sorted_hash *tree, cp_shared_mempool *pool)
01230 {
01231 int rc;
01232
01233 if ((rc = cp_sorted_hash_txlock(tree, COLLECTION_LOCK_WRITE))) return rc;
01234
01235 if (tree->mempool)
01236 {
01237 if (tree->items)
01238 {
01239 rc = ENOTEMPTY;
01240 goto DONE;
01241 }
01242
01243 cp_mempool_destroy(tree->mempool);
01244 }
01245
01246 tree->mempool = cp_shared_mempool_register(pool, sizeof(cp_sh_entry));
01247 if (tree->mempool == NULL)
01248 {
01249 rc = ENOMEM;
01250 goto DONE;
01251 }
01252
01253 DONE:
01254 cp_sorted_hash_txunlock(tree);
01255 return rc;
01256 }
01257