mkavl.c
Go to the documentation of this file.
00001 
00025 #include "mkavl.h"
00026 #include "libavl/avl.h"
00027 #include <stdio.h>
00028 
00033 #ifndef CT_ASSERT
00034 #define CT_ASSERT(e) extern char (*CT_ASSERT(void)) [sizeof(char[1 - 2*!(e)])]
00035 #endif
00036 
00040 #ifndef NELEMS
00041 #define NELEMS(x) (sizeof(x) / sizeof(x[0]))
00042 #endif
00043 
00047 #define MKAVL_RUNAWAY_SANITY 100000
00048 
00052 #define MKAVL_CTX_MAGIC 0xCAFEBABE
00053 
00057 #define MKAVL_CTX_STALE 0xDEADBEEF
00058 
00062 typedef struct mkavl_avl_ctx_st_ {
00064     uint32_t magic;
00066     mkavl_tree_handle tree_h;
00068     size_t key_idx;
00069 } mkavl_avl_ctx_st;
00070 
00074 typedef struct mkavl_avl_tree_st_ {
00076     struct avl_table *tree;
00078     mkavl_compare_fn compare_fn;
00080     mkavl_avl_ctx_st *avl_ctx;
00081 } mkavl_avl_tree_st;
00082 
00086 typedef struct mkavl_allocator_wrapper_st_ {
00090     struct libavl_allocator avl_allocator;
00092     uint32_t magic;
00094     mkavl_allocator_st mkavl_allocator;
00096     mkavl_tree_handle tree_h;
00097 } mkavl_allocator_wrapper_st;
00098 
00102 typedef struct mkavl_tree_st_ {
00104     void *context;
00106     mkavl_allocator_wrapper_st allocator;
00108     size_t avl_tree_count;
00110     mkavl_avl_tree_st *avl_tree_array;
00116     uint32_t item_count;
00121     mkavl_copy_fn copy_fn;
00122 } mkavl_tree_st;
00123 
00127 typedef struct mkavl_iterator_st_ {
00129     struct avl_traverser avl_t;
00131     mkavl_tree_handle tree_h;
00133     size_t key_idx;
00134 } mkavl_iterator_st;
00135 
00143 static inline void
00144 mkavl_assert_abort (bool condition)
00145 {
00146     if (!condition) {
00147         abort();
00148     }
00149 }
00150 
00156 static const char * const mkavl_rc_e_string[] = {
00157     "Invalid RC",
00158     "Success",
00159     "Invalid input",
00160     "No memory",
00161     "Out of sync",
00162     "Max RC"
00163 };
00164 
00166 /* Ensure there is a string for each enum declared */
00167 CT_ASSERT(NELEMS(mkavl_rc_e_string) == (MKAVL_RC_E_MAX + 1));
00176 bool
00177 mkavl_rc_e_is_notok (mkavl_rc_e rc)
00178 {
00179     return (MKAVL_RC_E_SUCCESS != rc);
00180 }
00181 
00188 bool
00189 mkavl_rc_e_is_ok (mkavl_rc_e rc)
00190 {
00191     return (MKAVL_RC_E_SUCCESS == rc);
00192 }
00193 
00200 bool
00201 mkavl_rc_e_is_valid (mkavl_rc_e rc)
00202 {
00203     return ((rc >= MKAVL_RC_E_INVALID) && (rc <= MKAVL_RC_E_MAX));
00204 }
00205 
00213 const char *
00214 mkavl_rc_e_get_string (mkavl_rc_e rc)
00215 {
00216     const char* retval = "__Invalid__";
00217 
00218     if (mkavl_rc_e_is_valid(rc)) {
00219         retval = mkavl_rc_e_string[rc];
00220     }
00221 
00222     return (retval);
00223 }
00224 
00230 static const char * const mkavl_find_type_e_string[] = {
00231     "Invalid",
00232     "Equal",
00233     "Greater than",
00234     "Less than",
00235     "Greater than or equal",
00236     "Less than or equal",
00237     "Max type"
00238 };
00239 
00241 /* Ensure there is a string for each enum declared */
00242 CT_ASSERT(NELEMS(mkavl_find_type_e_string) == (MKAVL_FIND_TYPE_E_MAX + 1));
00251 bool
00252 mkavl_find_type_e_is_valid (mkavl_find_type_e type)
00253 {
00254     return ((type >= MKAVL_FIND_TYPE_E_INVALID) && 
00255             (type <= MKAVL_FIND_TYPE_E_MAX));
00256 }
00257 
00265 const char *
00266 mkavl_find_type_e_get_string (mkavl_find_type_e type)
00267 {
00268     const char* retval = "__Invalid__";
00269 
00270     if (mkavl_find_type_e_is_valid(type)) {
00271         retval = mkavl_find_type_e_string[type];
00272     }
00273 
00274     return (retval);
00275 }
00276 
00283 static bool
00284 mkavl_avl_ctx_is_valid (mkavl_avl_ctx_st *avl_ctx)
00285 {
00286     bool is_valid = true;
00287 
00288     if (is_valid && (NULL == avl_ctx)) {
00289         is_valid = false;
00290     }
00291 
00292     if (is_valid && (MKAVL_CTX_MAGIC != avl_ctx->magic)) {
00293         is_valid = false;
00294     }
00295 
00296     if (is_valid && (NULL == avl_ctx->tree_h)) {
00297         is_valid = false;
00298     }
00299 
00300     if (is_valid && (avl_ctx->key_idx >= avl_ctx->tree_h->avl_tree_count)) {
00301         is_valid = false;
00302     }
00303 
00304     return (is_valid);
00305 }
00306 
00313 static bool
00314 mkavl_allocator_wrapper_is_valid (mkavl_allocator_wrapper_st *allocator)
00315 {
00316     bool is_valid = true;
00317 
00318     if (is_valid && (NULL == allocator)) {
00319         is_valid = false;
00320     }
00321 
00322     if (is_valid && (MKAVL_CTX_MAGIC != allocator->magic)) {
00323         is_valid = false;
00324     }
00325 
00326     if (is_valid && (NULL == allocator->mkavl_allocator.malloc_fn)) {
00327         is_valid = false;
00328     }
00329 
00330     if (is_valid && (NULL == allocator->mkavl_allocator.free_fn)) {
00331         is_valid = false;
00332     }
00333 
00334     if (is_valid && (NULL == allocator->tree_h)) {
00335         is_valid = false;
00336     }
00337 
00338     return (is_valid);
00339 }
00340 
00348 static void *
00349 mkavl_malloc_wrapper (struct libavl_allocator *allocator, size_t size)
00350 {
00351     mkavl_allocator_wrapper_st *mkavl_allocator =
00352         (mkavl_allocator_wrapper_st *) allocator;
00353 
00354     mkavl_assert_abort(mkavl_allocator_wrapper_is_valid(mkavl_allocator));
00355 
00356     return (mkavl_allocator->mkavl_allocator.malloc_fn(size,
00357                 mkavl_allocator->tree_h->context));
00358 }
00359 
00366 static void
00367 mkavl_free_wrapper (struct libavl_allocator *allocator, void *libavl_block)
00368 {
00369     mkavl_allocator_wrapper_st *mkavl_allocator =
00370         (mkavl_allocator_wrapper_st *) allocator;
00371 
00372     mkavl_assert_abort(mkavl_allocator_wrapper_is_valid(mkavl_allocator));
00373 
00374     return (mkavl_allocator->mkavl_allocator.free_fn(libavl_block,
00375                 mkavl_allocator->tree_h->context));
00376 }
00377 
00385 static void *
00386 mkavl_default_malloc_fn (size_t size, void *context)
00387 {
00388     return (malloc(size));
00389 }
00390 
00397 static void
00398 mkavl_default_free_fn (void *ptr, void *context)
00399 {
00400     return (free(ptr));
00401 }
00402 
00406 static mkavl_allocator_st mkavl_allocator_default = {
00407     mkavl_default_malloc_fn,
00408     mkavl_default_free_fn
00409 };
00410 
00414 static struct libavl_allocator mkavl_allocator_wrapper = {
00415     mkavl_malloc_wrapper,
00416     mkavl_free_wrapper
00417 };
00418 
00427 static int
00428 mkavl_compare_wrapper (const void *avl_a, const void *avl_b, void *avl_param)
00429 {
00430     mkavl_avl_ctx_st *avl_ctx;
00431     mkavl_compare_fn cmp_fn;
00432 
00433     avl_ctx = (mkavl_avl_ctx_st *) avl_param;
00434     mkavl_assert_abort(mkavl_avl_ctx_is_valid(avl_ctx));
00435 
00436     cmp_fn = avl_ctx->tree_h->avl_tree_array[avl_ctx->key_idx].compare_fn;
00437     mkavl_assert_abort(NULL != cmp_fn);
00438 
00439     return (cmp_fn(avl_a, avl_b, avl_ctx->tree_h->context));
00440 }
00441 
00449 static void *
00450 mkavl_copy_wrapper (void *avl_item, void *avl_param)
00451 {
00452     mkavl_avl_ctx_st *avl_ctx;
00453     mkavl_copy_fn copy_fn;
00454 
00455     avl_ctx = (mkavl_avl_ctx_st *) avl_param;
00456     mkavl_assert_abort(mkavl_avl_ctx_is_valid(avl_ctx));
00457 
00458     copy_fn = avl_ctx->tree_h->copy_fn;
00459     mkavl_assert_abort(NULL != copy_fn);
00460 
00461     return (copy_fn(avl_item, avl_ctx->tree_h->context));
00462 }
00463 
00471 static mkavl_rc_e
00472 mkavl_delete_tree (mkavl_tree_handle *tree_h)
00473 {
00474     mkavl_allocator_st local_allocator;
00475     mkavl_tree_handle local_tree_h;
00476     void *context;
00477     uint32_t i;
00478 
00479     if (NULL == tree_h) {
00480         return (MKAVL_RC_E_EINVAL);
00481     }
00482     local_tree_h = *tree_h;
00483 
00484     memcpy(&local_allocator, &(local_tree_h->allocator.mkavl_allocator),
00485            sizeof(local_allocator));
00486     context = local_tree_h->context;
00487 
00488     if (NULL == local_tree_h) {
00489         return (MKAVL_RC_E_SUCCESS);
00490     }
00491 
00492     if (NULL != local_tree_h->avl_tree_array) {
00493         for (i = 0; i < local_tree_h->avl_tree_count; ++i) {
00494             if (NULL != local_tree_h->avl_tree_array[i].tree) { 
00495                 if (NULL != local_tree_h->avl_tree_array[i].avl_ctx) {
00496                     local_allocator.free_fn(
00497                         local_tree_h->avl_tree_array[i].avl_ctx, context);
00498                     local_tree_h->avl_tree_array[i].avl_ctx = NULL;
00499                 }
00500                 avl_destroy(local_tree_h->avl_tree_array[i].tree, NULL);
00501                 local_tree_h->avl_tree_array[i].tree = NULL;
00502             }
00503         }
00504         local_allocator.free_fn(local_tree_h->avl_tree_array, context);
00505     }
00506     local_tree_h->allocator.tree_h = NULL;
00507     local_tree_h->allocator.magic = MKAVL_CTX_STALE;
00508 
00509     local_allocator.free_fn(local_tree_h, context);
00510 
00511     *tree_h = NULL;
00512 
00513     return (MKAVL_RC_E_SUCCESS);
00514 }
00515 
00522 static bool
00523 mkavl_tree_is_valid (mkavl_tree_handle tree_h)
00524 {
00525     bool is_valid = true;
00526     uint32_t i;
00527 
00528     if (is_valid && (NULL == tree_h)) {
00529         is_valid = false;
00530     }
00531 
00532     if (is_valid && (0 == tree_h->avl_tree_count)) {
00533         is_valid = false;
00534     }
00535 
00536     if (is_valid && 
00537         !mkavl_allocator_wrapper_is_valid(&(tree_h->allocator))) {
00538         is_valid = false;
00539     }
00540 
00541     if (is_valid) {
00542         for (i = 0; i < tree_h->avl_tree_count; ++i) {
00543             if (NULL == tree_h->avl_tree_array[i].tree) {
00544                 is_valid = false;
00545                 break;
00546             }
00547 
00548             if (NULL == tree_h->avl_tree_array[i].compare_fn) {
00549                 is_valid = false;
00550                 break;
00551             }
00552 
00553             if (!mkavl_avl_ctx_is_valid(tree_h->avl_tree_array[i].avl_ctx)) {
00554                 is_valid = false;
00555                 break;
00556             }
00557         }
00558     }
00559 
00560     return (is_valid);
00561 }
00562 
00569 static bool
00570 mkavl_iterator_is_valid (mkavl_iterator_handle iterator_h)
00571 {
00572     bool is_valid = true;
00573 
00574     if (is_valid && (NULL == iterator_h)) {
00575         is_valid = false;
00576     }
00577 
00578     if (is_valid && !mkavl_tree_is_valid(iterator_h->tree_h)) {
00579         is_valid = false;
00580     }
00581 
00582     if (is_valid && 
00583         (iterator_h->key_idx >= iterator_h->tree_h->avl_tree_count)) {
00584         is_valid = false;
00585     }
00586 
00587     return (is_valid);
00588 }
00589 
00607 mkavl_rc_e
00608 mkavl_new (mkavl_tree_handle *tree_h,
00609            mkavl_compare_fn *compare_fn_array, 
00610            size_t compare_fn_array_count, 
00611            void *context, mkavl_allocator_st *allocator)
00612 {
00613     mkavl_allocator_st *local_allocator;
00614     mkavl_tree_handle local_tree_h;
00615     mkavl_avl_ctx_st *avl_ctx;
00616     mkavl_rc_e rc = MKAVL_RC_E_SUCCESS, err_rc;
00617     uint32_t i;
00618 
00619     if ((NULL == tree_h) || (NULL == compare_fn_array) ||
00620         (0 == compare_fn_array_count)) {
00621         return (MKAVL_RC_E_EINVAL);
00622     }
00623     *tree_h = NULL;
00624 
00625     local_allocator = 
00626         (NULL == allocator) ? &mkavl_allocator_default : allocator;
00627 
00628     local_tree_h = local_allocator->malloc_fn(sizeof(*local_tree_h), context);
00629     if (NULL == local_tree_h) {
00630         rc = MKAVL_RC_E_ENOMEM;
00631         goto err_exit;
00632     }
00633 
00634     local_tree_h->context = context;
00635     memcpy(&(local_tree_h->allocator.avl_allocator), &mkavl_allocator_wrapper,
00636            sizeof(local_tree_h->allocator.avl_allocator));
00637     memcpy(&(local_tree_h->allocator.mkavl_allocator), local_allocator,
00638            sizeof(local_tree_h->allocator));
00639     local_tree_h->allocator.tree_h = local_tree_h;
00640     local_tree_h->allocator.magic = MKAVL_CTX_MAGIC;
00641     local_tree_h->avl_tree_count = compare_fn_array_count;
00642     local_tree_h->avl_tree_array = NULL;
00643     local_tree_h->item_count = 0;
00644     local_tree_h->copy_fn = NULL;
00645 
00646     local_tree_h->avl_tree_array = 
00647         local_allocator->malloc_fn(local_tree_h->avl_tree_count * 
00648                                    sizeof(*(local_tree_h->avl_tree_array)),
00649                                    context);
00650     if (NULL == local_tree_h->avl_tree_array) {
00651         rc = MKAVL_RC_E_ENOMEM;
00652         goto err_exit;
00653     }
00654 
00655     for (i = 0; i < local_tree_h->avl_tree_count; ++i) {
00656         local_tree_h->avl_tree_array[i].tree = NULL;
00657         local_tree_h->avl_tree_array[i].compare_fn = compare_fn_array[i];
00658         if (NULL == local_tree_h->avl_tree_array[i].compare_fn) {
00659             rc = MKAVL_RC_E_ENOMEM;
00660             goto err_exit;
00661         }
00662         local_tree_h->avl_tree_array[i].avl_ctx = NULL;
00663     }
00664 
00665     for (i = 0; i < local_tree_h->avl_tree_count; ++i) {
00666         avl_ctx = local_allocator->malloc_fn(sizeof(*avl_ctx), context);
00667         if (NULL == avl_ctx) {
00668             rc = MKAVL_RC_E_ENOMEM;
00669             goto err_exit;
00670         }
00671         avl_ctx->magic = MKAVL_CTX_STALE;
00672 
00673         local_tree_h->avl_tree_array[i].tree = 
00674             avl_create(mkavl_compare_wrapper, avl_ctx,
00675                        &(local_tree_h->allocator.avl_allocator));
00676         if (NULL == local_tree_h->avl_tree_array[i].tree) {
00677             rc = MKAVL_RC_E_ENOMEM;
00678             goto err_exit;
00679         }
00680 
00681         avl_ctx->tree_h = local_tree_h;
00682         avl_ctx->key_idx = i;
00683         avl_ctx->magic = MKAVL_CTX_MAGIC;
00684         local_tree_h->avl_tree_array[i].avl_ctx = avl_ctx;
00685         avl_ctx = NULL;
00686     }
00687 
00688     if (!mkavl_tree_is_valid(local_tree_h)) {
00689         rc = MKAVL_RC_E_EINVAL;
00690         goto err_exit;
00691     }
00692 
00693     *tree_h = local_tree_h;
00694 
00695     return (rc);
00696 
00697 err_exit:
00698 
00699     if (NULL != local_tree_h) {
00700         err_rc = mkavl_delete_tree(&local_tree_h);
00701         mkavl_assert_abort(mkavl_rc_e_is_ok(err_rc));
00702     }
00703 
00704     if (NULL != avl_ctx) {
00705         /* Ownership of this memory hasn't been transferred to a tree yet */
00706         local_allocator->free_fn(avl_ctx, context);
00707     }
00708 
00709     return (rc);
00710 }
00711 
00720 void *
00721 mkavl_get_tree_context (mkavl_tree_handle tree_h)
00722 {
00723     mkavl_assert_abort(mkavl_tree_is_valid(tree_h));
00724 
00725     return (tree_h->context);
00726 }
00727 
00749 mkavl_rc_e
00750 mkavl_delete (mkavl_tree_handle *tree_h, mkavl_item_fn item_fn,
00751               mkavl_delete_context_fn delete_context_fn)
00752 {
00753     mkavl_tree_handle local_tree_h;
00754     void *item, *item_to_delete;
00755     uint32_t i, first_tree_idx;
00756     uint32_t runaway_counter = 0;
00757     struct avl_traverser avl_t = {0};
00758     void *context;
00759     mkavl_rc_e rc = MKAVL_RC_E_SUCCESS;
00760     mkavl_rc_e retval = MKAVL_RC_E_SUCCESS;
00761 
00762     if (NULL == tree_h) {
00763         return (MKAVL_RC_E_EINVAL);
00764     }
00765     local_tree_h = *tree_h;
00766 
00767     if (!mkavl_tree_is_valid(local_tree_h)) {
00768         return (MKAVL_RC_E_EINVAL);
00769     }
00770 
00771     /* 
00772      * Just randomly select the first tree as the one on which to iterate.
00773      * All trees should have the same set of data, just in different orders.
00774      */
00775     first_tree_idx = local_tree_h->avl_tree_count;
00776     for (i = 0; i < local_tree_h->avl_tree_count; ++i) {
00777         if (NULL != local_tree_h->avl_tree_array[i].tree) {
00778             first_tree_idx = i;
00779             avl_t_init(&avl_t, 
00780                        local_tree_h->avl_tree_array[first_tree_idx].tree);
00781             break;
00782         }
00783     }
00784 
00785     if (first_tree_idx < local_tree_h->avl_tree_count) {
00786         /* 
00787          * May be more efficient to just pull the root out each time instead
00788          * of traversing to get the first.
00789          */
00790         item_to_delete = 
00791             avl_t_first(&avl_t,
00792                         local_tree_h->avl_tree_array[first_tree_idx].tree);
00793         while (NULL != item_to_delete) {
00794             mkavl_assert_abort(runaway_counter <= MKAVL_RUNAWAY_SANITY);
00795             for (i = first_tree_idx; i < local_tree_h->avl_tree_count; ++i) {
00796                 if (NULL != local_tree_h->avl_tree_array[i].tree) {
00797                     item = avl_delete(local_tree_h->avl_tree_array[i].tree,
00798                                       item_to_delete);
00799                     mkavl_assert_abort(NULL != item);
00800                 }
00801             }
00802 
00803             if (NULL != item_fn) {
00804                 rc = item_fn(item_to_delete, local_tree_h->context);
00805                 if (mkavl_rc_e_is_notok(rc)) {
00806                     retval = rc;
00807                 }
00808             }
00809 
00810             --(local_tree_h->item_count);
00811 
00812             /* We deleted the last item, so there should be a new first */
00813             item_to_delete = 
00814                 avl_t_first(&avl_t, 
00815                             local_tree_h->avl_tree_array[first_tree_idx].tree);
00816             ++runaway_counter;
00817         }
00818     }
00819 
00820     context = local_tree_h->context;
00821 
00822     rc = mkavl_delete_tree(tree_h);
00823     mkavl_assert_abort(mkavl_rc_e_is_ok(rc));
00824 
00825     if (NULL != delete_context_fn) {
00826         rc = delete_context_fn(context);
00827         if (mkavl_rc_e_is_notok(rc)) {
00828             retval = rc;
00829         }
00830     }
00831 
00832     return (retval);
00833 }
00834 
00861 mkavl_rc_e
00862 mkavl_copy (mkavl_tree_handle source_tree_h, 
00863             mkavl_tree_handle *new_tree_h,
00864             mkavl_copy_fn copy_fn, mkavl_item_fn item_fn, 
00865             bool use_source_context, void *new_context,
00866             mkavl_delete_context_fn delete_context_fn,
00867             mkavl_allocator_st *allocator)
00868 {
00869     mkavl_tree_handle local_tree_h = NULL;
00870     mkavl_allocator_st *local_allocator = allocator;
00871     bool allocated_mkavl_tree = false;
00872     struct avl_traverser avl_t = {0};
00873     mkavl_copy_fn old_copy_fn, copy_fn_to_use;
00874     void *item, *existing_item;
00875     void *context_to_use;
00876     mkavl_delete_context_fn delete_context_fn_to_use;
00877     uint32_t i;
00878     bool is_first_item;
00879     mkavl_rc_e rc = MKAVL_RC_E_SUCCESS;
00880 
00881     if (NULL == new_tree_h) {
00882         return (MKAVL_RC_E_EINVAL);
00883     }
00884     *new_tree_h = NULL;
00885 
00886     if (!mkavl_tree_is_valid(source_tree_h)) {
00887         return (MKAVL_RC_E_EINVAL);
00888     }
00889 
00890     if (NULL == local_allocator) {
00891         local_allocator = &(source_tree_h->allocator.mkavl_allocator);
00892     }
00893 
00894     {
00895         mkavl_compare_fn cmp_fn_array[source_tree_h->avl_tree_count];
00896 
00897         for (i = 0; i < NELEMS(cmp_fn_array); ++i) {
00898             cmp_fn_array[i] = source_tree_h->avl_tree_array[i].compare_fn;
00899         }
00900 
00901         context_to_use = new_context;
00902         if (use_source_context) {
00903             context_to_use = source_tree_h->context;
00904         }
00905 
00906         rc = mkavl_new(&local_tree_h,
00907                        cmp_fn_array, NELEMS(cmp_fn_array),
00908                        context_to_use, local_allocator);
00909         if (mkavl_rc_e_is_notok(rc)) {
00910             goto err_exit;
00911         }
00912         allocated_mkavl_tree = true;
00913 
00914         /*
00915          * Copy the first AVL tree (which applies the user's copy function to
00916          * each item).  Then, iterate over the new, copied tree and add each
00917          * item to each of the other AVL trees.  Need to temorarily set the
00918          * source tree's copy function to the user provided one during this
00919          * iteration, since mkavl_copy_wrapper will look there for the function
00920          * to use for the real copy function.
00921          */
00922         old_copy_fn = source_tree_h->copy_fn;
00923         source_tree_h->copy_fn = copy_fn;
00924         copy_fn_to_use = NULL;
00925         if (NULL != copy_fn) {
00926             copy_fn_to_use = mkavl_copy_wrapper;
00927         }
00928         /*
00929          * avl_copy() is going to allocate the tree, but mkavl_new() already did
00930          * this, so we free the mkavl_new one here to prevent a leak.
00931          */
00932         local_tree_h->allocator.mkavl_allocator.free_fn(
00933             local_tree_h->avl_tree_array[0].tree, local_tree_h->context);
00934         local_tree_h->avl_tree_array[0].tree = 
00935             avl_copy(source_tree_h->avl_tree_array[0].tree, copy_fn_to_use,
00936                      NULL, &(local_tree_h->allocator.avl_allocator));
00937         source_tree_h->copy_fn = old_copy_fn;
00938         if (NULL == local_tree_h->avl_tree_array[0].tree) {
00939             goto err_exit;
00940         }
00941 
00942         local_tree_h->item_count = 
00943             avl_count(local_tree_h->avl_tree_array[0].tree);
00944         /* 
00945          * avl_copy() sets the AVL context to that of the source, so we need to
00946          * fix it up here explicitly.
00947          */
00948         local_tree_h->avl_tree_array[0].tree->avl_param =
00949             local_tree_h->avl_tree_array[0].avl_ctx;
00950 
00951         if (local_tree_h->avl_tree_count > 1) {
00952             item = avl_t_first(&avl_t, local_tree_h->avl_tree_array[0].tree);
00953             is_first_item = true;
00954             while (NULL != item) {
00955                 for (i = 1; i < local_tree_h->avl_tree_count; ++i) {
00956                     if (is_first_item) {
00957                         /* 
00958                          * avl_copy() sets the AVL context to that of the
00959                          * source, so we need to fix it up here explicitly.
00960                          */
00961                         local_tree_h->avl_tree_array[i].tree->avl_param =
00962                             local_tree_h->avl_tree_array[i].avl_ctx;
00963                     }
00964                     rc = mkavl_add_key_idx(local_tree_h, i,
00965                                            item, &existing_item);
00966                     if (mkavl_rc_e_is_notok(rc)) {
00967                         goto err_exit;
00968                     }
00969                 }
00970                 item = avl_t_next(&avl_t);
00971                 is_first_item = false;
00972             }
00973         }
00974     }
00975 
00976     *new_tree_h = local_tree_h;
00977 
00978     return (MKAVL_RC_E_SUCCESS);
00979 
00980 err_exit:
00981 
00982     if (allocated_mkavl_tree) {
00983         delete_context_fn_to_use = NULL;
00984         if (!use_source_context) {
00985             delete_context_fn_to_use = delete_context_fn;
00986         }
00987         /* Just deleting the tree should clean everything up. */
00988         mkavl_delete(&local_tree_h, item_fn, delete_context_fn_to_use);
00989     }
00990 
00991     return (rc);
00992 }
00993 
01003 mkavl_rc_e
01004 mkavl_add (mkavl_tree_handle tree_h, void *item_to_add, 
01005            void **existing_item)
01006 {
01007     uint32_t i, err_idx = 0;
01008     void *item, *first_item = NULL;
01009     mkavl_rc_e rc = MKAVL_RC_E_SUCCESS;
01010 
01011     if ((NULL == item_to_add) || (NULL == existing_item)) {
01012         return (MKAVL_RC_E_EINVAL);
01013     }
01014     *existing_item = NULL;
01015 
01016     if (!mkavl_tree_is_valid(tree_h)) {
01017         return (MKAVL_RC_E_EINVAL);
01018     }
01019 
01020     for (i = 0; i < tree_h->avl_tree_count; ++i) {
01021         item = avl_insert(tree_h->avl_tree_array[i].tree, item_to_add);
01022         if (0 == i) {
01023             first_item = item;
01024         } else if (first_item != item) {
01025             err_idx = i + 1;
01026             rc = MKAVL_RC_E_EOOSYNC;
01027             goto err_exit;
01028         }
01029     }
01030 
01031     if (NULL == first_item) {
01032         ++(tree_h->item_count);
01033     }
01034 
01035     *existing_item = first_item;
01036 
01037     return (rc);
01038 
01039 err_exit:
01040 
01041     for (i = 0; i < err_idx; ++i) {
01042         if (NULL == first_item) {
01043             /* Attempt to remove all the items we added */
01044             item = avl_delete(tree_h->avl_tree_array[i].tree, item_to_add);
01045             mkavl_assert_abort(NULL != item);
01046         }
01047     }
01048 
01049     return (rc);
01050 }
01051 
01062 static inline mkavl_rc_e
01063 mkavl_avl_end_item (const struct avl_node *node, void **found_item,
01064                     uint8_t side)
01065 {
01066     const struct avl_node *cur_node;
01067 
01068     if (NULL == found_item) {
01069         return (MKAVL_RC_E_EINVAL);
01070     }
01071     *found_item = NULL;
01072 
01073     if (side >= 2) {
01074         return (MKAVL_RC_E_EINVAL);
01075     }
01076 
01077     if (NULL == node) {
01078         return (MKAVL_RC_E_SUCCESS);
01079     }
01080     cur_node = node;
01081 
01082     while (NULL != cur_node->avl_link[side]) {
01083         cur_node = cur_node->avl_link[side];
01084     }
01085     *found_item = cur_node->avl_data;
01086 
01087     return (MKAVL_RC_E_SUCCESS);
01088 }
01089 
01097 static mkavl_rc_e
01098 mkavl_avl_first (const struct avl_node *node, void **found_item)
01099 {
01100     return (mkavl_avl_end_item(node, found_item, 0));
01101 }
01102 
01110 static mkavl_rc_e
01111 mkavl_avl_last (const struct avl_node *node, void **found_item)
01112 {
01113     return (mkavl_avl_end_item(node, found_item, 1));
01114 }
01115 
01129 static mkavl_rc_e
01130 mkavl_find_avl_lt (const struct avl_table *avl_tree,
01131                    const struct avl_node *node,
01132                    bool find_equal_to, const void *lookup_item, 
01133                    void **found_item)
01134 {
01135     int32_t cmp_rc;
01136     mkavl_rc_e rc;
01137 
01138     if ((NULL == found_item) || (NULL == lookup_item) ||
01139         (NULL == avl_tree)) {
01140         return (MKAVL_RC_E_EINVAL);
01141     }
01142     *found_item = NULL;
01143 
01144     if (NULL == node) {
01145         return (MKAVL_RC_E_SUCCESS);
01146     }
01147 
01148     cmp_rc = avl_tree->avl_compare(node->avl_data, lookup_item,
01149                                    avl_tree->avl_param);
01150 
01151     if (cmp_rc < 0) {
01152         /* Current node is less than what we're searching for */
01153         rc = mkavl_find_avl_lt(avl_tree, node->avl_link[1], find_equal_to,
01154                                lookup_item, found_item);
01155         if (mkavl_rc_e_is_notok(rc)) {
01156             return (rc);
01157         }
01158 
01159         if (NULL == *found_item) {
01160             /* 
01161              * There is nothing smaller in the right subtree, so the current
01162              * node is the winner.  Otherwise, return what was found in the
01163              * right subtree.
01164              */
01165             *found_item = node->avl_data;
01166         }
01167 
01168         return (MKAVL_RC_E_SUCCESS);
01169     } else if (cmp_rc > 0) {
01170         /* Current node is greater than what we're searching for */
01171         return (mkavl_find_avl_lt(avl_tree, node->avl_link[0], find_equal_to,
01172                                   lookup_item, found_item));
01173     }
01174 
01175     /* Current node is equal to what we're searching for */
01176 
01177     if (find_equal_to) {
01178         /* We're done if we can stop on equality */
01179         *found_item = node->avl_data;
01180         return (MKAVL_RC_E_SUCCESS);
01181     }
01182 
01183     /* 
01184      * If we can't stop on equality, then get the biggest item in the left
01185      * subtree.
01186      */
01187     return (mkavl_avl_last(node->avl_link[0], found_item));
01188 }
01189 
01203 static mkavl_rc_e
01204 mkavl_find_avl_gt (const struct avl_table *avl_tree,
01205                    const struct avl_node *node,
01206                    bool find_equal_to, const void *lookup_item, 
01207                    void **found_item)
01208 {
01209     int32_t cmp_rc;
01210     mkavl_rc_e rc;
01211 
01212     if ((NULL == found_item) || (NULL == lookup_item) ||
01213         (NULL == avl_tree)) {
01214         return (MKAVL_RC_E_EINVAL);
01215     }
01216     *found_item = NULL;
01217 
01218     if (NULL == node) {
01219         return (MKAVL_RC_E_SUCCESS);
01220     }
01221 
01222     cmp_rc = avl_tree->avl_compare(node->avl_data, lookup_item,
01223                                    avl_tree->avl_param);
01224 
01225     if (cmp_rc < 0) {
01226         /* Current node is less than what we're searching for */
01227         return (mkavl_find_avl_gt(avl_tree, node->avl_link[1], find_equal_to,
01228                                   lookup_item, found_item));
01229     } else if (cmp_rc > 0) {
01230         /* Current node is greater than what we're searching for */
01231         rc = mkavl_find_avl_gt(avl_tree, node->avl_link[0], find_equal_to,
01232                                lookup_item, found_item);
01233         if (mkavl_rc_e_is_notok(rc)) {
01234             return (rc);
01235         }
01236 
01237         if (NULL == *found_item) {
01238             /* 
01239              * There is nothing bigger in the left subtree, so the current node
01240              * is the winner.  Otherwise, return what was found in the left
01241              * subtree.
01242              */
01243             *found_item = node->avl_data;
01244         }
01245 
01246         return (MKAVL_RC_E_SUCCESS);
01247     }
01248 
01249     /* Current node is equal to what we're searching for */
01250 
01251     if (find_equal_to) {
01252         /* We're done if we can stop on equality */
01253         *found_item = node->avl_data;
01254         return (MKAVL_RC_E_SUCCESS);
01255     }
01256 
01257     /* 
01258      * If we can't stop on equality, then get the smallest item in the right
01259      * subtree.
01260      */
01261     return (mkavl_avl_first(node->avl_link[1], found_item));
01262 }
01263 
01274 mkavl_rc_e
01275 mkavl_find (mkavl_tree_handle tree_h, mkavl_find_type_e type,
01276             size_t key_idx, const void *lookup_item, void **found_item)
01277 {
01278     void *item = NULL;
01279     mkavl_rc_e rc;
01280 
01281     if ((NULL == lookup_item) || (NULL == found_item)) {
01282         return (MKAVL_RC_E_EINVAL);
01283     }
01284     *found_item = NULL;
01285 
01286     if (!mkavl_find_type_e_is_valid(type)) {
01287         return (MKAVL_RC_E_EINVAL);
01288     }
01289 
01290     if (!mkavl_tree_is_valid(tree_h)) {
01291         return (MKAVL_RC_E_EINVAL);
01292     }
01293 
01294     if (key_idx >= tree_h->avl_tree_count) {
01295         return (MKAVL_RC_E_EINVAL);
01296     }
01297 
01298     switch (type) {
01299     case MKAVL_FIND_TYPE_E_EQUAL:
01300         item = avl_find(tree_h->avl_tree_array[key_idx].tree, lookup_item);
01301         break;
01302     case MKAVL_FIND_TYPE_E_GT:
01303         rc = mkavl_find_avl_gt(tree_h->avl_tree_array[key_idx].tree,
01304                                tree_h->avl_tree_array[key_idx].tree->avl_root,
01305                                false, lookup_item, &item);
01306         if (mkavl_rc_e_is_notok(rc)) {
01307             return (rc);
01308         }
01309         break;
01310     case MKAVL_FIND_TYPE_E_GE:
01311         rc = mkavl_find_avl_gt(tree_h->avl_tree_array[key_idx].tree,
01312                                tree_h->avl_tree_array[key_idx].tree->avl_root,
01313                                true, lookup_item, &item);
01314         if (mkavl_rc_e_is_notok(rc)) {
01315             return (rc);
01316         }
01317         break;
01318     case MKAVL_FIND_TYPE_E_LT:
01319         rc = mkavl_find_avl_lt(tree_h->avl_tree_array[key_idx].tree,
01320                                tree_h->avl_tree_array[key_idx].tree->avl_root,
01321                                false, lookup_item, &item);
01322         if (mkavl_rc_e_is_notok(rc)) {
01323             return (rc);
01324         }
01325         break;
01326     case MKAVL_FIND_TYPE_E_LE:
01327         rc = mkavl_find_avl_lt(tree_h->avl_tree_array[key_idx].tree,
01328                                tree_h->avl_tree_array[key_idx].tree->avl_root,
01329                                true, lookup_item, &item);
01330         if (mkavl_rc_e_is_notok(rc)) {
01331             return (rc);
01332         }
01333         break;
01334     default:
01335         return (MKAVL_RC_E_EINVAL);
01336     }
01337 
01338     *found_item = item;
01339 
01340     return (MKAVL_RC_E_SUCCESS);
01341 }
01342 
01351 mkavl_rc_e
01352 mkavl_remove (mkavl_tree_handle tree_h, const void *item_to_remove,
01353               void **found_item)
01354 {
01355     uint32_t i, err_idx = 0;
01356     void *item, *first_item = NULL;
01357     mkavl_rc_e rc = MKAVL_RC_E_SUCCESS;
01358 
01359     if ((NULL == item_to_remove) || (NULL == found_item)) {
01360         return (MKAVL_RC_E_EINVAL);
01361     }
01362     *found_item = NULL;
01363 
01364     if (!mkavl_tree_is_valid(tree_h)) {
01365         return (MKAVL_RC_E_EINVAL);
01366     }
01367 
01368     for (i = 0; i < tree_h->avl_tree_count; ++i) {
01369         item = avl_delete(tree_h->avl_tree_array[i].tree, item_to_remove);
01370         if (0 == i) {
01371             first_item = item;
01372         } else if (first_item != item) {
01373             err_idx = i + 1;
01374             rc = MKAVL_RC_E_EOOSYNC;
01375             goto err_exit;
01376         }
01377     }
01378 
01379     if (NULL != first_item) {
01380         if (0 == tree_h->item_count) {
01381             rc = MKAVL_RC_E_EOOSYNC;
01382             goto err_exit;
01383         }
01384         --(tree_h->item_count);
01385     }
01386 
01387     *found_item = first_item;
01388 
01389     return (rc);
01390 
01391 err_exit:
01392 
01393     for (i = 0; i < err_idx; ++i) {
01394         if (NULL != first_item) {
01395             /* Attempt to insert all the items we removed */
01396             item = avl_insert(tree_h->avl_tree_array[i].tree, first_item);
01397             mkavl_assert_abort(NULL == item);
01398         }
01399     }
01400 
01401     return (rc);
01402 }
01403 
01421 mkavl_rc_e
01422 mkavl_add_key_idx (mkavl_tree_handle tree_h, size_t key_idx,
01423                    void *item_to_add, void **existing_item)
01424 {
01425     void *item;
01426 
01427     if ((NULL == item_to_add) || (NULL == existing_item)) {
01428         return (MKAVL_RC_E_EINVAL);
01429     }
01430     *existing_item = NULL;
01431 
01432     if (!mkavl_tree_is_valid(tree_h)) {
01433         return (MKAVL_RC_E_EINVAL);
01434     }
01435 
01436     if (key_idx >= tree_h->avl_tree_count) {
01437         return (MKAVL_RC_E_EINVAL);
01438     }
01439 
01440     item = avl_insert(tree_h->avl_tree_array[key_idx].tree, item_to_add);
01441     *existing_item = item;
01442 
01443     return (MKAVL_RC_E_SUCCESS);
01444 }
01445 
01463 mkavl_rc_e
01464 mkavl_remove_key_idx (mkavl_tree_handle tree_h, size_t key_idx,
01465                       const void *item_to_remove, void **found_item)
01466 {
01467     void *item;
01468 
01469     if ((NULL == item_to_remove) || (NULL == found_item)) {
01470         return (MKAVL_RC_E_EINVAL);
01471     }
01472     *found_item = NULL;
01473 
01474     if (!mkavl_tree_is_valid(tree_h)) {
01475         return (MKAVL_RC_E_EINVAL);
01476     }
01477 
01478     if (key_idx >= tree_h->avl_tree_count) {
01479         return (MKAVL_RC_E_EINVAL);
01480     }
01481 
01482     item = avl_delete(tree_h->avl_tree_array[key_idx].tree, item_to_remove);
01483     *found_item = item;
01484 
01485     return (MKAVL_RC_E_SUCCESS);
01486 }
01487 
01501 uint32_t
01502 mkavl_count (mkavl_tree_handle tree_h)
01503 {
01504     if (!mkavl_tree_is_valid(tree_h)) {
01505         return (0);
01506     }
01507 
01508     return (tree_h->item_count);
01509 }
01510 
01520 mkavl_rc_e
01521 mkavl_walk (mkavl_tree_handle tree_h, mkavl_walk_cb_fn cb_fn,
01522             void *walk_context)
01523 {
01524     void *item;
01525     bool stop_walk = false;
01526     struct avl_traverser avl_t = {0};
01527     mkavl_rc_e rc = MKAVL_RC_E_SUCCESS;
01528 
01529     if (NULL == cb_fn) {
01530         return (MKAVL_RC_E_EINVAL);
01531     }
01532 
01533     if (!mkavl_tree_is_valid(tree_h)) {
01534         return (MKAVL_RC_E_EINVAL);
01535     }
01536 
01537     /* 
01538      * Just randomly select the first tree as the one on which to iterate.
01539      * All trees should have the same set of data, just in different orders.
01540      */
01541     avl_t_init(&avl_t, tree_h->avl_tree_array[0].tree);
01542 
01543     item = avl_t_first(&avl_t, tree_h->avl_tree_array[0].tree);
01544     while ((NULL != item) && !stop_walk) {
01545         rc = cb_fn(item, tree_h->context, walk_context, &stop_walk);
01546         if (mkavl_rc_e_is_notok(rc)) {
01547             break;
01548         }
01549         item = avl_t_next(&avl_t);
01550     }
01551 
01552     return (rc);
01553 }
01554 
01564 mkavl_rc_e
01565 mkavl_iter_new (mkavl_iterator_handle *iterator_h, mkavl_tree_handle tree_h,
01566                 size_t key_idx)
01567 {
01568     mkavl_iterator_handle local_iter_h;
01569     mkavl_rc_e rc;
01570 
01571     if ((NULL == iterator_h) || !mkavl_tree_is_valid(tree_h)) {
01572         return (MKAVL_RC_E_EINVAL);
01573     }
01574 
01575     if (key_idx >= tree_h->avl_tree_count) {
01576         return (MKAVL_RC_E_EINVAL);
01577     }
01578     *iterator_h = NULL;
01579 
01580     local_iter_h =
01581         tree_h->allocator.mkavl_allocator.malloc_fn(sizeof(*local_iter_h),
01582                                                     tree_h->context);
01583     if (NULL == local_iter_h) {
01584         rc = MKAVL_RC_E_ENOMEM;
01585         goto err_exit;
01586     }
01587     local_iter_h->tree_h = tree_h;
01588     local_iter_h->key_idx = key_idx;
01589     memset(&(local_iter_h->avl_t), 0, sizeof(local_iter_h->avl_t));
01590 
01591     avl_t_init(&(local_iter_h->avl_t), tree_h->avl_tree_array[key_idx].tree);
01592 
01593     *iterator_h = local_iter_h;
01594 
01595     return (MKAVL_RC_E_SUCCESS);
01596 
01597 err_exit:
01598 
01599     if (NULL != local_iter_h) {
01600         tree_h->allocator.mkavl_allocator.free_fn(local_iter_h, 
01601                                                   tree_h->context);
01602         local_iter_h = NULL;
01603     }
01604 
01605     return (rc);
01606 }
01607 
01616 mkavl_rc_e
01617 mkavl_iter_delete (mkavl_iterator_handle *iterator_h)
01618 {
01619     mkavl_iterator_handle local_iter_h;
01620     mkavl_free_fn free_fn;
01621 
01622     if (NULL == iterator_h) {
01623         return (MKAVL_RC_E_EINVAL);
01624     }
01625     local_iter_h = *iterator_h;
01626 
01627     if (!mkavl_iterator_is_valid(local_iter_h)) {
01628         return (MKAVL_RC_E_EINVAL);
01629     }
01630 
01631     free_fn = local_iter_h->tree_h->allocator.mkavl_allocator.free_fn;
01632     free_fn(local_iter_h, local_iter_h->tree_h->context);
01633 
01634     *iterator_h = NULL;
01635 
01636     return (MKAVL_RC_E_SUCCESS);
01637 }
01638 
01647 mkavl_rc_e
01648 mkavl_iter_first (mkavl_iterator_handle iterator_h, void **item)
01649 {
01650     if (NULL == item) {
01651         return (MKAVL_RC_E_EINVAL);
01652     }
01653     *item = NULL;
01654 
01655     if (!mkavl_iterator_is_valid(iterator_h)) {
01656         return (MKAVL_RC_E_EINVAL);
01657     }
01658 
01659     *item = avl_t_first(&(iterator_h->avl_t),
01660                 iterator_h->tree_h->avl_tree_array[iterator_h->key_idx].tree);
01661 
01662     return (MKAVL_RC_E_SUCCESS);
01663 }
01664 
01673 mkavl_rc_e
01674 mkavl_iter_last (mkavl_iterator_handle iterator_h, void **item)
01675 {
01676     if (NULL == item) {
01677         return (MKAVL_RC_E_EINVAL);
01678     }
01679     *item = NULL;
01680 
01681     if (!mkavl_iterator_is_valid(iterator_h)) {
01682         return (MKAVL_RC_E_EINVAL);
01683     }
01684 
01685     *item = avl_t_last(&(iterator_h->avl_t),
01686                 iterator_h->tree_h->avl_tree_array[iterator_h->key_idx].tree);
01687 
01688     return (MKAVL_RC_E_SUCCESS);
01689 }
01690 
01700 mkavl_rc_e
01701 mkavl_iter_find (mkavl_iterator_handle iterator_h, void *lookup_item,
01702                  void **found_item)
01703 {
01704     if ((NULL == lookup_item) || (NULL == found_item)) {
01705         return (MKAVL_RC_E_EINVAL);
01706     }
01707     *found_item = NULL;
01708 
01709     if (!mkavl_iterator_is_valid(iterator_h)) {
01710         return (MKAVL_RC_E_EINVAL);
01711     }
01712 
01713     *found_item = 
01714         avl_t_find(&(iterator_h->avl_t),
01715                    iterator_h->tree_h->avl_tree_array[iterator_h->key_idx].tree,
01716                    lookup_item);
01717 
01718     return (MKAVL_RC_E_SUCCESS);
01719 }
01720 
01729 mkavl_rc_e
01730 mkavl_iter_next (mkavl_iterator_handle iterator_h, void **item)
01731 {
01732     if (NULL == item) {
01733         return (MKAVL_RC_E_EINVAL);
01734     }
01735     *item = NULL;
01736 
01737     if (!mkavl_iterator_is_valid(iterator_h)) {
01738         return (MKAVL_RC_E_EINVAL);
01739     }
01740 
01741     *item = avl_t_next(&(iterator_h->avl_t));
01742 
01743     return (MKAVL_RC_E_SUCCESS);
01744 }
01745 
01754 mkavl_rc_e
01755 mkavl_iter_prev (mkavl_iterator_handle iterator_h, void **item)
01756 {
01757     if (NULL == item) {
01758         return (MKAVL_RC_E_EINVAL);
01759     }
01760     *item = NULL;
01761 
01762     if (!mkavl_iterator_is_valid(iterator_h)) {
01763         return (MKAVL_RC_E_EINVAL);
01764     }
01765 
01766     *item = avl_t_prev(&(iterator_h->avl_t));
01767 
01768     return (MKAVL_RC_E_SUCCESS);
01769 }
01770 
01779 mkavl_rc_e
01780 mkavl_iter_cur (mkavl_iterator_handle iterator_h, void **item)
01781 {
01782     if (NULL == item) {
01783         return (MKAVL_RC_E_EINVAL);
01784     }
01785     *item = NULL;
01786 
01787     if (!mkavl_iterator_is_valid(iterator_h)) {
01788         return (MKAVL_RC_E_EINVAL);
01789     }
01790 
01791     *item = avl_t_cur(&(iterator_h->avl_t));
01792 
01793     return (MKAVL_RC_E_SUCCESS);
01794 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines