Home | History | Annotate | Download | only in tests
      1 
      2 #include <assert.h>
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 
      7 #include "pub_core_basics.h"
      8 #include "pub_core_libcbase.h"
      9 #include "pub_core_libcassert.h"
     10 #include "pub_core_libcprint.h"
     11 
     12 // I need this to avoid some signedness warnings, not sure why
     13 // #define Char char
     14 // jrs 19 Aug 2005: m_oset.c relies on Char being a signed char.
     15 // It appears that plain 'char' on ppc32 is unsigned and so the
     16 // above #define screws up the AVL tree balancing logic and
     17 // leads to segfaults.  Commenting it out and using the standard
     18 // definition of Char from pub_core_basics.h seems a good solution
     19 // as that has the same signedness on all platforms.
     20 
     21 // Crudely redirect various VG_(foo)() functions to their libc equivalents.
     22 #undef vg_assert
     23 #define vg_assert(e)                   assert(e)
     24 #undef vg_assert2
     25 #define vg_assert2(e, fmt, args...)    assert(e)
     26 
     27 #define vgPlain_printf                 printf
     28 #define vgPlain_memset                 memset
     29 #define vgPlain_memcpy                 memcpy
     30 #define vgPlain_memmove                memmove
     31 #define vgPlain_strcmp                 strcmp
     32 
     33 // Crudely replace some functions (in m_xarray.c, but not needed for
     34 // this unit test) by (hopefully) failing asserts.
     35 #define vgPlain_ssort(a,b,c,d) assert(a)
     36 #define vgPlain_vcbprintf(a,b,...) assert(a == b)
     37 #include "coregrind/m_xarray.c"
     38 #undef vgPlain_ssort
     39 #undef vgPlain_vcbprintf
     40 #include "coregrind/m_poolalloc.c"
     41 #include "coregrind/m_oset.c"
     42 
     43 #define NN  1000       // Size of OSets being created
     44 
     45 
     46 /* Consistent random number generator, so it produces the
     47    same results on all platforms. */
     48 
     49 #define random error_do_not_use_libc_random
     50 
     51 static UInt seed = 0;
     52 static UInt myrandom( void )
     53 {
     54   seed = (1103515245 * seed + 12345);
     55   return seed;
     56 }
     57 
     58 static void* allocate_node(const HChar* cc, SizeT szB)
     59 { return malloc(szB); }
     60 
     61 static void free_node(void* p)
     62 { return free(p); }
     63 
     64 
     65 //---------------------------------------------------------------------------
     66 // Word example
     67 //---------------------------------------------------------------------------
     68 
     69 // This example shows that an element can be a single value (in this
     70 // case a Word), in which case the element is also the key.
     71 
     72 __attribute__((unused))
     73 static const HChar *wordToStr(const void *p)
     74 {
     75    static HChar buf[32];
     76    sprintf(buf, "%ld", *(Word*)p);
     77    return buf;
     78 }
     79 
     80 __attribute__((unused))
     81 static Word wordCmp(void* vkey, void* velem)
     82 {
     83    return *(Word*)vkey - *(Word*)velem;
     84 }
     85 
     86 void example1singleset(OSet* oset, char *descr)
     87 {
     88    Int  i, n;
     89    UWord v, prev;
     90    UWord* vs[NN];
     91    UWord *pv;
     92    UWord  sorted_elts[NN]; // Used to test VG_(OSetGen_ResetIterAt)
     93 
     94    // Try some operations on an empty OSet to ensure they don't screw up.
     95    vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
     96    vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
     97    vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
     98    vg_assert( ! VG_(OSetGen_Next)(oset) );
     99    vg_assert( 0 == VG_(OSetGen_Size)(oset) );
    100 
    101    // Create some elements, with gaps (they're all even) but no dups,
    102    // and shuffle them randomly.
    103    for (i = 0; i < NN; i++) {
    104       vs[i] = VG_(OSetGen_AllocNode)(oset, sizeof(Word));
    105       *(vs[i]) = 2*(i+1);
    106       sorted_elts[i] = *(vs[i]);
    107    }
    108    seed = 0;
    109    for (i = 0; i < NN; i++) {
    110       UWord r1  = myrandom() % NN;
    111       UWord r2  = myrandom() % NN;
    112       UWord* tmp= vs[r1];
    113       vs[r1]   = vs[r2];
    114       vs[r2]   = tmp;
    115    }
    116 
    117    // Insert the elements
    118    for (i = 0; i < NN; i++) {
    119       VG_(OSetGen_Insert)(oset, vs[i]);
    120    }
    121 
    122    // Check the size
    123    vg_assert( NN == VG_(OSetGen_Size)(oset) );
    124 
    125    // Check we can find all the elements we inserted
    126    for (i = 0; i < NN; i++) {
    127       assert( VG_(OSetGen_Contains)(oset, vs[i]) );
    128    }
    129 
    130 #define FULLCHECKEVERY 20
    131    // Check VG_(OSetGen_ResetIterAt) works before, at, and after each element.
    132    // For some elements, we check all the successive elements.
    133    for (i = 0; i < NN; i++) {
    134       UWord k;
    135       UWord *pval;
    136       Int j;
    137 
    138       // check ResetIterAt just before an elt gives this elt.
    139       k = sorted_elts[i] - 1;
    140       VG_(OSetGen_ResetIterAt) (oset, &k);
    141       // Check all elts till the end
    142       for (j = i; j < NN; j++) {
    143          pval = VG_(OSetGen_Next)(oset);
    144          assert (*pval == sorted_elts[j]);
    145          if (i % FULLCHECKEVERY != 0) break;
    146       }
    147 
    148       // check ResetIterAt at an elt gives this elt.
    149       k = sorted_elts[i];
    150       VG_(OSetGen_ResetIterAt) (oset, &k);
    151       // Check all elts till the end
    152       for (j = i; j < NN; j++) {
    153          pval = VG_(OSetGen_Next)(oset);
    154          assert (*pval == sorted_elts[j]);
    155          if (i % FULLCHECKEVERY != 0) break;
    156       }
    157 
    158       // check ResetIterAt after an elt gives the next elt or nothing
    159       // when we reset after the last elt.
    160       k = sorted_elts[i] + 1;
    161       VG_(OSetGen_ResetIterAt) (oset, &k);
    162       if (i < NN - 1) {
    163          for (j = i+1; j < NN; j++) {
    164             pval = VG_(OSetGen_Next)(oset);
    165             assert (*pval == sorted_elts[j]);
    166             if (i % FULLCHECKEVERY != 0) break;
    167          }
    168       } else {
    169          pval = VG_(OSetGen_Next)(oset);
    170          assert (pval == NULL);
    171       }
    172 
    173    }
    174 
    175    // Check we cannot find elements we did not insert, below, within (odd
    176    // numbers), and above the inserted elements.
    177    v = 0;
    178    assert( ! VG_(OSetGen_Contains)(oset, &v) );
    179    for (i = 0; i < NN; i++) {
    180       v = *(vs[i]) + 1;
    181       assert( ! VG_(OSetGen_Contains)(oset, &v) );
    182    }
    183    v = 2*(NN+1);
    184    assert( ! VG_(OSetGen_Contains)(oset, &v) );
    185 
    186    // Check we can find all the elements we inserted, and the right values
    187    // are returned.
    188    for (i = 0; i < NN; i++) {
    189       assert( vs[i] == VG_(OSetGen_Lookup)(oset, vs[i]) );
    190    }
    191 
    192    // Check that we can iterate over the OSet elements in sorted order, and
    193    // there is the right number of them.
    194    n = 0;
    195    pv = NULL;
    196    prev = 0;
    197    VG_(OSetGen_ResetIter)(oset);
    198    while ( (pv = VG_(OSetGen_Next)(oset)) ) {
    199       UWord curr = *pv;
    200       assert(prev < curr);
    201       prev = curr;
    202       n++;
    203    }
    204    assert(NN == n);
    205    vg_assert( ! VG_(OSetGen_Next)(oset) );
    206    vg_assert( ! VG_(OSetGen_Next)(oset) );
    207 
    208    // Check that we can remove half of the elements, and that their values
    209    // are as expected.
    210    for (i = 0; i < NN; i += 2) {
    211       pv = VG_(OSetGen_Remove)(oset, vs[i]);
    212       assert( pv );
    213       assert( pv == vs[i] );
    214    }
    215 
    216    // Check the size
    217    vg_assert( NN/2 == VG_(OSetGen_Size)(oset) );
    218 
    219    // Check we can find the remaining elements (with the right values).
    220    for (i = 1; i < NN; i += 2) {
    221       pv = VG_(OSetGen_LookupWithCmp)(oset, vs[i], NULL);
    222       assert( pv );
    223       assert( pv == vs[i] );
    224    }
    225 
    226    // Check we cannot find any of the elements we removed.
    227    for (i = 0; i < NN; i += 2) {
    228       assert( ! VG_(OSetGen_Contains)(oset, vs[i]) );
    229    }
    230 
    231    // Check that we can remove the remaining half of the elements, and that
    232    // their values are as expected.
    233    for (i = 1; i < NN; i += 2) {
    234       pv = VG_(OSetGen_Remove)(oset, vs[i]);
    235       assert( pv );
    236       assert( pv == vs[i] );
    237    }
    238 
    239    // Try some more operations on the empty OSet to ensure they don't screw up.
    240    vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
    241    vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
    242    vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
    243    vg_assert( ! VG_(OSetGen_Next)(oset) );
    244    vg_assert( 0 == VG_(OSetGen_Size)(oset) );
    245 
    246    // Free a few elements
    247    VG_(OSetGen_FreeNode)(oset, vs[0]);
    248    VG_(OSetGen_FreeNode)(oset, vs[1]);
    249    VG_(OSetGen_FreeNode)(oset, vs[2]);
    250 
    251    // Re-insert remaining elements, to give OSetGen_Destroy something to
    252    // work with.
    253    for (i = 3; i < NN; i++) {
    254       VG_(OSetGen_Insert)(oset, vs[i]);
    255    }
    256 
    257    // Print the list
    258    OSet_Print(oset, descr, wordToStr);
    259 
    260 }
    261 
    262 void example1(void)
    263 {
    264    OSet *oset, *oset_empty_clone;
    265 
    266    // Create a static OSet of UWords.  This one uses fast (built-in)
    267    // comparisons.
    268 
    269    // First a single oset, no pool allocator.
    270    oset = VG_(OSetGen_Create)(0,
    271                               NULL,
    272                               allocate_node, "oset_test.1", free_node);
    273    example1singleset(oset, "single oset, no pool allocator");
    274 
    275    // Destroy the OSet
    276    VG_(OSetGen_Destroy)(oset);
    277 
    278    // Then same, but with a group allocator
    279    oset = VG_(OSetGen_Create_With_Pool)(0,
    280                                         NULL,
    281                                         allocate_node, "oset_test.1",
    282                                         free_node,
    283                                         101, sizeof(Word));
    284    example1singleset(oset, "single oset, pool allocator");
    285 
    286    // Destroy the OSet
    287    VG_(OSetGen_Destroy)(oset);
    288 
    289 
    290    // Then two sets, sharing a group allocator.
    291    oset = VG_(OSetGen_Create_With_Pool)
    292       (0,
    293        NULL,
    294        allocate_node, "oset_test.1", free_node,
    295        101, sizeof(Word));
    296    oset_empty_clone = VG_(OSetGen_EmptyClone) (oset);
    297    example1singleset(oset, "oset, shared pool");
    298    example1singleset(oset_empty_clone, "cloned oset, shared pool");
    299    // Destroy both OSet
    300 
    301    VG_(OSetGen_Destroy)(oset_empty_clone);
    302    VG_(OSetGen_Destroy)(oset);
    303 
    304 }
    305 
    306 void example1b(void)
    307 {
    308    Int  i, n;
    309    UWord v = 0, prev;
    310    UWord vs[NN];
    311 
    312    // Create a static OSet of UWords.  This one uses fast (built-in)
    313    // comparisons.
    314    OSet* oset = VG_(OSetWord_Create)(allocate_node, "oset_test.2", free_node);
    315 
    316    // Try some operations on an empty OSet to ensure they don't screw up.
    317    vg_assert( ! VG_(OSetWord_Contains)(oset, v) );
    318    vg_assert( ! VG_(OSetWord_Remove)(oset, v) );
    319    vg_assert( ! VG_(OSetWord_Next)(oset, (UWord *)&v) );
    320    vg_assert( 0 == VG_(OSetWord_Size)(oset) );
    321 
    322    // Create some elements, with gaps (they're all even) but no dups,
    323    // and shuffle them randomly.
    324    for (i = 0; i < NN; i++) {
    325       vs[i] = 2*i;
    326    }
    327    seed = 0;
    328    for (i = 0; i < NN; i++) {
    329       UWord r1  = myrandom() % NN;
    330       UWord r2  = myrandom() % NN;
    331       UWord tmp = vs[r1];
    332       vs[r1]   = vs[r2];
    333       vs[r2]   = tmp;
    334    }
    335 
    336    // Insert the elements
    337    for (i = 0; i < NN; i++) {
    338       VG_(OSetWord_Insert)(oset, vs[i]);
    339    }
    340 
    341    // Check the size
    342    vg_assert( NN == VG_(OSetWord_Size)(oset) );
    343 
    344    // Check we can find all the elements we inserted
    345    for (i = 0; i < NN; i++) {
    346       assert( VG_(OSetWord_Contains)(oset, vs[i]) );
    347    }
    348 
    349    // Check we cannot find elements we did not insert, below, within (odd
    350    // numbers), and above the inserted elements.
    351    v = 0xffffffff;
    352    assert( ! VG_(OSetWord_Contains)(oset, v) );
    353    for (i = 0; i < NN; i++) {
    354       v = vs[i] + 1;
    355       assert( ! VG_(OSetWord_Contains)(oset, v) );
    356    }
    357    v = NN*2;
    358    assert( ! VG_(OSetWord_Contains)(oset, v) );
    359 
    360    // Check we can find all the elements we inserted.
    361    for (i = 0; i < NN; i++) {
    362       assert( VG_(OSetWord_Contains)(oset, vs[i]) );
    363    }
    364 
    365    // Check that we can iterate over the OSet elements in sorted order, and
    366    // there is the right number of them.
    367    n = 0;
    368    prev = 0;
    369    VG_(OSetWord_ResetIter)(oset);
    370    while ( VG_(OSetWord_Next)(oset, (UWord *)&v) ) {
    371       UWord curr = v;
    372       if (n == 0)
    373          assert(prev == curr);
    374       else
    375          assert(prev < curr);
    376       prev = curr;
    377       n++;
    378    }
    379    assert(NN == n);
    380    vg_assert( ! VG_(OSetWord_Next)(oset, (UWord *)&v) );
    381    vg_assert( ! VG_(OSetWord_Next)(oset, (UWord *)&v) );
    382 
    383    // Check that we can remove half of the elements.
    384    for (i = 0; i < NN; i += 2) {
    385       assert( VG_(OSetWord_Remove)(oset, vs[i]) );
    386    }
    387 
    388    // Check the size
    389    vg_assert( NN/2 == VG_(OSetWord_Size)(oset) );
    390 
    391    // Check we can find the remaining elements (with the right values).
    392    for (i = 1; i < NN; i += 2) {
    393       assert( VG_(OSetWord_Contains)(oset, vs[i]) );
    394    }
    395 
    396    // Check we cannot find any of the elements we removed.
    397    for (i = 0; i < NN; i += 2) {
    398       assert( ! VG_(OSetWord_Contains)(oset, vs[i]) );
    399    }
    400 
    401    // Check that we can remove the remaining half of the elements.
    402    for (i = 1; i < NN; i += 2) {
    403       assert( VG_(OSetWord_Remove)(oset, vs[i]) );
    404    }
    405 
    406    // Try some more operations on the empty OSet to ensure they don't screw up.
    407    vg_assert( ! VG_(OSetWord_Contains)(oset, v) );
    408    vg_assert( ! VG_(OSetWord_Remove)(oset, v) );
    409    vg_assert( ! VG_(OSetWord_Next)(oset, (UWord *)&v) );
    410    vg_assert( 0 == VG_(OSetWord_Size)(oset) );
    411 
    412    // Re-insert remaining elements, to give OSetWord_Destroy something to
    413    // work with.
    414    for (i = 3; i < NN; i++) {
    415       VG_(OSetWord_Insert)(oset, vs[i]);
    416    }
    417 
    418    // Print the list
    419    OSet_Print(oset, "oset1b", wordToStr);
    420 
    421    // Destroy the OSet
    422    VG_(OSetWord_Destroy)(oset);
    423 }
    424 
    425 
    426 //---------------------------------------------------------------------------
    427 // Struct example
    428 //---------------------------------------------------------------------------
    429 
    430 // This element shows that a key can be in the middle of the element, and
    431 // be of arbitrary size and even span multiple (contiguous) fields.  It
    432 // also demonstrates how an OSet can be used to implement a list of
    433 // non-overlapping intervals.
    434 
    435 typedef struct {
    436    Int   b1;
    437    Addr  first;
    438    Addr  last;
    439    Int   b2;
    440 }
    441 Block;
    442 
    443 __attribute__((unused))
    444 static HChar *blockToStr(void *p)
    445 {
    446    static HChar buf[32];
    447    Block* b = (Block*)p;
    448    sprintf(buf, "<(%d) %lu..%lu (%d)>", b->b1, b->first, b->last, b->b2);
    449    return buf;
    450 }
    451 
    452 static Word blockCmp(const void* vkey, const void* velem)
    453 {
    454    Addr   key  = *(const Addr*)vkey;
    455    const Block* elem = (const Block*)velem;
    456 
    457    assert(elem->first <= elem->last);
    458    if (key < elem->first) return -1;
    459    if (key > elem->last)  return  1;
    460    return 0;
    461 }
    462 
    463 void example2(void)
    464 {
    465    Int i, n;
    466    Addr a;
    467    Block* vs[NN];
    468    Block v, prev;
    469    Block *pv;
    470 
    471    // Create a dynamic OSet of Blocks.  This one uses slow (custom)
    472    // comparisons.
    473    OSet* oset = VG_(OSetGen_Create)(offsetof(Block, first),
    474                                     blockCmp,
    475                                     allocate_node, "oset_test.3", free_node);
    476 
    477    // Try some operations on an empty OSet to ensure they don't screw up.
    478    vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
    479    vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
    480    vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
    481    vg_assert( ! VG_(OSetGen_Next)(oset) );
    482    vg_assert( 0 == VG_(OSetGen_Size)(oset) );
    483 
    484    // Create some inputs, with gaps -- intervals are 1..3, 11..13, ... -- but
    485    // no dups, and shuffle them randomly.
    486    for (i = 0; i < NN; i++) {
    487       vs[i] = VG_(OSetGen_AllocNode)(oset, sizeof(Block));
    488       vs[i]->b1    = i;
    489       vs[i]->first = i*10 + 1;
    490       vs[i]->last  = vs[i]->first + 2;
    491       vs[i]->b2    = i+1;
    492    }
    493    seed = 0;
    494    for (i = 0; i < NN; i++) {
    495       Int r1  = myrandom() % NN;
    496       Int r2  = myrandom() % NN;
    497       Block* tmp = vs[r1];
    498       vs[r1]  = vs[r2];
    499       vs[r2]  = tmp;
    500    }
    501 
    502    // Insert the elements
    503    for (i = 0; i < NN; i++) {
    504       VG_(OSetGen_Insert)(oset, vs[i]);
    505    }
    506 
    507    // Check the size
    508    vg_assert( NN == VG_(OSetGen_Size)(oset) );
    509 
    510    // Check we can find all the elements we inserted, within the full range
    511    // of each Block.
    512    for (i = 0; i < NN; i++) {
    513       a = vs[i]->first + 0;    assert( VG_(OSetGen_Contains)(oset, &a) );
    514       a = vs[i]->first + 1;    assert( VG_(OSetGen_Contains)(oset, &a) );
    515       a = vs[i]->first + 2;    assert( VG_(OSetGen_Contains)(oset, &a) );
    516    }
    517 
    518    // Check we cannot find elements we did not insert, below and above the
    519    // ranges of the inserted elements.
    520    a = 0;
    521    assert( ! VG_(OSetGen_Contains)(oset, &a) );
    522    for (i = 0; i < NN; i++) {
    523       a = vs[i]->first - 1;    assert( ! VG_(OSetGen_Contains)(oset, &a) );
    524       a = vs[i]->first + 3;    assert( ! VG_(OSetGen_Contains)(oset, &a) );
    525    }
    526 
    527    // Check we can find all the elements we inserted, and the right values
    528    // are returned.
    529    for (i = 0; i < NN; i++) {
    530       a = vs[i]->first + 0;    assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
    531       a = vs[i]->first + 1;    assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
    532       a = vs[i]->first + 2;    assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
    533       assert( vs[i] == VG_(OSetGen_LookupWithCmp)(oset, &a, blockCmp) );
    534    }
    535 
    536    // Check that we can iterate over the OSet elements in sorted order, and
    537    // there is the right number of them.
    538    n = 0;
    539    pv = NULL;
    540    prev.last = 0;
    541    VG_(OSetGen_ResetIter)(oset);
    542    while ( (pv = VG_(OSetGen_Next)(oset)) ) {
    543       Block curr = *pv;
    544       assert(prev.last < curr.first);
    545       prev = curr;
    546       n++;
    547    }
    548    assert(NN == n);
    549    vg_assert( ! VG_(OSetGen_Next)(oset) );
    550    vg_assert( ! VG_(OSetGen_Next)(oset) );
    551 
    552    // Check that we can remove half of the elements, and that their values
    553    // are as expected.
    554    for (i = 0; i < NN; i += 2) {
    555       a = vs[i]->first;    assert( vs[i] == VG_(OSetGen_Remove)(oset, &a) );
    556    }
    557 
    558    // Check the size
    559    vg_assert( NN/2 == VG_(OSetGen_Size)(oset) );
    560 
    561    // Check we can find the remaining elements (with the right values).
    562    for (i = 1; i < NN; i += 2) {
    563       a = vs[i]->first + 0;    assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
    564       a = vs[i]->first + 1;    assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
    565       a = vs[i]->first + 2;    assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
    566    }
    567 
    568    // Check we cannot find any of the elements we removed.
    569    for (i = 0; i < NN; i += 2) {
    570       a = vs[i]->first + 0;    assert( ! VG_(OSetGen_Contains)(oset, &a) );
    571       a = vs[i]->first + 1;    assert( ! VG_(OSetGen_Contains)(oset, &a) );
    572       a = vs[i]->first + 2;    assert( ! VG_(OSetGen_Contains)(oset, &a) );
    573    }
    574 
    575    // Check that we can remove the remaining half of the elements, and that
    576    // their values are as expected.
    577    for (i = 1; i < NN; i += 2) {
    578       a = vs[i]->first;    assert( vs[i] == VG_(OSetGen_Remove)(oset, &a) );
    579    }
    580 
    581    // Try some more operations on the empty OSet to ensure they don't screw up.
    582    vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
    583    vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
    584    vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
    585    vg_assert( ! VG_(OSetGen_Next)(oset) );
    586    vg_assert( 0 == VG_(OSetGen_Size)(oset) );
    587 
    588    // Re-insert all elements, to give OSetGen_Destroy something to work with.
    589    for (i = 0; i < NN; i++) {
    590       VG_(OSetGen_Insert)(oset, vs[i]);
    591    }
    592 
    593    // Destroy the OSet
    594    VG_(OSetGen_Destroy)(oset);
    595 }
    596 
    597 //-----------------------------------------------------------------------
    598 // main()
    599 //-----------------------------------------------------------------------
    600 
    601 int main(void)
    602 {
    603    example1();
    604    example1b();
    605    example2();
    606    return 0;
    607 }
    608