tree.c

Go to the documentation of this file.
00001 
00012 /* Adapted from... */
00013 /*
00014  * ANSI C Library for maintainance of AVL Balanced Trees
00015  *
00016  * ref.:
00017  *  G. M. Adelson-Velskij & E. M. Landis
00018  *  Doklady Akad. Nauk SSSR 146 (1962), 263-266
00019  *
00020  * see also:
00021  *  D. E. Knuth: The Art of Computer Programming Vol.3 (Sorting and Searching)
00022  *
00023  * (C) 2000 Daniel Nagy, Budapest University of Technology and Economics
00024  * Released under GNU General Public License (GPL) version 2
00025  * 
00026 **/
00027 #include "ctl/ctldef.h"
00028 #include "ctl/tree.h"
00029 
00030 #ifndef CTL_UNIT
00031 
00032 
00033 /* Manufacture relative offset trees from templates, for unique and multi-copy sets */
00034 #define tree_temp_offset        ctlt_relative(0)
00035 #define tree_temp_multiple      ctlt_unique
00036 #include "ctl/tree.temp.h"
00037 #undef tree_temp_multiple
00038 #define tree_temp_multiple      ctlt_multiple
00039 #include "ctl/tree.temp.h"
00040 #undef tree_temp_multiple
00041 #undef tree_temp_offset
00042 /* Manufacture non-invasive tree base for map/multimap */
00043 #define tree_temp_offset        ctlt_after
00044 #define tree_temp_multiple      ctlt_unique
00045 #include "ctl/tree.temp.h"
00046 #undef tree_temp_multiple
00047 #define tree_temp_multiple      ctlt_multiple
00048 #include "ctl/tree.temp.h"
00049 #undef tree_temp_multiple
00050 #undef tree_temp_offset
00051 
00052 
00053 #else /* CTL_UNIT */
00054 #include <stdio.h>
00055 #include "unit/unit.h"
00056 #include "ctl/iset.h"
00057 #include "ctl/imultiset.h"
00058 #include "ctl/ctlstring.h"
00059 
00064 typedef struct TestData
00065 {
00066     int             value;
00067     ctlt_node_type(ctlt_relative(0),ctlt_unique)    link;
00068 } TestData;
00069 
00070 static int TestDataValues( const TestData* t1, const TestData* t2 )
00071 {
00072     return t1->value - t2->value;
00073 }
00074 
00075 /* Was static, but the warning about eating this got too tiresome */
00076 size_t printTestData( const void* data, char* buff, size_t buffSize )
00077 {
00078     TestData* tdata = (TestData*)data;
00079     return snprintf( buff, buffSize, "%d", tdata->value );
00080 }
00081 
00082 void Test_iset(void);
00083 void Test_imultiset(void);
00084 
00091 void Test_Tree(void)
00092 {
00093     TestData array[20];
00094     {
00095         ctl_tree_auto(ctlt_relative(offsetof(TestData,link)),ctlt_unique, TestDataValues, testTree );
00096         {
00097             /* Initialize array and build tree from array */
00098             int valCurr = 1;
00099             array_foreach( TestData, array, curr )
00100             {
00101                 curr->value = valCurr++;
00102                 ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, insert)( &testTree, curr );
00103             }
00104         }
00105         /* Show me tree */
00106 /* ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, pretty_print)( &testTree, printTestData, NULL ); */
00107         /* See that we have the predicted number of nodes */
00108         Test_Error( ctl_tree_size(ctlt_relative(offsetof(TestData,link)),ctlt_unique, &testTree ) == countof(array) );
00109         {
00110             /* Step through each sequentially */
00111             int valCurr = 1;
00112             ctl_iset_foreach(TestData,link, &testTree, tcurr )
00113             {
00114 /*              printf( "%d ", tcurr->value ); */
00115                 Test_Error( tcurr->value == valCurr++ )
00116             }
00117         }
00118         {
00119             /* Step through each in reverse */
00120             int valCurr = countof(array);
00121             ctl_iset_foreach_reverse(TestData,link, &testTree, tcurr )
00122             {
00123                 Test_Error( tcurr->value == valCurr-- )
00124             }
00125         }
00126 /* ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, pretty_print)( &testTree, printTestData, NULL ); */
00127         {
00128             TestData tmp = { 5, {0} };
00129             const void* found = ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, find)( &testTree, &tmp );
00130             Test_Error( NULL != found );
00131             Test_Error( ((TestData*)found)->value == tmp.value );
00132         }
00133         ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, reset)( &testTree );
00134     }
00135     {
00136         /* Shuffle array */
00137         array_foreach( TestData, array, curr )
00138         {
00139             int iRand = rand()%countof(array);
00140             int tmp = curr->value;
00141             curr->value = array[iRand].value;
00142             array[iRand].value = tmp;
00143         }
00144     }
00145     {
00146         /* Assemble tree from shuffled values */
00147         ctl_tree_auto(ctlt_relative(offsetof(TestData,link)),ctlt_unique, TestDataValues, testTree );
00148         array_foreach( TestData, array, curr )
00149         {
00150             ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, insert)( &testTree, curr );
00151         }
00152         {
00153             TestData tmp = { 5, {0} };
00154             const void* found = ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, find)( &testTree, &tmp );
00155             Test_Error( NULL != found );
00156             Test_Error( ((TestData*)found)->value == tmp.value );
00157         }
00158         /* See that we have the predicted number of nodes */
00159         Test_Error( ctl_tree_size(ctlt_relative(offsetof(TestData,link)),ctlt_unique, &testTree ) == countof(array) );
00160         {
00161             /* Step through each sequentially */
00162             int valCurr = 1;
00163             ctl_iset_foreach(TestData,link, &testTree, tcurr )
00164             {
00165                 Test_Error( tcurr->value == valCurr++ )
00166             }
00167         }
00168         {
00169             /* Step through each in reverse */
00170             int valCurr = countof(array);
00171             ctl_iset_foreach_reverse(TestData,link, &testTree, tcurr )
00172             {
00173                 Test_Error( tcurr->value == valCurr-- )
00174             }
00175         }
00176         /* Show me tree */
00177 /* ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, pretty_print)( &testTree, printTestData, NULL ); */
00178         {
00179             TestData tmp = { 5, {0} };
00180             const void* found = ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, remove)( &testTree, &tmp );
00181             Test_Error( NULL != found );
00182             Test_Error( ((TestData*)found)->value == tmp.value );
00183 /* ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, pretty_print)( &testTree, printTestData, NULL ); */
00184             tmp.value = 7;
00185             found = ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, remove)( &testTree, &tmp );
00186             Test_Error( NULL != found );
00187             Test_Error( ((TestData*)found)->value == tmp.value );
00188 /* ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, pretty_print)( &testTree, printTestData, NULL ); */
00189         }
00190         /* Show me tree */
00191         ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, reset)( &testTree );
00192     }
00193     /*
00194      * A couple more tests
00195      */
00196     UNIT_TEST(Test_iset);
00197     UNIT_TEST(Test_imultiset);
00198 }
00199 
00206 void Test_iset(void)
00207 {
00208     ctl_pool_auto(TestData, scratch,16);
00209     ctl_iset_auto(TestData,link, TestDataValues, testTree );
00210     const int range = 16;
00211     int iterations = rand_between(int32,100,300);
00212     {
00213         int seed = 16;
00214         TestData* addthis;
00215         while( seed-- )
00216         {
00217             ctl_pool_alloc( TestData, &scratch, addthis );
00218             addthis->value = seed;
00219             {
00220                 /* If we don't get back the same pointer, it's already in there. */
00221                 TestData* found = ctl_iset_insert(TestData,link, &testTree, addthis );
00222                 if( found != addthis )
00223                     ctl_pool_free(TestData, &scratch, addthis );
00224             }
00225         }
00226     }
00227     while( iterations-- )
00228     {
00229         {
00230             TestData delthis;
00231             delthis.value = rand()%range;
00232 /*          printf( "Delete %d\n", delthis.value ); */
00233             {
00234                 TestData* found = ctl_iset_remove(TestData,link, &testTree, &delthis );
00235                 if( found )
00236                     ctl_pool_free(TestData, &scratch, found );
00237 /* ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, pretty_print)( &testTree, printTestData, &found->link ); */
00238             }
00239         }
00240         {
00241             TestData* addthis;
00242             ctl_pool_alloc( TestData, &scratch, addthis );
00243             addthis->value = rand()%range;
00244 /*          printf( "Add %d\n", addthis->value ); */
00245             {
00246                 /* If we don't get back the same pointer, it's already in there. */
00247                 TestData* found = ctl_iset_insert(TestData,link, &testTree, addthis );
00248                 if( found != addthis )
00249                     ctl_pool_free(TestData, &scratch, addthis );
00250 /* ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, pretty_print)( &testTree, printTestData, &addthis->link ); */
00251             }
00252         }
00253         {
00254             /* Exercise iterators */
00255             TestData from, to;
00256             int prev;
00257             size_t total;
00258 /* ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, pretty_print)( &testTree, printTestData, NULL ); */
00259             total = 0;
00260             prev = -1;
00261 /*          printf( "Simple\n" ); */
00262             {
00263                 ctl_iset_foreach(TestData,link, &testTree, curr )
00264                 {
00265                     Test_Error( prev < curr->value );
00266                     prev = curr->value;
00267                     total++;
00268                 }
00269                 Test_Error( total == ctl_iset_size(TestData,link, &testTree) );
00270             }
00271             total = 0;
00272             prev = -1;
00273             {
00274                 ctl_iset_foreach_const(TestData,link, &testTree, curr )
00275                 {
00276                     Test_Error( prev < curr->value );
00277                     prev = curr->value;
00278                     total++;
00279                 }
00280                 Test_Error( total == ctl_iset_size(TestData,link, &testTree) );
00281             }
00282             total = 0;
00283             prev = (int)(~0u>>1);
00284             {
00285                 ctl_iset_foreach_reverse(TestData,link, &testTree, curr )
00286                 {
00287                     Test_Error( prev > curr->value );
00288                     prev = curr->value;
00289                     total++;
00290                 }
00291                 Test_Error( total == ctl_iset_size(TestData,link, &testTree) );
00292             }
00293             total = 0;
00294             prev = (int)(~0u>>1);
00295             {
00296                 ctl_iset_foreach_reverse_const(TestData,link, &testTree, curr )
00297                 {
00298                     Test_Error( prev > curr->value );
00299                     prev = curr->value;
00300                     total++;
00301                 }
00302                 Test_Error( total == ctl_iset_size(TestData,link, &testTree) );
00303             }
00304             /* Now do partial sets */
00305 /*          printf( "Partial\n" ); */
00306             total = 0;
00307             from.value = rand()%range;
00308             prev = from.value-1;
00309             {
00310                 ctl_iset_from(TestData,link, &testTree, &from, curr )
00311                 {
00312                     Test_Error( curr->value >= from.value );
00313                     Test_Error( prev < curr->value );
00314                     prev = curr->value;
00315                     total++;
00316                 }
00317                 Test_Error( total <= ctl_iset_size(TestData,link, &testTree) );
00318             }
00319             total = 0;
00320             from.value = rand()%range;
00321             prev = from.value-1;
00322             {
00323                 ctl_iset_from_const(TestData,link, &testTree, &from, curr )
00324                 {
00325                     Test_Error( curr->value >= from.value );
00326                     Test_Error( prev < curr->value );
00327                     prev = curr->value;
00328                     total++;
00329                 }
00330                 Test_Error( total <= ctl_iset_size(TestData,link, &testTree) );
00331             }
00332             total = 0;
00333             from.value = rand()%range;
00334             prev = from.value+1;
00335             {
00336                 ctl_iset_from_reverse(TestData,link, &testTree, &from, curr )
00337                 {
00338                     Test_Error( curr->value <= from.value );
00339                     Test_Error( prev > curr->value );
00340                     prev = curr->value;
00341                     total++;
00342                 }
00343                 Test_Error( total <= ctl_iset_size(TestData,link, &testTree) );
00344             }
00345             total = 0;
00346             from.value = rand()%range;
00347             prev = from.value+1;
00348             {
00349                 ctl_iset_from_reverse_const(TestData,link, &testTree, &from, curr )
00350                 {
00351                     Test_Error( curr->value <= from.value );
00352                     Test_Error( prev > curr->value );
00353                     prev = curr->value;
00354                     total++;
00355                 }
00356                 Test_Error( total <= ctl_iset_size(TestData,link, &testTree) );
00357             }
00358             /* Now do subsets */
00359 /*          printf( "Subset\n" ); */
00360             total = 0;
00361             from.value = rand()%range;
00362             to.value = rand()%range;
00363             prev = from.value-1;
00364             {
00365                 ctl_iset_from_to(TestData,link, &testTree, &from, &to, curr )
00366                 {
00367                     Test_Error( curr->value >= from.value && curr->value < to.value  );
00368                     Test_Error( prev < curr->value );
00369                     prev = curr->value;
00370                     total++;
00371                 }
00372                 Test_Error( total <= ctl_iset_size(TestData,link, &testTree) );
00373             }
00374             total = 0;
00375             from.value = rand()%range;
00376             to.value = rand()%range;
00377             prev = from.value-1;
00378             {
00379                 ctl_iset_from_to_const(TestData,link, &testTree, &from, &to, curr )
00380                 {
00381                     Test_Error( curr->value >= from.value && curr->value < to.value );
00382                     Test_Error( prev < curr->value );
00383                     prev = curr->value;
00384                     total++;
00385                 }
00386                 Test_Error( total <= ctl_iset_size(TestData,link, &testTree) );
00387             }
00388             total = 0;
00389             from.value = rand()%range;
00390             to.value = rand()%range;
00391             prev = from.value+1;
00392             {
00393                 ctl_iset_from_to_reverse(TestData,link, &testTree, &from, &to, curr )
00394                 {
00395                     Test_Error( curr->value <= from.value && curr->value > to.value );
00396                     Test_Error( prev > curr->value );
00397                     prev = curr->value;
00398                     total++;
00399                 }
00400                 Test_Error( total <= ctl_iset_size(TestData,link, &testTree) );
00401             }
00402             total = 0;
00403             from.value = rand()%range;
00404             to.value = rand()%range;
00405             prev = from.value+1;
00406             {
00407                 ctl_iset_from_to_reverse_const(TestData,link, &testTree, &from, &to, curr )
00408                 {
00409                     Test_Error( curr->value <= from.value && curr->value > to.value );
00410                     Test_Error( prev > curr->value );
00411                     prev = curr->value;
00412                     total++;
00413                 }
00414                 Test_Error( total <= ctl_iset_size(TestData,link, &testTree) );
00415             }
00416         }
00417     }
00418     ctl_iset_reset( TestData,link, &testTree );
00419     ctl_pool_destroy(TestData, &scratch);
00420 }
00421 
00428 void Test_imultiset(void)
00429 {
00430     ctl_pool_auto(TestData, scratch,16);
00431     ctl_imultiset_auto(TestData,link, TestDataValues, testTree );
00432     const int range = 16;
00433     int iterations = rand_between(int32,100,300);
00434     while( iterations-- )
00435     {
00436         {
00437             TestData delthis;
00438             delthis.value = rand()%range;
00439 /*printf( "Delete %d\n", delthis.value ); */
00440 /* ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, pretty_print)( &testTree, printTestData, NULL ); */
00441             {
00442                 TestData* found = ctl_imultiset_remove(TestData,link, &testTree, &delthis );
00443                 if( found )
00444                     ctl_pool_free(TestData, &scratch, found );
00445 /* ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, pretty_print)( &testTree, printTestData, &found->link ); */
00446             }
00447         }
00448         {
00449             TestData* addthis;
00450             ctl_pool_alloc( TestData, &scratch, addthis );
00451             addthis->value = rand()%range;
00452 /*printf( "Add %d\n", addthis->value ); */
00453             {
00454                 /* If we don't get back the same pointer, it's already in there. */
00455                 TestData* found = ctl_imultiset_insert(TestData,link, &testTree, addthis );
00456                 if( found != addthis )
00457                     ctl_pool_free(TestData, &scratch, addthis );
00458 /* ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, pretty_print)( &testTree, printTestData, &addthis->link ); */
00459             }
00460         }
00461         {
00462             /* Exercise iterators */
00463             TestData from, to;
00464             int prev;
00465             size_t total;
00466 /* ctl_tree_(ctlt_relative(offsetof(TestData,link)),ctlt_unique, pretty_print)( &testTree, printTestData, NULL ); */
00467             total = 0;
00468             prev = -1;
00469 /*          printf( "Simple\n" ); */
00470             {
00471                 ctl_imultiset_foreach(TestData,link, &testTree, curr )
00472                 {
00473                     Test_Error( prev <= curr->value );
00474                     prev = curr->value;
00475                     total++;
00476                 }
00477                 Test_Error( total == ctl_imultiset_size(TestData,link, &testTree) );
00478             }
00479             total = 0;
00480             prev = -1;
00481             {
00482                 ctl_imultiset_foreach_const(TestData,link, &testTree, curr )
00483                 {
00484                     Test_Error( prev <= curr->value );
00485                     prev = curr->value;
00486                     total++;
00487                 }
00488                 Test_Error( total == ctl_imultiset_size(TestData,link, &testTree) );
00489             }
00490             total = 0;
00491             prev = (int)(~0u>>1);
00492             {
00493                 ctl_imultiset_foreach_reverse(TestData,link, &testTree, curr )
00494                 {
00495                     Test_Error( prev >= curr->value );
00496                     prev = curr->value;
00497                     total++;
00498                 }
00499                 Test_Error( total == ctl_imultiset_size(TestData,link, &testTree) );
00500             }
00501             total = 0;
00502             prev = (int)(~0u>>1);
00503             {
00504                 ctl_imultiset_foreach_reverse_const(TestData,link, &testTree, curr )
00505                 {
00506                     Test_Error( prev >= curr->value );
00507                     prev = curr->value;
00508                     total++;
00509                 }
00510                 Test_Error( total == ctl_imultiset_size(TestData,link, &testTree) );
00511             }
00512             /* Now do partial multisets */
00513 /*          printf( "Partial\n" ); */
00514             total = 0;
00515             from.value = rand()%range;
00516             prev = from.value-1;
00517             {
00518                 ctl_imultiset_from(TestData,link, &testTree, &from, curr )
00519                 {
00520                     Test_Error( curr->value >= from.value );
00521                     Test_Error( prev <= curr->value );
00522                     prev = curr->value;
00523                     total++;
00524                 }
00525                 Test_Error( total <= ctl_imultiset_size(TestData,link, &testTree) );
00526             }
00527             total = 0;
00528             from.value = rand()%range;
00529             prev = from.value-1;
00530             {
00531                 ctl_imultiset_from_const(TestData,link, &testTree, &from, curr )
00532                 {
00533                     Test_Error( curr->value >= from.value );
00534                     Test_Error( prev <= curr->value );
00535                     prev = curr->value;
00536                     total++;
00537                 }
00538                 Test_Error( total <= ctl_imultiset_size(TestData,link, &testTree) );
00539             }
00540             total = 0;
00541             from.value = rand()%range;
00542             prev = from.value+1;
00543             {
00544                 ctl_imultiset_from_reverse(TestData,link, &testTree, &from, curr )
00545                 {
00546                     Test_Error( curr->value <= from.value );
00547                     Test_Error( prev >= curr->value );
00548                     prev = curr->value;
00549                     total++;
00550                 }
00551                 Test_Error( total <= ctl_imultiset_size(TestData,link, &testTree) );
00552             }
00553             total = 0;
00554             from.value = rand()%range;
00555             prev = from.value+1;
00556             {
00557                 ctl_imultiset_from_reverse_const(TestData,link, &testTree, &from, curr )
00558                 {
00559                     Test_Error( curr->value <= from.value );
00560                     Test_Error( prev >= curr->value );
00561                     prev = curr->value;
00562                     total++;
00563                 }
00564                 Test_Error( total <= ctl_imultiset_size(TestData,link, &testTree) );
00565             }
00566             /* Now do susets */
00567 /*          printf( "Subset\n" ); */
00568             total = 0;
00569             from.value = rand()%range;
00570             to.value = rand()%range;
00571             prev = from.value-1;
00572             {
00573                 ctl_imultiset_from_to(TestData,link, &testTree, &from, &to, curr )
00574                 {
00575                     Test_Error( curr->value >= from.value && curr->value < to.value  );
00576                     Test_Error( prev <= curr->value );
00577                     prev = curr->value;
00578                     total++;
00579                 }
00580                 Test_Error( total <= ctl_imultiset_size(TestData,link, &testTree) );
00581             }
00582             total = 0;
00583             from.value = rand()%range;
00584             to.value = rand()%range;
00585             prev = from.value-1;
00586             {
00587                 ctl_imultiset_from_to_const(TestData,link, &testTree, &from, &to, curr )
00588                 {
00589                     Test_Error( curr->value >= from.value && curr->value < to.value );
00590                     Test_Error( prev <= curr->value );
00591                     prev = curr->value;
00592                     total++;
00593                 }
00594                 Test_Error( total <= ctl_imultiset_size(TestData,link, &testTree) );
00595             }
00596             total = 0;
00597             from.value = rand()%range;
00598             to.value = rand()%range;
00599             prev = from.value+1;
00600             {
00601                 ctl_imultiset_from_to_reverse(TestData,link, &testTree, &from, &to, curr )
00602                 {
00603                     Test_Error( curr->value <= from.value && curr->value > to.value );
00604                     Test_Error( prev >= curr->value );
00605                     prev = curr->value;
00606                     total++;
00607                 }
00608                 Test_Error( total <= ctl_imultiset_size(TestData,link, &testTree) );
00609             }
00610             total = 0;
00611             from.value = rand()%range;
00612             to.value = rand()%range;
00613             prev = from.value+1;
00614             {
00615                 ctl_imultiset_from_to_reverse_const(TestData,link, &testTree, &from, &to, curr )
00616                 {
00617                     Test_Error( curr->value <= from.value && curr->value > to.value );
00618                     Test_Error( prev >= curr->value );
00619                     prev = curr->value;
00620                     total++;
00621                 }
00622                 Test_Error( total <= ctl_imultiset_size(TestData,link, &testTree) );
00623             }
00624         }
00625     }
00626     ctl_imultiset_reset( TestData,link, &testTree );
00627     ctl_pool_destroy(TestData, &scratch);
00628 }
00629 
00630 #endif /* CTL_UNIT */

Generated on Fri Jan 2 15:28:35 2009 for Squat by  doxygen 1.5.6