00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <string.h>
00004 #include <errno.h>
00005
00006 #include "collection.h"
00007 #include "vector.h"
00008 #include "multimap.h"
00009
00010 cp_index_map_node *
00011 cp_index_map_node_create(void *entry, cp_mempool *pool)
00012 {
00013 cp_index_map_node *node;
00014
00015 if (pool)
00016 node = (cp_index_map_node *) cp_mempool_calloc(pool);
00017 else
00018 node = (cp_index_map_node *) calloc(1, sizeof(cp_index_map_node));
00019
00020 if (node == NULL) return NULL;
00021
00022 node->entry = entry;
00023
00024 return node;
00025 }
00026
00027
00028 static cp_index_map_node *
00029 create_index_map_node(cp_index_map *tree, void *entry)
00030 {
00031 if (tree->mode & COLLECTION_MODE_COPY)
00032 {
00033 void *e;
00034 e = tree->owner->copy ? (*tree->owner->copy)(entry) : entry;
00035 if (e)
00036 {
00037 if ((tree->mode & COLLECTION_MODE_MULTIPLE_VALUES))
00038 {
00039 cp_vector *m = cp_vector_create(1);
00040 if (m == NULL) return NULL;
00041 cp_vector_add_element(m, e);
00042 e = m;
00043 }
00044
00045 return cp_index_map_node_create(e, tree->owner->mempool);
00046 }
00047 }
00048 else if ((tree->mode & COLLECTION_MODE_MULTIPLE_VALUES))
00049 {
00050 cp_vector *m = cp_vector_create(1);
00051 if (m == NULL) return NULL;
00052 cp_vector_add_element(m, entry);
00053 return cp_index_map_node_create(m, tree->owner->mempool);
00054 }
00055 else
00056 return cp_index_map_node_create(entry, tree->owner->mempool);
00057
00058 return NULL;
00059 }
00060
00061 void cp_index_map_destroy_node(cp_index_map *tree, cp_index_map_node *node)
00062 {
00063 if (node)
00064 {
00065 if ((tree->owner->mode & COLLECTION_MODE_DEEP))
00066 {
00067 if ((tree->mode & COLLECTION_MODE_MULTIPLE_VALUES) && node->entry)
00068 cp_vector_destroy_custom(node->entry, tree->owner->dtr);
00069 else if (tree->owner->dtr)
00070 (*tree->owner->dtr)(node->entry);
00071 }
00072 else if ((tree->mode & COLLECTION_MODE_MULTIPLE_VALUES) && node->entry)
00073 cp_vector_destroy(node->entry);
00074
00075 if (tree->owner->mempool)
00076 cp_mempool_free(tree->owner->mempool, node);
00077 else
00078 free(node);
00079 }
00080 }
00081
00082 void cp_index_map_drop_node(cp_index_map *tree, cp_index_map_node *node)
00083 {
00084 if (node)
00085 {
00086 if (tree->mode & COLLECTION_MODE_MULTIPLE_VALUES && node->entry)
00087 cp_vector_destroy(node->entry);
00088
00089 if (tree->owner->mempool)
00090 cp_mempool_free(tree->owner->mempool, node);
00091 else
00092 free(node);
00093 }
00094 }
00095
00096 void cp_index_map_drop_node_deep(cp_index_map *tree, cp_index_map_node *node)
00097 {
00098 if (node)
00099 {
00100 if (node->left)
00101 cp_index_map_drop_node_deep(tree, node->left);
00102 if (node->right)
00103 cp_index_map_drop_node_deep(tree, node->right);
00104 cp_index_map_drop_node(tree, node);
00105 }
00106 }
00107
00108 void cp_index_map_destroy_ref(cp_index_map *tree)
00109 {
00110 cp_index_map_drop_node_deep(tree, tree->root);
00111 free(tree);
00112 }
00113
00114 void cp_index_map_destroy_node_deep(cp_index_map *owner,
00115 cp_index_map_node *node)
00116 {
00117 while (node)
00118 {
00119 if (node->right)
00120 {
00121 node = node->right;
00122 node->up->right = NULL;
00123 }
00124 else if (node->left)
00125 {
00126 node = node->left;
00127 node->up->left = NULL;
00128 }
00129 else
00130 {
00131 cp_index_map_node *tmp = node;
00132 node = node->up;
00133 cp_index_map_destroy_node(owner, tmp);
00134 }
00135 }
00136 }
00137
00138 void cp_index_map_destroy(cp_index_map *tree)
00139 {
00140 if (tree)
00141 {
00142 cp_index_map_destroy_node_deep(tree, tree->root);
00143 free(tree);
00144 }
00145 }
00146
00147 void *cp_index_map_insert(cp_index_map *tree, void *entry);
00148
00149 cp_multimap *
00150 cp_multimap_create_by_option(int mode, cp_key_fn key,
00151 cp_compare_fn cmp, cp_copy_fn copy,
00152 cp_destructor_fn dtr)
00153 {
00154 cp_multimap *map = (cp_multimap *) calloc(1, sizeof(cp_multimap));
00155 if (map == NULL) goto CREATE_ERROR;
00156
00157 if (!(mode & COLLECTION_MODE_NOSYNC))
00158 {
00159 map->lock = (cp_lock *) malloc(sizeof(cp_lock));
00160 if (map->lock == NULL) goto CREATE_ERROR;
00161
00162 if (cp_lock_init(map->lock, NULL) != 0) goto CREATE_ERROR;
00163 }
00164
00165 map->mode = mode;
00166
00167 map->copy = copy;
00168 map->dtr = dtr;
00169
00170 map->default_index.type =
00171 (mode & COLLECTION_MODE_MULTIPLE_VALUES) ? CP_MULTIPLE : CP_UNIQUE;
00172 map->default_index.key = key;
00173 map->default_index.cmp = cmp;
00174
00175 map->default_map =
00176 cp_index_map_create(map, mode , &map->default_index);
00177 if (map->default_map == NULL) goto CREATE_ERROR;
00178
00179 map->index =
00180 cp_hashlist_create_by_option(COLLECTION_MODE_NOSYNC |
00181 COLLECTION_MODE_DEEP,
00182 3,
00183 cp_hash_addr, cp_hash_compare_addr,
00184 (cp_copy_fn) cp_index_copy, free,
00185 NULL,
00186 (cp_destructor_fn)
00187 cp_index_map_destroy_ref);
00188 if (map->index == NULL) goto CREATE_ERROR;
00189
00190 if (mode & COLLECTION_MODE_MULTIPLE_VALUES)
00191 {
00192 cp_index *primary_index = (cp_index *) calloc(1, sizeof(cp_index));
00193 if (primary_index == NULL) goto CREATE_ERROR;
00194 primary_index->type = CP_UNIQUE;
00195 primary_index->key = NULL;
00196 primary_index->cmp = cp_hash_compare_addr;
00197 map->primary =
00198 cp_index_map_create(map, mode & ~(COLLECTION_MODE_MULTIPLE_VALUES), primary_index);
00199 if (map->primary == NULL)
00200 {
00201 free(primary_index);
00202 goto CREATE_ERROR;
00203 }
00204
00205 cp_hashlist_append(map->index, &map->default_index, map->default_map);
00206 }
00207 else
00208 map->primary = map->default_map;
00209
00210 return map;
00211
00212 CREATE_ERROR:
00213 if (map)
00214 {
00215 if ((map->mode & COLLECTION_MODE_MULTIPLE_VALUES) &&
00216 map->primary != NULL)
00217 cp_index_map_destroy(map->primary);
00218 if (map->default_map) cp_index_map_destroy(map->default_map);
00219 if (map->index) cp_hashlist_destroy(map->index);
00220 if (map->lock) cp_lock_destroy(map->lock);
00221 free(map);
00222 }
00223 return NULL;
00224 }
00225
00226 cp_multimap *cp_multimap_create(cp_key_fn key_fn, cp_compare_fn cmp)
00227 {
00228 return cp_multimap_create_by_option(0, key_fn, cmp, NULL, NULL);
00229 }
00230
00231 void cp_multimap_destroy(cp_multimap *map)
00232 {
00233 if (map)
00234 {
00235 if ((map->mode & COLLECTION_MODE_MULTIPLE_VALUES))
00236 {
00237 free(map->primary->index);
00238 cp_hashlist_remove_by_option(map->index, &map->default_index, COLLECTION_MODE_NOSYNC);
00239 cp_hashlist_destroy(map->index);
00240 if (map->primary) cp_index_map_destroy(map->primary);
00241 if (map->default_map) cp_index_map_destroy_ref(map->default_map);
00242 }
00243 else
00244 {
00245 if (map->index) cp_hashlist_destroy(map->index);
00246 if (map->default_map) cp_index_map_destroy(map->default_map);
00247 }
00248 if (map->lock) cp_lock_destroy(map->lock);
00249 free(map);
00250 }
00251 }
00252
00253 void cp_multimap_destroy_custom(cp_multimap *map, cp_destructor_fn dtr)
00254 {
00255 if (map)
00256 {
00257 map->dtr = dtr;
00258 cp_multimap_destroy(map);
00259 }
00260 }
00261
00262 cp_index_map *
00263 cp_index_map_create(cp_multimap *owner, int mode, cp_index *index)
00264 {
00265 cp_index_map *tree;
00266
00267 if (index == NULL) return NULL;
00268
00269 tree = calloc(1, sizeof(cp_index_map));
00270 if (tree == NULL) return NULL;
00271
00272 tree->index = index;
00273 tree->mode = mode;
00274
00275 tree->owner = owner;
00276
00277 return tree;
00278 }
00279
00280 void cp_index_map_destroy_custom(cp_index_map *tree, cp_destructor_fn dtr)
00281 {
00282 tree->mode |= COLLECTION_MODE_DEEP;
00283 tree->owner->dtr = dtr;
00284 cp_index_map_destroy(tree);
00285 }
00286
00287 static int cp_multimap_lock_internal(cp_multimap *map, int type)
00288 {
00289 int rc;
00290
00291 switch (type)
00292 {
00293 case COLLECTION_LOCK_READ:
00294 rc = cp_lock_rdlock(map->lock);
00295 break;
00296
00297 case COLLECTION_LOCK_WRITE:
00298 rc = cp_lock_wrlock(map->lock);
00299 break;
00300
00301 case COLLECTION_LOCK_NONE:
00302 rc = 0;
00303 break;
00304
00305 default:
00306 rc = EINVAL;
00307 break;
00308 }
00309
00310
00311 if (rc) errno = rc;
00312
00313 return rc;
00314 }
00315
00316 static int cp_multimap_unlock_internal(cp_multimap *map)
00317 {
00318 return cp_lock_unlock(map->lock);
00319 }
00320
00321 int cp_multimap_txlock(cp_multimap *map, int type)
00322 {
00323
00324
00325
00326
00327 if (map->mode & COLLECTION_MODE_NOSYNC) return 0;
00328 if ((map->mode & COLLECTION_MODE_IN_TRANSACTION) &&
00329 map->txtype == COLLECTION_LOCK_WRITE)
00330 {
00331 cp_thread self = cp_thread_self();
00332 if (cp_thread_equal(self, map->txowner)) return 0;
00333 }
00334 errno = 0;
00335 return cp_multimap_lock_internal(map, type);
00336 }
00337
00338 int cp_multimap_txunlock(cp_multimap *map)
00339 {
00340 if (map->mode & COLLECTION_MODE_NOSYNC) return 0;
00341 if ((map->mode & COLLECTION_MODE_IN_TRANSACTION) &&
00342 map->txtype == COLLECTION_LOCK_WRITE)
00343 {
00344 cp_thread self = cp_thread_self();
00345 if (cp_thread_equal(self, map->txowner)) return 0;
00346 }
00347 return cp_multimap_unlock_internal(map);
00348 }
00349
00350
00351 int cp_multimap_lock(cp_multimap *map, int type)
00352 {
00353 int rc;
00354 if ((map->mode & COLLECTION_MODE_NOSYNC)) return EINVAL;
00355 if ((rc = cp_multimap_lock_internal(map, type))) return rc;
00356 map->txtype = type;
00357 map->txowner = cp_thread_self();
00358 map->mode |= COLLECTION_MODE_IN_TRANSACTION;
00359 return 0;
00360 }
00361
00362
00363 int cp_multimap_unlock(cp_multimap *map)
00364 {
00365 cp_thread self = cp_thread_self();
00366 if (map->txowner == self)
00367 {
00368 map->txowner = 0;
00369 map->txtype = 0;
00370 map->mode ^= COLLECTION_MODE_IN_TRANSACTION;
00371 }
00372 else if (map->txtype == COLLECTION_LOCK_WRITE)
00373 return -1;
00374 return cp_multimap_unlock_internal(map);
00375 }
00376
00377
00378 int cp_multimap_set_mode(cp_multimap *map, int mode)
00379 {
00380 int rc;
00381 int nosync;
00382
00383
00384 if ((map->mode & COLLECTION_MODE_IN_TRANSACTION) &&
00385 (mode & COLLECTION_MODE_NOSYNC)) return EINVAL;
00386
00387 if ((mode & COLLECTION_MODE_MULTIPLE_VALUES)) return EINVAL;
00388
00389 if ((rc = cp_multimap_txlock(map, COLLECTION_LOCK_WRITE))) return rc;
00390
00391 nosync = map->mode & COLLECTION_MODE_NOSYNC;
00392
00393 map->mode |= mode;
00394
00395 if (!nosync)
00396 cp_multimap_txunlock(map);
00397
00398 return 0;
00399 }
00400
00401
00402
00403
00404
00405 int cp_multimap_unset_mode(cp_multimap *map, int mode)
00406 {
00407 int rc;
00408 int nosync;
00409
00410
00411 if ((mode & COLLECTION_MODE_MULTIPLE_VALUES)) return EINVAL;
00412
00413 if ((rc = cp_multimap_txlock(map, COLLECTION_LOCK_WRITE))) return rc;
00414
00415 nosync = map->mode & COLLECTION_MODE_NOSYNC;
00416
00417
00418 if ((mode & COLLECTION_MODE_NOSYNC) && map->lock == NULL)
00419 {
00420
00421 if ((map->lock = malloc(sizeof(cp_lock))) == NULL)
00422 return -1;
00423 if (cp_lock_init(map->lock, NULL))
00424 return -1;
00425 }
00426
00427
00428 map->mode &= map->mode ^ mode;
00429 if (!nosync)
00430 cp_multimap_txunlock(map);
00431
00432 return 0;
00433 }
00434
00435 int cp_multimap_get_mode(cp_multimap *map)
00436 {
00437 return map->mode;
00438 }
00439
00440
00441 static cp_index_map_node *sibling(cp_index_map_node *node)
00442 {
00443 return (node->up != NULL ) && (node == node->up->left) ?
00444 node->up->right : node->up->left;
00445 }
00446
00447 static int is_right_child(cp_index_map_node *node)
00448 {
00449 return (node->up->right == node);
00450 }
00451
00452 static int is_left_child(cp_index_map_node *node)
00453 {
00454 return (node->up->left == node);
00455 }
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466 static void left_rotate(cp_index_map *tree, cp_index_map_node *p)
00467 {
00468 cp_index_map_node *q = p->right;
00469 cp_index_map_node **sup;
00470
00471 if (p->up)
00472 sup = is_left_child(p) ? &(p->up->left) : &(p->up->right);
00473 else
00474 sup = &tree->root;
00475
00476 p->right = q->left;
00477 if (p->right) p->right->up = p;
00478 q->left = p;
00479 q->up = p->up;
00480 p->up = q;
00481 *sup = q;
00482 }
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493 static void right_rotate(cp_index_map *tree, cp_index_map_node *p)
00494 {
00495 cp_index_map_node *q = p->left;
00496 cp_index_map_node **sup;
00497
00498 if (p->up)
00499 sup = is_left_child(p) ? &(p->up->left) : &(p->up->right);
00500 else
00501 sup = &tree->root;
00502
00503 p->left = q->right;
00504 if (p->left) p->left->up = p;
00505 q->right = p;
00506 q->up = p->up;
00507 p->up = q;
00508 *sup = q;
00509 }
00510
00511
00512
00513
00514
00515 static void rebalance(cp_index_map *tree, cp_index_map_node *node)
00516 {
00517 cp_index_map_node *up = node->up;
00518 if (up == NULL || up->color == MM_BLACK) return;
00519 if (sibling(up) && sibling(up)->color == MM_RED)
00520 {
00521 up->color = MM_BLACK;
00522 sibling(up)->color = MM_BLACK;
00523 if (up->up->up)
00524 {
00525 up->up->color = MM_RED;
00526 rebalance(tree, up->up);
00527 }
00528 }
00529 else
00530 {
00531 if (is_left_child(node) && is_right_child(up))
00532 {
00533 right_rotate(tree, up);
00534 node = node->right;
00535 }
00536 else if (is_right_child(node) && is_left_child(up))
00537 {
00538 left_rotate(tree, up);
00539 node = node->left;
00540 }
00541
00542 node->up->color = MM_BLACK;
00543 node->up->up->color = MM_RED;
00544
00545 if (is_left_child(node))
00546 right_rotate(tree, node->up->up);
00547 else
00548 left_rotate(tree, node->up->up);
00549 }
00550 }
00551
00552 void cp_index_map_drop(cp_index_map *tree, void *entry);
00553
00554 static void
00555 multimap_swap_secondaries(cp_multimap *map, void *before, void *after)
00556 {
00557 if (map->index)
00558 {
00559 cp_hashlist_iterator itr;
00560 if (cp_hashlist_iterator_init(&itr, map->index,
00561 COLLECTION_LOCK_NONE) == 0)
00562 {
00563 cp_index_map *curr;
00564 while ((curr = (cp_index_map *)
00565 cp_hashlist_iterator_next_value(&itr)))
00566 cp_index_map_drop(curr, before);
00567 cp_hashlist_iterator_release(&itr);
00568 }
00569 }
00570 }
00571
00572
00573
00574
00575
00576 static void *
00577 update_index_map_node(cp_index_map *tree,
00578 cp_index_map_node *node,
00579 void *entry)
00580 {
00581 void *before = node->entry;
00582 void *new_entry = entry;
00583
00584 if (tree->mode & COLLECTION_MODE_COPY)
00585 {
00586 if (tree->owner->copy)
00587 {
00588 new_entry = (*tree->owner->copy)(entry);
00589 if (new_entry == NULL) return NULL;
00590 }
00591 }
00592
00593 if (!(tree->mode & COLLECTION_MODE_MULTIPLE_VALUES))
00594 node->entry = new_entry;
00595 else
00596 {
00597 cp_vector_add_element(node->entry, new_entry);
00598 new_entry = node->entry;
00599 }
00600
00601
00602
00603
00604 if (tree->owner->primary == tree && new_entry != before)
00605 multimap_swap_secondaries(tree->owner, before, new_entry);
00606
00607 if (tree->mode & COLLECTION_MODE_DEEP)
00608 {
00609 if (tree->owner->dtr && !(tree->mode & COLLECTION_MODE_MULTIPLE_VALUES))
00610 (*tree->owner->dtr)(before);
00611 }
00612
00613 return new_entry;
00614 }
00615
00616 int cp_index_compare_internal(cp_index *index, void *a, void *b)
00617 {
00618 void *e;
00619 if (index->type == CP_UNIQUE)
00620 e = a;
00621 else
00622 {
00623 cp_vector *v = a;
00624 if (v && cp_vector_size(v))
00625 e = cp_vector_element_at(v, 0);
00626 #ifdef DEBUG
00627 else
00628 cp_error(CP_INVALID_VALUE, "empty multiple value node %p", a);
00629 #endif
00630 }
00631
00632 return index->key ?
00633 (*index->cmp)((*index->key)(e), (*index->key)(b)) :
00634 (*index->cmp)(e, b);
00635 }
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646 void *cp_index_map_insert(cp_index_map *tree, void *entry)
00647 {
00648 void *res = NULL;
00649
00650 if (tree->root == NULL)
00651 {
00652 tree->root = create_index_map_node(tree, entry);
00653 if (tree->root == NULL)
00654 {
00655 errno = CP_MEMORY_ALLOCATION_FAILURE;
00656 goto DONE;
00657 }
00658 res = tree->root->entry;
00659 tree->root->color = MM_BLACK;
00660 }
00661 else
00662 {
00663 int cmp;
00664 cp_index_map_node **curr = &tree->root;
00665 cp_index_map_node *prev = NULL;
00666
00667 while (*curr)
00668 {
00669 prev = *curr;
00670 cmp = cp_index_compare_internal(tree->index, (*curr)->entry, entry);
00671 if (cmp < 0)
00672 curr = &(*curr)->right;
00673 else if (cmp > 0)
00674 curr = &(*curr)->left;
00675 else
00676 {
00677 res = update_index_map_node(tree, *curr, entry);
00678 break;
00679 }
00680 }
00681
00682 if (*curr == NULL)
00683 {
00684 *curr = create_index_map_node(tree, entry);
00685 if (*curr == NULL) goto DONE;
00686 res = (*curr)->entry;
00687 (*curr)->up = prev;
00688 rebalance(tree, *curr);
00689 }
00690 }
00691
00692 DONE:
00693 return res;
00694 }
00695
00696 void *cp_index_map_get(cp_index_map *tree, void *entry);
00697
00698 int cp_multimap_match_unique(cp_multimap *map,
00699 void *entry,
00700 cp_index **index,
00701 void **existing)
00702 {
00703 void *res = NULL;
00704 int count = 0;
00705 cp_index_map *idx;
00706 cp_hashlist_iterator itr;
00707
00708
00709 if (map->default_map->index->type == CP_UNIQUE)
00710 if ((res = cp_multimap_get(map, entry)))
00711 {
00712 if (index) *index = map->default_map->index;
00713 if (existing) *existing = res;
00714 count = 1;
00715 }
00716
00717 cp_hashlist_iterator_init(&itr, map->index, COLLECTION_LOCK_NONE);
00718 while ((idx = (cp_index_map *) cp_hashlist_iterator_next_value(&itr)))
00719 {
00720 if (idx->index->type == CP_UNIQUE)
00721 if ((res = cp_index_map_get(idx, entry)))
00722 {
00723 if (count == 0)
00724 {
00725 if (index) *index = idx->index;
00726 if (existing) *existing = res;
00727 }
00728 count++;
00729 }
00730 }
00731 cp_hashlist_iterator_release(&itr);
00732
00733 return count;
00734 }
00735
00736 void *cp_index_map_delete(cp_index_map *tree, void *entry);
00737
00738 void *cp_multimap_insert(cp_multimap *map, void *entry, int *err)
00739 {
00740 void *res = NULL;
00741 void *dupl = NULL;
00742 cp_hashlist_iterator *itr = NULL;
00743 cp_hashlist_entry *idx;
00744
00745 if (cp_multimap_txlock(map, COLLECTION_LOCK_WRITE))
00746 {
00747 if (err != NULL) *err = CP_LOCK_FAILED;
00748 return NULL;
00749 }
00750
00751 if (cp_multimap_match_unique(map, entry, NULL, &res))
00752 {
00753 if (err != NULL) *err = CP_UNIQUE_INDEX_VIOLATION;
00754 goto DONE;
00755 }
00756
00757
00758 if ((res = cp_index_map_insert(map->primary, entry)) == NULL)
00759 {
00760 if (err != NULL) *err = CP_MEMORY_ALLOCATION_FAILURE;
00761 goto DONE;
00762 }
00763
00764
00765 itr = cp_hashlist_create_iterator(map->index, COLLECTION_MODE_NOSYNC);
00766 if (itr == NULL)
00767 {
00768 if (err != NULL) *err = errno;
00769 map->items++;
00770 goto DONE;
00771 }
00772
00773 while (idx = cp_hashlist_iterator_next(itr))
00774 if (cp_index_map_insert(idx->value, res) == NULL)
00775 {
00776 if (err != NULL) *err = CP_MEMORY_ALLOCATION_FAILURE;
00777 goto INSERT_ERROR;
00778 }
00779
00780 map->items++;
00781 goto DONE;
00782
00783
00784 INSERT_ERROR:
00785 if (itr)
00786 {
00787 cp_hashlist_entry *idx;
00788 while (idx = cp_hashlist_iterator_prev(itr))
00789 cp_index_map_drop(idx->value, entry);
00790 }
00791 cp_index_map_delete(map->primary, entry);
00792 if ((dupl != NULL) && (map->mode & COLLECTION_MODE_DEEP) && map->dtr)
00793 (*map->dtr)(dupl);
00794
00795 DONE:
00796 if (itr) cp_hashlist_iterator_destroy(itr);
00797 cp_multimap_txunlock(map);
00798 return res;
00799 }
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813 int cp_index_map_reindex(cp_index_map *tree, void *before, void *after)
00814 {
00815 int rc = 0;
00816 int cmp;
00817 cp_index_map_node **curr;
00818 cp_index_map_node *prev;
00819
00820 if (tree->root == NULL)
00821 {
00822 #ifdef DEBUG
00823 cp_error(CP_ITEM_DOES_NOT_EXIST, "can\'t reindex entry at %p", before);
00824 #endif
00825 return -1;
00826 }
00827
00828
00829 cp_index_map_drop(tree, before);
00830 if (tree->root == NULL)
00831 {
00832 tree->root = create_index_map_node(tree, after);
00833 if (tree->root == NULL)
00834 {
00835 #ifdef DEBUG
00836 cp_error(CP_MEMORY_ALLOCATION_FAILURE,
00837 "can\'t reindex entry at %p", before);
00838 #endif
00839 return -1;
00840 }
00841
00842 tree->root->color = MM_BLACK;
00843 return 0;
00844 }
00845
00846
00847 curr = &tree->root;
00848 prev = NULL;
00849 while (*curr)
00850 {
00851 prev = *curr;
00852 cmp = cp_index_compare_internal(tree->index, (*curr)->entry, after);
00853 if (cmp < 0)
00854 curr = &(*curr)->right;
00855 else if (cmp > 0)
00856 curr = &(*curr)->left;
00857 else
00858 {
00859 if ((tree->mode & COLLECTION_MODE_MULTIPLE_VALUES) == 0)
00860 (*curr)->entry = after;
00861 else
00862 cp_vector_add_element((*curr)->entry, after);
00863 break;
00864 }
00865 }
00866
00867 if (*curr == NULL)
00868 {
00869 *curr = create_index_map_node(tree, after);
00870 if (*curr == NULL)
00871 {
00872 #ifdef DEBUG
00873 int err = errno;
00874 cp_perror(CP_MEMORY_ALLOCATION_FAILURE, err,
00875 "can\'t create new node reindexing %p", before);
00876 #endif
00877 return -1;
00878 }
00879 (*curr)->up = prev;
00880 rebalance(tree, *curr);
00881 }
00882
00883 return 0;
00884 }
00885
00886
00887
00888
00889
00890 int cp_multimap_reindex(cp_multimap *map, void *before, void *after)
00891 {
00892 int rc;
00893 void *existing;
00894 cp_index *index;
00895 int violation_count;
00896
00897 if (cp_multimap_txlock(map, COLLECTION_LOCK_WRITE)) return CP_LOCK_FAILED;
00898
00899 violation_count = cp_multimap_match_unique(map, after, &index, &existing);
00900 if (violation_count > 2 ||
00901 (violation_count == 2 && existing != before))
00902 {
00903 return CP_UNIQUE_INDEX_VIOLATION;
00904 }
00905
00906 if (map->index)
00907 {
00908 cp_hashlist_iterator itr;
00909 if (cp_hashlist_iterator_init(&itr, map->index,
00910 COLLECTION_LOCK_NONE) == 0)
00911 {
00912 cp_index_map *curr;
00913 while ((curr = (cp_index_map *)
00914 cp_hashlist_iterator_next_value(&itr)))
00915 {
00916 if (cp_index_compare(curr->index, before, after))
00917 cp_index_map_reindex(curr, before, after);
00918 }
00919 cp_hashlist_iterator_release(&itr);
00920 }
00921 }
00922
00923 if (cp_index_compare(&map->default_index, before, after))
00924 cp_index_map_reindex(map->default_map, before, after);
00925
00926 cp_multimap_txunlock(map);
00927
00928 return 0;
00929 }
00930
00931
00932
00933
00934
00935 void *cp_index_map_get(cp_index_map *tree, void *entry)
00936 {
00937 cp_index_map_node *curr;
00938 void *res = NULL;
00939
00940 curr = tree->root;
00941 while (curr)
00942 {
00943 int c = cp_index_compare_internal(tree->index, curr->entry, entry);
00944 if (c == 0) return curr->entry;
00945 curr = (c > 0) ? curr->left : curr->right;
00946 }
00947
00948 if (curr) res = curr->entry;
00949
00950 return res;
00951 }
00952
00953 void *cp_multimap_get(cp_multimap *map, void *entry)
00954 {
00955 void *res = NULL;
00956
00957 if (cp_multimap_txlock(map, COLLECTION_LOCK_READ)) return NULL;
00958 res = cp_index_map_get(map->default_map, entry);
00959 cp_multimap_txunlock(map);
00960
00961 return res;
00962 }
00963
00964 void *cp_index_map_find(cp_index_map *tree, void *entry, cp_op op)
00965 {
00966 int cmp;
00967 cp_index_map_node **curr;
00968 cp_index_map_node *prev;
00969 cp_index_map_node *res = NULL;
00970
00971 if (tree->root == NULL) return NULL;
00972
00973 curr = &tree->root;
00974 while (*curr)
00975 {
00976 prev = *curr;
00977 cmp = cp_index_compare_internal(tree->index, (*curr)->entry, entry);
00978
00979 if (cmp == 0) break;
00980 if (op == CP_OP_NE)
00981 {
00982 res = *curr;
00983 goto FIND_DONE;
00984 }
00985
00986 if (cmp < 0)
00987 curr = &(*curr)->right;
00988 else
00989 curr = &(*curr)->left;
00990 }
00991
00992 if (*curr)
00993 {
00994 if (op == CP_OP_EQ || op == CP_OP_LE || op == CP_OP_GE)
00995 {
00996 res = *curr;
00997 goto FIND_DONE;
00998 }
00999
01000 if (op == CP_OP_GT)
01001 {
01002 if ((*curr)->right)
01003 {
01004 curr = &(*curr)->right;
01005 while ((*curr)->left) curr = &(*curr)->left;
01006 res = *curr;
01007 }
01008 else
01009 {
01010 while ((*curr)->up)
01011 {
01012 prev = *curr;
01013 curr = &(*curr)->up;
01014 if ((*curr)->left == prev)
01015 {
01016 res = *curr;
01017 break;
01018 }
01019 }
01020 }
01021 }
01022 else
01023 {
01024 if ((*curr)->left)
01025 {
01026 curr = &(*curr)->left;
01027 while ((*curr)->right) curr = &(*curr)->right;
01028 res = *curr;
01029 }
01030 else
01031 {
01032 while ((*curr)->up)
01033 {
01034 prev = *curr;
01035 curr = &(*curr)->up;
01036 if ((*curr)->right == prev)
01037 {
01038 res = *curr;
01039 break;
01040 }
01041 }
01042 }
01043 }
01044
01045 goto FIND_DONE;
01046 }
01047
01048
01049 if (op == CP_OP_EQ) goto FIND_DONE;
01050
01051 if (op == CP_OP_LT || op == CP_OP_LE)
01052 {
01053 if (curr == &prev->right)
01054 {
01055 res = prev;
01056 goto FIND_DONE;
01057 }
01058
01059 while (prev)
01060 {
01061 if (prev->up && prev->up->right == prev)
01062 {
01063 res = prev->up;
01064 break;
01065 }
01066 prev = prev->up;
01067 }
01068 }
01069 else
01070 {
01071 if (curr == &prev->left)
01072 {
01073 res = prev;
01074 goto FIND_DONE;
01075 }
01076
01077 while (prev)
01078 {
01079 if (prev->up && prev->up->left == prev)
01080 {
01081 res = prev->up;
01082 break;
01083 }
01084 prev = prev->up;
01085 }
01086 }
01087
01088 FIND_DONE:
01089 return res ? res->entry : NULL;
01090 }
01091
01092 void *cp_multimap_find(cp_multimap *map, void *entry, cp_op op)
01093 {
01094 void *res = NULL;
01095
01096 if (cp_multimap_txlock(map, COLLECTION_LOCK_READ)) return NULL;
01097 res = cp_index_map_find(map->default_map, entry, op);
01098 cp_multimap_txunlock(map);
01099
01100 return res;
01101 }
01102
01103 void *cp_multimap_find_by_index(cp_multimap *map,
01104 cp_index *index,
01105 void *entry,
01106 cp_op op)
01107 {
01108 void *res = NULL;
01109
01110 cp_index_map *tree = cp_hashlist_get(map->index, index);
01111 if (tree == NULL)
01112 {
01113 #ifdef DEBUG
01114 cp_error(CP_INVALID_VALUE,
01115 "request for search by unknown index %p", index);
01116 #endif
01117 return NULL;
01118 }
01119
01120 if (cp_multimap_txlock(map, COLLECTION_LOCK_READ)) return NULL;
01121 res = cp_index_map_find(tree, entry, op);
01122 cp_multimap_txunlock(map);
01123
01124 return res;
01125 }
01126
01127
01128 void *cp_multimap_get_by_index(cp_multimap *map, cp_index *index, void *entry)
01129 {
01130 void *res = NULL;
01131 cp_index_map *tree;
01132 if (index == NULL) return cp_multimap_get(map, entry);
01133
01134 if (cp_multimap_txlock(map, COLLECTION_LOCK_READ)) return NULL;
01135
01136 #ifdef DEBUG
01137 if (map->index == NULL)
01138 {
01139 cp_error(CP_INVALID_VALUE, "no secondary indices set on multimap");
01140 return NULL;
01141 }
01142 #endif
01143
01144 tree = cp_hashlist_get(map->index, index);
01145 if (tree)
01146 res = cp_index_map_get(tree, entry);
01147 #ifdef DEBUG
01148 else
01149 cp_error(CP_INVALID_VALUE,
01150 "request for lookup by unknown index %p", index);
01151 #endif
01152 cp_multimap_txunlock(map);
01153
01154 return res;
01155 }
01156
01157 int cp_index_map_contains(cp_index_map *tree, void *entry)
01158 {
01159 return (cp_index_map_get(tree, entry) != NULL);
01160 }
01161
01162
01163 CPROPS_DLL
01164 int cp_multimap_contains(cp_multimap *map, void *entry)
01165 {
01166 int res = 0;
01167 cp_index_map *idx;
01168 cp_hashlist_iterator itr;
01169
01170
01171 if (cp_multimap_get(map, entry) != NULL) return 1;
01172
01173 cp_hashlist_iterator_init(&itr, map->index, COLLECTION_LOCK_NONE);
01174 while ((idx = (cp_index_map *) cp_hashlist_iterator_next_value(&itr)))
01175 {
01176 if (cp_index_map_get(idx, entry) != NULL)
01177 {
01178 res = 1;
01179 break;
01180 }
01181 }
01182 cp_hashlist_iterator_release(&itr);
01183
01184 return res;
01185 }
01186
01187
01188
01189 static void swap_node_content(cp_index_map_node *a, cp_index_map_node *b)
01190 {
01191 void *tmp;
01192
01193 tmp = a->entry;
01194 a->entry = b->entry;
01195 b->entry = tmp;
01196 }
01197
01198
01199
01200
01201
01202 static void index_map_unlink(cp_index_map *tree, cp_index_map_node *node)
01203 {
01204 if (node->left)
01205 {
01206 node->left->up = node->up;
01207 if (node->up)
01208 {
01209 if (is_left_child(node))
01210 node->up->left = node->left;
01211 else
01212 node->up->right = node->left;
01213 }
01214 else
01215 tree->root = node->left;
01216 }
01217 else
01218 {
01219 if (node->right) node->right->up = node->up;
01220 if (node->up)
01221 {
01222 if (is_left_child(node))
01223 node->up->left = node->right;
01224 else
01225 node->up->right = node->right;
01226 }
01227 else
01228 tree->root = node->right;
01229 }
01230 }
01231
01232
01233 static void delete_rebalance(cp_index_map *tree, cp_index_map_node *n)
01234 {
01235 if (n->up)
01236 {
01237 cp_index_map_node *sibl = sibling(n);
01238
01239 if (sibl->color == MM_RED)
01240 {
01241 n->up->color = MM_RED;
01242 sibl->color = MM_BLACK;
01243 if (is_left_child(n))
01244 left_rotate(tree, n->up);
01245 else
01246 right_rotate(tree, n->up);
01247 sibl = sibling(n);
01248 }
01249
01250 if (n->up->color == MM_BLACK &&
01251 sibl->color == MM_BLACK &&
01252 (sibl->left == NULL || sibl->left->color == MM_BLACK) &&
01253 (sibl->right == NULL || sibl->right->color == MM_BLACK))
01254 {
01255 sibl->color = MM_RED;
01256 delete_rebalance(tree, n->up);
01257 }
01258 else
01259 {
01260 if (n->up->color == MM_RED &&
01261 sibl->color == MM_BLACK &&
01262 (sibl->left == NULL || sibl->left->color == MM_BLACK) &&
01263 (sibl->right == NULL || sibl->right->color == MM_BLACK))
01264 {
01265 sibl->color = MM_RED;
01266 n->up->color = MM_BLACK;
01267 }
01268 else
01269 {
01270 if (is_left_child(n) &&
01271 sibl->color == MM_BLACK &&
01272 sibl->left && sibl->left->color == MM_RED &&
01273 (sibl->right == NULL || sibl->right->color == MM_BLACK))
01274 {
01275 sibl->color = MM_RED;
01276 sibl->left->color = MM_BLACK;
01277 right_rotate(tree, sibl);
01278
01279 sibl = sibling(n);
01280 }
01281 else if (is_right_child(n) &&
01282 sibl->color == MM_BLACK &&
01283 sibl->right && sibl->right->color == MM_RED &&
01284 (sibl->left == NULL || sibl->left->color == MM_BLACK))
01285 {
01286 sibl->color = MM_RED;
01287 sibl->right->color = MM_BLACK;
01288 left_rotate(tree, sibl);
01289
01290 sibl = sibling(n);
01291 }
01292
01293 sibl->color = n->up->color;
01294 n->up->color = MM_BLACK;
01295 if (is_left_child(n))
01296 {
01297 sibl->right->color = MM_BLACK;
01298 left_rotate(tree, n->up);
01299 }
01300 else
01301 {
01302 sibl->left->color = MM_BLACK;
01303 right_rotate(tree, n->up);
01304 }
01305 }
01306 }
01307 }
01308 }
01309
01310
01311
01312
01313 void *cp_index_map_delete(cp_index_map *tree, void *entry)
01314 {
01315 void *res = NULL;
01316 cp_index_map_node *node;
01317 int cmp;
01318
01319 node = tree->root;
01320 while (node)
01321 {
01322 cmp = cp_index_compare_internal(tree->index, node->entry, entry);
01323 if (cmp < 0)
01324 node = node->right;
01325 else if (cmp > 0)
01326 node = node->left;
01327 else
01328 break;
01329 }
01330
01331 if (node)
01332 {
01333 cp_index_map_node *child;
01334 res = node->entry;
01335
01336 if (node->right && node->left)
01337 {
01338 cp_index_map_node *surrogate = node;
01339 node = node->right;
01340 while (node->left) node = node->left;
01341 swap_node_content(node, surrogate);
01342 }
01343 child = node->right ? node->right : node->left;
01344
01345
01346 if (node->color == MM_BLACK)
01347 {
01348 if (child)
01349 {
01350
01351 if (child->color == MM_RED)
01352 child->color = MM_BLACK;
01353 else
01354 delete_rebalance(tree, child);
01355 }
01356 else
01357 delete_rebalance(tree, node);
01358 }
01359
01360 index_map_unlink(tree, node);
01361 cp_index_map_destroy_node(tree, node);
01362 }
01363
01364 return res;
01365 }
01366
01367
01368
01369
01370
01371 void cp_index_map_drop(cp_index_map *tree, void *entry)
01372 {
01373 cp_index_map_node *node;
01374 int cmp;
01375
01376 node = tree->root;
01377 while (node)
01378 {
01379 cmp = cp_index_compare_internal(tree->index, node->entry, entry);
01380 if (cmp < 0)
01381 node = node->right;
01382 else if (cmp > 0)
01383 node = node->left;
01384 else
01385 break;
01386 }
01387
01388 if (node)
01389 {
01390 cp_index_map_node *child;
01391
01392
01393 if (tree->index->type == CP_MULTIPLE)
01394 {
01395 int i;
01396 cp_vector *v = node->entry;
01397 int size = cp_vector_size(v);
01398
01399 for (i = 0; i < size; i++)
01400 if (cp_vector_element_at(v, i) == entry)
01401 {
01402 cp_vector_remove_element_at(v, i);
01403 break;
01404 }
01405
01406
01407 if (cp_vector_size(v)) return;
01408 }
01409
01410 if (node->right && node->left)
01411 {
01412 cp_index_map_node *surrogate = node;
01413 node = node->right;
01414 while (node->left) node = node->left;
01415 swap_node_content(node, surrogate);
01416 }
01417 child = node->right ? node->right : node->left;
01418
01419
01420 if (node->color == MM_BLACK)
01421 {
01422 if (child)
01423 {
01424
01425 if (child->color == MM_RED)
01426 child->color = MM_BLACK;
01427 else
01428 delete_rebalance(tree, child);
01429 }
01430 else
01431 delete_rebalance(tree, node);
01432 }
01433
01434 index_map_unlink(tree, node);
01435 cp_index_map_drop_node(tree, node);
01436 }
01437 }
01438
01439
01440 void cp_multimap_drop(cp_multimap *map,
01441 cp_index *index,
01442 void *entry)
01443 {
01444 cp_hashlist_iterator *itr = NULL;
01445
01446 if (map->index)
01447 itr = cp_hashlist_create_iterator(map->index, COLLECTION_LOCK_NONE);
01448
01449 if (itr)
01450 {
01451 cp_hashlist_entry *idx;
01452
01453 while (idx = cp_hashlist_iterator_next(itr))
01454 if (idx->key != index && idx->key != &map->default_index) cp_index_map_drop(idx->value, entry);
01455
01456 cp_hashlist_iterator_destroy(itr);
01457 }
01458
01459 if (index)
01460 cp_index_map_drop(map->default_map, entry);
01461 }
01462
01463
01464
01465
01466 void *cp_multimap_remove(cp_multimap *map, void *entry)
01467 {
01468 void *res = NULL;
01469 int count = 0;
01470
01471 if (cp_multimap_txlock(map, COLLECTION_LOCK_WRITE)) return NULL;
01472
01473 if (0)
01474 {
01475 int i;
01476 cp_vector *v = cp_index_map_get(map->primary, entry);
01477 if (v)
01478 {
01479 res = v;
01480 count = cp_vector_size(v);
01481 for (i = 0; i < count; i++)
01482 {
01483 void *element = cp_vector_element_at(v, i);
01484 cp_multimap_drop(map, NULL, element);
01485 cp_index_map_delete(map->primary, element);
01486 }
01487 }
01488 }
01489 else
01490 {
01491 void *e = cp_index_map_get(map->primary, entry);
01492 if (e)
01493 {
01494 res = e;
01495 cp_multimap_drop(map, NULL, e);
01496
01497 count = 1;
01498 }
01499 }
01500
01501 if (count)
01502 map->items -= count;
01503
01504 cp_multimap_txunlock(map);
01505
01506 return res;
01507 }
01508
01509
01510
01511
01512
01513 void *cp_multimap_remove_by_index(cp_multimap *map,
01514 cp_index *index,
01515 void *entry)
01516 {
01517 void *res = NULL;
01518 cp_index_map *lookup;
01519 int count = 0;
01520
01521 if (index == NULL)
01522 return cp_multimap_remove(map, entry);
01523
01524 if (cp_multimap_txlock(map, COLLECTION_LOCK_WRITE)) return NULL;
01525
01526 lookup = cp_hashlist_get(map->index, index);
01527 #ifdef DEBUG
01528 if (lookup == NULL)
01529 {
01530 cp_error(CP_INVALID_VALUE,
01531 "request for removal by unknown index %p", index);
01532 goto DELETE_DONE;
01533 }
01534 #endif
01535
01536 if (lookup->mode & COLLECTION_MODE_MULTIPLE_VALUES)
01537 {
01538 int i;
01539 cp_vector *v = cp_index_map_get(lookup, entry);
01540 if (v)
01541 {
01542 res = v;
01543 count = cp_vector_size(v);
01544 for (i = 0; i < count; i++)
01545 cp_multimap_drop(map, index, cp_vector_element_at(v, i));
01546 }
01547 }
01548 else
01549 {
01550 void *e = cp_index_map_get(lookup, entry);
01551 if (e)
01552 {
01553 res = e;
01554 cp_multimap_drop(map, index, e);
01555 count = 1;
01556 }
01557 }
01558
01559 if (count)
01560 {
01561 cp_index_map_delete(lookup, entry);
01562 map->items -= count;
01563 }
01564
01565 #ifdef DEBUG
01566 DELETE_DONE:
01567 #endif
01568 cp_multimap_txunlock(map);
01569
01570 return res;
01571 }
01572
01573 static int
01574 index_map_scan_pre_order(cp_index_map_node *node,
01575 cp_callback_fn callback,
01576 void *prm)
01577 {
01578 int rc;
01579
01580 if (node)
01581 {
01582 if ((rc = (*callback)(node, prm))) return rc;
01583 if ((rc = index_map_scan_pre_order(node->left, callback, prm))) return rc;
01584 if ((rc = index_map_scan_pre_order(node->right, callback, prm))) return rc;
01585 }
01586
01587 return 0;
01588 }
01589
01590 int cp_multimap_callback_preorder(cp_multimap *map,
01591 cp_callback_fn callback,
01592 void *prm)
01593 {
01594 int rc;
01595
01596 if ((rc = cp_multimap_txlock(map, COLLECTION_LOCK_READ))) return rc;
01597 rc = index_map_scan_pre_order(map->default_map->root, callback, prm);
01598 cp_multimap_txunlock(map);
01599
01600 return rc;
01601 }
01602
01603 static int
01604 index_map_scan_in_order(cp_index_map_node *node,
01605 cp_callback_fn callback,
01606 void *prm)
01607 {
01608 int rc;
01609
01610 if (node)
01611 {
01612 if ((rc = index_map_scan_in_order(node->left, callback, prm))) return rc;
01613 if ((rc = (*callback)(node, prm))) return rc;
01614 if ((rc = index_map_scan_in_order(node->right, callback, prm))) return rc;
01615 }
01616
01617 return 0;
01618 }
01619
01620 int cp_multimap_callback(cp_multimap *map, cp_callback_fn callback, void *prm)
01621 {
01622 int rc;
01623
01624 if ((rc = cp_multimap_txlock(map, COLLECTION_LOCK_READ))) return rc;
01625 rc = index_map_scan_in_order(map->default_map->root, callback, prm);
01626 cp_multimap_txunlock(map);
01627
01628 return rc;
01629 }
01630
01631 int cp_multimap_callback_by_index(cp_multimap *map,
01632 cp_index *index,
01633 cp_callback_fn callback,
01634 void *prm)
01635 {
01636 int rc;
01637 cp_index_map *imap;
01638
01639 if (index == NULL) return cp_multimap_callback(map, callback, prm);
01640
01641 if ((rc = cp_multimap_txlock(map, COLLECTION_LOCK_READ))) return rc;
01642
01643 imap = cp_hashlist_get(map->index, index);
01644 if (imap == NULL)
01645 rc = -1;
01646 else
01647 rc = index_map_scan_in_order(imap->root, callback, prm);
01648 cp_multimap_txunlock(map);
01649
01650 return rc;
01651 }
01652
01653
01654
01655 static int
01656 index_map_scan_post_order(cp_index_map_node *node, cp_callback_fn callback, void *prm)
01657 {
01658 int rc;
01659
01660 if (node)
01661 {
01662 if ((rc = index_map_scan_post_order(node->left, callback, prm))) return rc;
01663 if ((rc = index_map_scan_post_order(node->right, callback, prm))) return rc;
01664 if ((rc = (*callback)(node, prm))) return rc;
01665 }
01666
01667 return 0;
01668 }
01669
01670 int cp_multimap_callback_postorder(cp_multimap *map,
01671 cp_callback_fn callback,
01672 void *prm)
01673 {
01674 int rc;
01675
01676 if ((rc = cp_multimap_txlock(map, COLLECTION_LOCK_READ))) return rc;
01677 rc = index_map_scan_post_order(map->default_map->root, callback, prm);
01678 cp_multimap_txunlock(map);
01679
01680 return rc;
01681 }
01682
01683 int cp_multimap_count(cp_multimap *tree)
01684 {
01685 return tree->items;
01686 }
01687
01688
01689 void cp_index_map_node_print(cp_index_map_node *node, int level)
01690 {
01691 int i;
01692 if (node->right) cp_index_map_node_print(node->right, level + 1);
01693 for (i = 0; i < level; i++) printf(" . ");
01694 printf("(%d) [%s]\n", node->color, (char *) node->entry);
01695 if (node->left) cp_index_map_node_print(node->left, level + 1);
01696 }
01697
01698 void cp_index_map_node_multi_print(cp_index_map_node *node, int level)
01699 {
01700 int i;
01701 cp_vector *v = node->entry;
01702 if (node->right) cp_index_map_node_multi_print(node->right, level + 1);
01703
01704 for (i = 0; i < level; i++) printf(" . ");
01705 printf("(%d) [ ", node->color);
01706
01707 for (i = 0; i < cp_vector_size(v); i++)
01708 printf("%s; ", (char *) cp_vector_element_at(v, i));
01709
01710 printf("]\n");
01711
01712 if (node->left) cp_index_map_node_multi_print(node->left, level + 1);
01713 }
01714
01715 void cp_multimap_dump(cp_multimap *map)
01716 {
01717 if (map->default_map->root)
01718 {
01719 if ((map->mode & COLLECTION_MODE_MULTIPLE_VALUES))
01720 cp_index_map_node_multi_print(map->default_map->root, 0);
01721 else
01722 cp_index_map_node_print(map->default_map->root, 0);
01723 }
01724 }
01725
01726
01727 int cp_multimap_use_mempool(cp_multimap *map, cp_mempool *pool)
01728 {
01729 int rc = 0;
01730
01731 if ((rc = cp_multimap_txlock(map, COLLECTION_LOCK_WRITE))) return rc;
01732
01733 if (pool)
01734 {
01735 if (pool->item_size < sizeof(cp_index_map_node))
01736 {
01737 rc = EINVAL;
01738 goto DONE;
01739 }
01740 if (map->mempool)
01741 {
01742 if (map->items)
01743 {
01744 rc = ENOTEMPTY;
01745 goto DONE;
01746 }
01747 cp_mempool_destroy(map->mempool);
01748 }
01749 cp_mempool_inc_refcount(pool);
01750 map->mempool = pool;
01751 }
01752 else
01753 {
01754 map->mempool =
01755 cp_mempool_create_by_option(COLLECTION_MODE_NOSYNC,
01756 sizeof(cp_index_map_node), 0);
01757 if (map->mempool == NULL)
01758 {
01759 rc = ENOMEM;
01760 goto DONE;
01761 }
01762 }
01763
01764 DONE:
01765 cp_multimap_txunlock(map);
01766 return rc;
01767 }
01768
01769
01770
01771 int cp_multimap_share_mempool(cp_multimap *map, cp_shared_mempool *pool)
01772 {
01773 int rc;
01774
01775 if ((rc = cp_multimap_txlock(map, COLLECTION_LOCK_WRITE))) return rc;
01776
01777 if (map->mempool)
01778 {
01779 if (map->items)
01780 {
01781 rc = ENOTEMPTY;
01782 goto DONE;
01783 }
01784
01785 cp_mempool_destroy(map->mempool);
01786 }
01787
01788 map->mempool = cp_shared_mempool_register(pool, sizeof(cp_index_map_node));
01789 if (map->mempool == NULL)
01790 {
01791 rc = ENOMEM;
01792 goto DONE;
01793 }
01794
01795 DONE:
01796 cp_multimap_txunlock(map);
01797 return rc;
01798 }
01799
01800
01801 cp_index *cp_multimap_create_index(cp_multimap *map,
01802 cp_index_type type,
01803 cp_key_fn key,
01804 cp_compare_fn cmp,
01805 int *err)
01806 {
01807 int mode;
01808 cp_index *res = NULL;
01809 cp_index *desc;
01810 cp_index_map *index;
01811 int rc;
01812
01813 if ((rc = cp_multimap_txlock(map, COLLECTION_LOCK_WRITE)))
01814 {
01815 if (err != NULL) *err = rc;
01816 return NULL;
01817 }
01818
01819 if (map->index == NULL)
01820 {
01821 map->index =
01822 cp_hashlist_create_by_option(COLLECTION_MODE_NOSYNC |
01823 COLLECTION_MODE_DEEP, 3,
01824 cp_hash_addr, cp_hash_compare_addr,
01825 NULL, NULL,
01826 NULL, (cp_destructor_fn) free);
01827 if (map->index == NULL)
01828 {
01829 if (err != NULL) *err = CP_MEMORY_ALLOCATION_FAILURE;
01830 return NULL;
01831 }
01832 }
01833 else
01834 {
01835 int exists = 0;
01836 cp_hashlist_entry *entry;
01837 cp_hashlist_iterator *itr =
01838 cp_hashlist_create_iterator(map->index, COLLECTION_LOCK_NONE);
01839
01840 while ((entry = cp_hashlist_iterator_next(itr)))
01841 {
01842 cp_index *curr = (cp_index *) entry->key;
01843 if (curr->key == key && curr->cmp == cmp)
01844 {
01845 res = curr;
01846 exists = 1;
01847 break;
01848 }
01849 }
01850
01851 cp_hashlist_iterator_destroy(itr);
01852
01853 if (exists)
01854 {
01855 if (err != NULL) *err = CP_ITEM_EXISTS;
01856 goto DONE;
01857 }
01858 }
01859
01860 desc = calloc(1, sizeof(cp_index));
01861 if (desc == NULL)
01862 {
01863 if (err != NULL) *err = CP_MEMORY_ALLOCATION_FAILURE;
01864 goto DONE;
01865 }
01866 desc->type = type;
01867 desc->key = key;
01868 desc->cmp = cmp;
01869
01870 mode = map->mode & ~(COLLECTION_MODE_COPY | COLLECTION_MODE_DEEP);
01871 if (type == CP_UNIQUE)
01872 mode &= ~COLLECTION_MODE_MULTIPLE_VALUES;
01873 else
01874 mode |= COLLECTION_MODE_MULTIPLE_VALUES;
01875
01876 index = cp_index_map_create(map, mode, desc);
01877 if (index == NULL) goto DONE;
01878
01879 if (cp_hashlist_append(map->index, desc, index)) res = desc;
01880
01881 DONE:
01882 cp_multimap_txunlock(map);
01883 return res;
01884 }
01885