00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <assert.h>
00027 #include <limits.h>
00028 #include <stdarg.h>
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <time.h>
00033 #include "test.h"
00034
00035
00036 enum insert_order
00037 {
00038 INS_RANDOM,
00039 INS_ASCENDING,
00040 INS_DESCENDING,
00041 INS_BALANCED,
00042 INS_ZIGZAG,
00043 INS_ASCENDING_SHIFTED,
00044 INS_CUSTOM,
00045
00046 INS_CNT
00047 };
00048
00049
00050 enum delete_order
00051 {
00052 DEL_RANDOM,
00053 DEL_REVERSE,
00054 DEL_SAME,
00055 DEL_CUSTOM,
00056
00057 DEL_CNT
00058 };
00059
00060
00061 enum mt_policy
00062 {
00063 MT_TRACK,
00064 MT_NO_TRACK,
00065 MT_FAIL_COUNT,
00066 MT_FAIL_PERCENT,
00067 MT_SUBALLOC
00068 };
00069
00070
00071 struct option
00072 {
00073 const char *long_name;
00074 int short_name;
00075 int has_arg;
00076 };
00077
00078
00079 enum test
00080 {
00081 TST_CORRECTNESS,
00082 TST_OVERFLOW,
00083 TST_NULL
00084 };
00085
00086
00087 struct test_options
00088 {
00089 enum test test;
00090 enum insert_order insert_order;
00091 enum delete_order delete_order;
00092
00093 enum mt_policy alloc_policy;
00094 int alloc_arg[2];
00095 int alloc_incr;
00096
00097 int node_cnt;
00098 int iter_cnt;
00099
00100 int seed_given;
00101 unsigned seed;
00102
00103 int verbosity;
00104 int nonstop;
00105 };
00106
00107
00108 char *pgm_name;
00109
00110
00111
00112
00113
00114 int
00115 compare_ints (const void *pa, const void *pb, void *param)
00116 {
00117 const int *a = pa;
00118 const int *b = pb;
00119
00120 if (*a < *b)
00121 return -1;
00122 else if (*a > *b)
00123 return +1;
00124 else
00125 return 0;
00126 }
00127
00128
00129
00130 static void
00131 fail (const char *message, ...)
00132 {
00133 va_list args;
00134
00135 fprintf (stderr, "%s: ", pgm_name);
00136
00137 va_start (args, message);
00138 vfprintf (stderr, message, args);
00139 va_end (args);
00140
00141 putchar ('\n');
00142
00143 exit (EXIT_FAILURE);
00144 }
00145
00146
00147
00148 static void *
00149 xmalloc (size_t size)
00150 {
00151 void *block = malloc (size);
00152 if (block == NULL && size != 0)
00153 fail ("out of memory");
00154 return block;
00155 }
00156
00157
00158
00159
00160 struct block
00161 {
00162 struct block *next;
00163
00164 int idx;
00165 size_t size;
00166 size_t used;
00167 void *content;
00168 };
00169
00170
00171 enum mt_arg_index
00172 {
00173 MT_COUNT = 0,
00174 MT_PERCENT = 0,
00175 MT_BLOCK_SIZE = 0,
00176 MT_ALIGN = 1
00177 };
00178
00179
00180 struct mt_allocator
00181 {
00182 struct libavl_allocator allocator;
00183
00184
00185 enum mt_policy policy;
00186 int arg[2];
00187 int verbosity;
00188
00189
00190 struct block *head, *tail;
00191 int alloc_idx;
00192 int block_cnt;
00193 };
00194
00195 static void *mt_allocate (struct libavl_allocator *, size_t);
00196 static void mt_free (struct libavl_allocator *, void *);
00197
00198
00199
00200
00201 struct mt_allocator *
00202 mt_create (enum mt_policy policy, int arg[2], int verbosity)
00203 {
00204 struct mt_allocator *mt = xmalloc (sizeof *mt);
00205
00206 mt->allocator.libavl_malloc = mt_allocate;
00207 mt->allocator.libavl_free = mt_free;
00208
00209 mt->policy = policy;
00210 mt->arg[0] = arg[0];
00211 mt->arg[1] = arg[1];
00212 mt->verbosity = verbosity;
00213
00214 mt->head = mt->tail = NULL;
00215 mt->alloc_idx = 0;
00216 mt->block_cnt = 0;
00217
00218 return mt;
00219 }
00220
00221
00222
00223 void
00224 mt_destroy (struct mt_allocator *mt)
00225 {
00226 assert (mt != NULL);
00227
00228 if (mt->block_cnt == 0)
00229 {
00230 if (mt->policy != MT_NO_TRACK && mt->verbosity >= 1)
00231 printf (" No memory leaks.\n");
00232 }
00233 else
00234 {
00235 struct block *iter, *next;
00236
00237 if (mt->policy != MT_SUBALLOC)
00238 printf (" Memory leaks detected:\n");
00239 for (iter = mt->head; iter != NULL; iter = next)
00240 {
00241 if (mt->policy != MT_SUBALLOC)
00242 printf (" block #%d: %lu bytes\n",
00243 iter->idx, (unsigned long) iter->size);
00244
00245 next = iter->next;
00246 free (iter->content);
00247 free (iter);
00248 }
00249 }
00250
00251 free (mt);
00252 }
00253
00254
00255 void *
00256 mt_allocator (struct mt_allocator *mt)
00257 {
00258 return &mt->allocator;
00259 }
00260
00261
00262
00263 static void *
00264 new_block (struct mt_allocator *mt, size_t size)
00265 {
00266 struct block *new;
00267
00268
00269 new = xmalloc (sizeof *new);
00270 new->next = NULL;
00271 new->idx = mt->alloc_idx++;
00272 new->size = size;
00273 new->used = 0;
00274 new->content = xmalloc (size);
00275
00276
00277 if (mt->head == NULL)
00278 mt->head = new;
00279 else
00280 mt->tail->next = new;
00281 mt->tail = new;
00282
00283
00284 if (mt->verbosity >= 3)
00285 printf (" block #%d: allocated %lu bytes\n",
00286 new->idx, (unsigned long) size);
00287
00288
00289 mt->block_cnt++;
00290 return new->content;
00291 }
00292
00293
00294 static void
00295 reject_request (struct mt_allocator *mt, size_t size)
00296 {
00297 if (mt->verbosity >= 2)
00298 printf (" block #%d: rejected request for %lu bytes\n",
00299 mt->alloc_idx++, (unsigned long) size);
00300 }
00301
00302
00303 static void *
00304 mt_allocate (struct libavl_allocator *allocator, size_t size)
00305 {
00306 struct mt_allocator *mt = (struct mt_allocator *) allocator;
00307
00308
00309 if (size == 0)
00310 return NULL;
00311
00312 switch (mt->policy)
00313 {
00314 case MT_TRACK:
00315 return new_block (mt, size);
00316
00317 case MT_NO_TRACK:
00318 return xmalloc (size);
00319
00320 case MT_FAIL_COUNT:
00321 if (mt->arg[MT_COUNT] == 0)
00322 {
00323 reject_request (mt, size);
00324 return NULL;
00325 }
00326 mt->arg[MT_COUNT]--;
00327 return new_block (mt, size);
00328
00329 case MT_FAIL_PERCENT:
00330 if (rand () / (RAND_MAX / 100 + 1) < mt->arg[MT_PERCENT])
00331 {
00332 reject_request (mt, size);
00333 return NULL;
00334 }
00335 else
00336 return new_block (mt, size);
00337
00338 case MT_SUBALLOC:
00339 if (mt->tail == NULL
00340 || mt->tail->used + size > (size_t) mt->arg[MT_BLOCK_SIZE])
00341 new_block (mt, mt->arg[MT_BLOCK_SIZE]);
00342 if (mt->tail->used + size <= (size_t) mt->arg[MT_BLOCK_SIZE])
00343 {
00344 void *p = (char *) mt->tail->content + mt->tail->used;
00345 size = ((size + mt->arg[MT_ALIGN] - 1)
00346 / mt->arg[MT_ALIGN] * mt->arg[MT_ALIGN]);
00347 mt->tail->used += size;
00348 if (mt->verbosity >= 3)
00349 printf (" block #%d: suballocated %lu bytes\n",
00350 mt->tail->idx, (unsigned long) size);
00351 return p;
00352 }
00353 else
00354 fail ("blocksize %lu too small for %lu-byte allocation",
00355 (unsigned long) mt->tail->size, (unsigned long) size);
00356
00357 default:
00358 assert (0);
00359 }
00360 }
00361
00362
00363 static void
00364 mt_free (struct libavl_allocator *allocator, void *block)
00365 {
00366 struct mt_allocator *mt = (struct mt_allocator *) allocator;
00367 struct block *iter, *prev;
00368
00369
00370 if (block == NULL || mt->policy == MT_NO_TRACK)
00371 {
00372 free (block);
00373 return;
00374 }
00375 if (mt->policy == MT_SUBALLOC)
00376 return;
00377
00378
00379 for (prev = NULL, iter = mt->head; iter; prev = iter, iter = iter->next)
00380 {
00381 if (iter->content == block)
00382 {
00383
00384 struct block *next = iter->next;
00385
00386 if (prev == NULL)
00387 mt->head = next;
00388 else
00389 prev->next = next;
00390 if (next == NULL)
00391 mt->tail = prev;
00392
00393
00394 if (mt->verbosity >= 4)
00395 printf (" block #%d: freed %lu bytes\n",
00396 iter->idx, (unsigned long) iter->size);
00397
00398
00399 free (iter->content);
00400 free (iter);
00401
00402
00403 mt->block_cnt--;
00404 return;
00405 }
00406 }
00407
00408
00409 printf (" attempt to free unknown block %p (already freed?)\n", block);
00410 }
00411
00412
00413 struct option_state
00414 {
00415 const struct option *options;
00416 char **arg_next;
00417 char *short_next;
00418 };
00419
00420
00421
00422
00423 static struct option_state *
00424 option_init (const struct option *options, char **args)
00425 {
00426 struct option_state *state;
00427
00428 assert (options != NULL && args != NULL);
00429
00430 state = xmalloc (sizeof *state);
00431 state->options = options;
00432 state->arg_next = args;
00433 state->short_next = NULL;
00434
00435 return state;
00436 }
00437
00438
00439
00440
00441
00442 static int
00443 handle_short_option (struct option_state *state, char **argp)
00444 {
00445 const struct option *o;
00446
00447 assert (state != NULL
00448 && state->short_next != NULL && *state->short_next != '\0'
00449 && state->options != NULL);
00450
00451
00452 for (o = state->options; ; o++)
00453 if (o->long_name == NULL)
00454 fail ("unknown option `-%c'; use --help for help", *state->short_next);
00455 else if (o->short_name == *state->short_next)
00456 break;
00457 state->short_next++;
00458
00459
00460 if (o->has_arg)
00461 {
00462 if (*state->arg_next == NULL || **state->arg_next == '-')
00463 fail ("`-%c' requires an argument; use --help for help");
00464
00465 *argp = *state->arg_next++;
00466 }
00467
00468 return o->short_name;
00469 }
00470
00471
00472
00473
00474
00475 static int
00476 handle_long_option (struct option_state *state, char **argp)
00477 {
00478 const struct option *o;
00479 char name[16];
00480 const char *arg;
00481
00482 assert (state != NULL
00483 && state->arg_next != NULL && *state->arg_next != NULL
00484 && state->options != NULL
00485 && argp != NULL);
00486
00487
00488
00489 {
00490 const char *p = *state->arg_next + 2;
00491 const char *q = p + strcspn (p, "=");
00492 size_t name_len = q - p;
00493
00494 if (name_len > (sizeof name) - 1)
00495 name_len = (sizeof name) - 1;
00496 memcpy (name, p, name_len);
00497 name[name_len] = '\0';
00498
00499 arg = (*q == '=') ? q + 1 : NULL;
00500 }
00501
00502
00503 for (o = state->options; ; o++)
00504 if (o->long_name == NULL)
00505 fail ("unknown option --%s; use --help for help", name);
00506 else if (!strcmp (name, o->long_name))
00507 break;
00508
00509
00510 if ((arg != NULL) != (o->has_arg != 0))
00511 {
00512 if (arg != NULL)
00513 fail ("--%s can't take an argument; use --help for help", name);
00514 else
00515 fail ("--%s requires an argument; use --help for help", name);
00516 }
00517
00518
00519 state->arg_next++;
00520 *argp = (char *) arg;
00521 return o->short_name;
00522 }
00523
00524
00525
00526
00527 static int
00528 option_get (struct option_state *state, char **argp)
00529 {
00530 assert (state != NULL && argp != NULL);
00531
00532
00533 *argp = NULL;
00534
00535
00536 if (state->short_next != NULL)
00537 {
00538 if (*state->short_next != '\0')
00539 return handle_short_option (state, argp);
00540 else
00541 state->short_next = NULL;
00542 }
00543
00544
00545 if (*state->arg_next == NULL)
00546 {
00547 free (state);
00548 return -1;
00549 }
00550
00551
00552 if ((*state->arg_next)[0] != '-')
00553 fail ("non-option arguments encountered; use --help for help");
00554 if ((*state->arg_next)[1] == '\0')
00555 fail ("unknown option `-'; use --help for help");
00556
00557
00558 if ((*state->arg_next)[1] == '-')
00559 return handle_long_option (state, argp);
00560 else
00561 {
00562 state->short_next = *state->arg_next + 1;
00563 state->arg_next++;
00564 return handle_short_option (state, argp);
00565 }
00566 }
00567
00568
00569
00570
00571
00572
00573 size_t
00574 match_len (const char *a, const char *b)
00575 {
00576 size_t cnt;
00577
00578 for (cnt = 0; *a == *b && *a != '\0'; a++, b++)
00579 cnt++;
00580
00581 return (*a != *b && *a != '\0' && *b != '\0') ? 0 : cnt;
00582 }
00583
00584
00585
00586 static int
00587 stoi (const char *s)
00588 {
00589 long x = strtol (s, NULL, 10);
00590 return x >= INT_MIN && x <= INT_MAX ? x : 0;
00591 }
00592
00593
00594 static void
00595 usage (void)
00596 {
00597 static const char *help[] =
00598 {
00599 "bst-test, unit test for GNU libavl.\n\n",
00600 "Usage: %s [OPTION]...\n\n",
00601 "In the option descriptions below, CAPITAL denote arguments.\n",
00602 "If a long option shows an argument as mandatory, then it is\n",
00603 "mandatory for the equivalent short option also. See the GNU\n",
00604 "libavl manual for more information.\n\n",
00605 "-t, --test=TEST Sets test to perform. TEST is one of:\n",
00606 " correctness insert/delete/... (default)\n",
00607 " overflow stack overflow test\n",
00608 " benchmark benchmark test\n",
00609 " null no test\n",
00610 "-s, --size=TREE-SIZE Sets tree size in nodes (default 16).\n",
00611 "-r, --repeat=COUNT Repeats operation COUNT times (default 16).\n",
00612 "-i, --insert=ORDER Sets the insertion order. ORDER is one of:\n",
00613 " random random permutation (default)\n",
00614 " ascending ascending order 0...n-1\n",
00615 " descending descending order n-1...0\n",
00616 " balanced balanced tree order\n",
00617 " zigzag zig-zag tree\n",
00618 " asc-shifted n/2...n-1, 0...n/2-1\n",
00619 " custom custom, read from stdin\n",
00620 "-d, --delete=ORDER Sets the deletion order. ORDER is one of:\n",
00621 " random random permutation (default)\n",
00622 " reverse reverse order of insertion\n",
00623 " same same as insertion order\n",
00624 " custom custom, read from stdin\n",
00625 "-a, --alloc=POLICY Sets allocation policy. POLICY is one of:\n",
00626 " track track memory leaks (default)\n",
00627 " no-track turn off leak detection\n",
00628 " fail-CNT fail after CNT allocations\n",
00629 " fail%%PCT fail random PCT%% of allocations\n",
00630 " sub-B,A divide B-byte blocks in A-byte units\n",
00631 " (Ignored for `benchmark' test.)\n",
00632 "-A, --incr=INC Fail policies: arg increment per repetition.\n",
00633 "-S, --seed=SEED Sets initial number seed to SEED.\n",
00634 " (default based on system time)\n",
00635 "-n, --nonstop Don't stop after a single error.\n",
00636 "-q, --quiet Turns down verbosity level.\n",
00637 "-v, --verbose Turns up verbosity level.\n",
00638 "-h, --help Displays this help screen.\n",
00639 "-V, --version Reports version and copyright information.\n",
00640 NULL,
00641 };
00642
00643 const char **p;
00644 for (p = help; *p != NULL; p++)
00645 printf (*p, pgm_name);
00646
00647 exit (EXIT_SUCCESS);
00648 }
00649
00650
00651
00652 static void
00653 parse_command_line (char **args, struct test_options *options)
00654 {
00655 static const struct option option_tab[] =
00656 {
00657 {"test", 't', 1},
00658 {"insert", 'i', 1},
00659 {"delete", 'd', 1},
00660 {"alloc", 'a', 1},
00661 {"incr", 'A', 1},
00662 {"size", 's', 1},
00663 {"repeat", 'r', 1},
00664 {"operation", 'o', 1},
00665 {"seed", 'S', 1},
00666 {"nonstop", 'n', 0},
00667 {"quiet", 'q', 0},
00668 {"verbose", 'v', 0},
00669 {"help", 'h', 0},
00670 {"version", 'V', 0},
00671 {NULL, 0, 0},
00672 };
00673
00674 struct option_state *state;
00675
00676
00677 options->test = TST_CORRECTNESS;
00678 options->insert_order = INS_RANDOM;
00679 options->delete_order = DEL_RANDOM;
00680 options->alloc_policy = MT_TRACK;
00681 options->alloc_arg[0] = 0;
00682 options->alloc_arg[1] = 0;
00683 options->alloc_incr = 0;
00684 options->node_cnt = 15;
00685 options->iter_cnt = 15;
00686 options->seed_given = 0;
00687 options->verbosity = 0;
00688 options->nonstop = 0;
00689
00690 if (*args == NULL)
00691 return;
00692
00693 state = option_init (option_tab, args + 1);
00694 for (;;)
00695 {
00696 char *arg;
00697 int id = option_get (state, &arg);
00698 if (id == -1)
00699 break;
00700
00701 switch (id)
00702 {
00703 case 't':
00704 if (match_len (arg, "correctness") >= 3)
00705 options->test = TST_CORRECTNESS;
00706 else if (match_len (arg, "overflow") >= 3)
00707 options->test = TST_OVERFLOW;
00708 else if (match_len (arg, "null") >= 3)
00709 options->test = TST_NULL;
00710 else
00711 fail ("unknown test \"%s\"", arg);
00712 break;
00713
00714 case 'i':
00715 {
00716 static const char *orders[INS_CNT] =
00717 {
00718 "random", "ascending", "descending",
00719 "balanced", "zigzag", "asc-shifted", "custom",
00720 };
00721
00722 const char **iter;
00723
00724 assert (sizeof orders / sizeof *orders == INS_CNT);
00725 for (iter = orders; ; iter++)
00726 if (iter >= orders + INS_CNT)
00727 fail ("unknown order \"%s\"", arg);
00728 else if (match_len (*iter, arg) >= 3)
00729 {
00730 options->insert_order = iter - orders;
00731 break;
00732 }
00733 }
00734 break;
00735
00736 case 'd':
00737 {
00738 static const char *orders[DEL_CNT] =
00739 {
00740 "random", "reverse", "same", "custom",
00741 };
00742
00743 const char **iter;
00744
00745 assert (sizeof orders / sizeof *orders == DEL_CNT);
00746 for (iter = orders; ; iter++)
00747 if (iter >= orders + DEL_CNT)
00748 fail ("unknown order \"%s\"", arg);
00749 else if (match_len (*iter, arg) >= 3)
00750 {
00751 options->delete_order = iter - orders;
00752 break;
00753 }
00754 }
00755 break;
00756
00757 case 'a':
00758 if (match_len (arg, "track") >= 3)
00759 options->alloc_policy = MT_TRACK;
00760 else if (match_len (arg, "no-track") >= 3)
00761 options->alloc_policy = MT_NO_TRACK;
00762 else if (!strncmp (arg, "fail", 3))
00763 {
00764 const char *p = arg + strcspn (arg, "-%");
00765 if (*p == '-')
00766 options->alloc_policy = MT_FAIL_COUNT;
00767 else if (*p == '%')
00768 options->alloc_policy = MT_FAIL_PERCENT;
00769 else
00770 fail ("invalid allocation policy \"%s\"", arg);
00771
00772 options->alloc_arg[0] = stoi (p + 1);
00773 }
00774 else if (!strncmp (arg, "suballoc", 3))
00775 {
00776 const char *p = strchr (arg, '-');
00777 const char *q = strchr (arg, ',');
00778 if (p == NULL || q == NULL)
00779 fail ("invalid allocation policy \"%s\"", arg);
00780
00781 options->alloc_policy = MT_SUBALLOC;
00782 options->alloc_arg[0] = stoi (p + 1);
00783 options->alloc_arg[1] = stoi (q + 1);
00784 if (options->alloc_arg[MT_BLOCK_SIZE] < 32)
00785 fail ("block size too small");
00786 else if (options->alloc_arg[MT_ALIGN]
00787 > options->alloc_arg[MT_BLOCK_SIZE])
00788 fail ("alignment cannot be greater than block size");
00789 else if (options->alloc_arg[MT_ALIGN] < 1)
00790 fail ("alignment must be at least 1");
00791 }
00792 break;
00793
00794 case 'A':
00795 options->alloc_incr = stoi (arg);
00796 break;
00797
00798 case 's':
00799 options->node_cnt = stoi (arg);
00800 if (options->node_cnt < 1)
00801 fail ("bad tree size \"%s\"", arg);
00802 break;
00803
00804 case 'r':
00805 options->iter_cnt = stoi (arg);
00806 if (options->iter_cnt < 1)
00807 fail ("bad repeat count \"%s\"", arg);
00808 break;
00809
00810 case 'S':
00811 options->seed_given = 1;
00812 options->seed = strtoul (arg, NULL, 0);
00813 break;
00814
00815 case 'n':
00816 options->nonstop = 1;
00817 break;
00818
00819 case 'q':
00820 options->verbosity--;
00821 break;
00822
00823 case 'v':
00824 options->verbosity++;
00825 break;
00826
00827 case 'h':
00828 usage ();
00829 break;
00830
00831 case 'V':
00832 fputs ("GNU libavl 2.0.2\n"
00833 "Copyright (C) 1998-2002, 2004 "
00834 "Free Software Foundation, Inc.\n"
00835 "This program comes with NO WARRANTY, not even for\n"
00836 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
00837 "You may redistribute copies under the terms of the\n"
00838 "GNU General Public License. For more information on\n"
00839 "these matters, see the file named COPYING.\n",
00840 stdout);
00841 exit (EXIT_SUCCESS);
00842
00843 default:
00844 assert (0);
00845 }
00846 }
00847 }
00848
00849
00850
00851 static void
00852 permuted_integers (int array[], size_t n)
00853 {
00854 size_t i;
00855
00856 for (i = 0; i < n; i++)
00857 array[i] = i;
00858
00859 for (i = 0; i < n; i++)
00860 {
00861 size_t j = i + (unsigned) rand () / (RAND_MAX / (n - i) + 1);
00862 int t = array[j];
00863 array[j] = array[i];
00864 array[i] = t;
00865 }
00866 }
00867
00868
00869
00870
00871
00872 static void
00873 gen_balanced_tree (int min, int max, int **array)
00874 {
00875 int i;
00876
00877 if (min > max)
00878 return;
00879
00880 i = (min + max + 1) / 2;
00881 *(*array)++ = i;
00882 gen_balanced_tree (min, i - 1, array);
00883 gen_balanced_tree (i + 1, max, array);
00884 }
00885
00886
00887
00888
00889 static void
00890 gen_insertions (size_t n, enum insert_order insert_order, int insert[])
00891 {
00892 size_t i;
00893
00894 switch (insert_order)
00895 {
00896 case INS_RANDOM:
00897 permuted_integers (insert, n);
00898 break;
00899
00900 case INS_ASCENDING:
00901 for (i = 0; i < n; i++)
00902 insert[i] = i;
00903 break;
00904
00905 case INS_DESCENDING:
00906 for (i = 0; i < n; i++)
00907 insert[i] = n - i - 1;
00908 break;
00909
00910 case INS_BALANCED:
00911 gen_balanced_tree (0, n - 1, &insert);
00912 break;
00913
00914 case INS_ZIGZAG:
00915 for (i = 0; i < n; i++)
00916 if (i % 2 == 0)
00917 insert[i] = i / 2;
00918 else
00919 insert[i] = n - i / 2 - 1;
00920 break;
00921
00922 case INS_ASCENDING_SHIFTED:
00923 for (i = 0; i < n; i++)
00924 {
00925 insert[i] = i + n / 2;
00926 if ((size_t) insert[i] >= n)
00927 insert[i] -= n;
00928 }
00929 break;
00930
00931 case INS_CUSTOM:
00932 for (i = 0; i < n; i++)
00933 if (scanf ("%d", &insert[i]) == 0)
00934 fail ("error reading insertion order from stdin");
00935 break;
00936
00937 default:
00938 assert (0);
00939 }
00940 }
00941
00942
00943
00944 static void
00945 gen_deletions (size_t n, enum delete_order delete_order,
00946 const int *insert, int *delete)
00947 {
00948 size_t i;
00949
00950 switch (delete_order)
00951 {
00952 case DEL_RANDOM:
00953 permuted_integers (delete, n);
00954 break;
00955
00956 case DEL_REVERSE:
00957 for (i = 0; i < n; i++)
00958 delete[i] = insert[n - i - 1];
00959 break;
00960
00961 case DEL_SAME:
00962 for (i = 0; i < n; i++)
00963 delete[i] = insert[i];
00964 break;
00965
00966 case DEL_CUSTOM:
00967 for (i = 0; i < n; i++)
00968 if (scanf ("%d", &delete[i]) == 0)
00969 fail ("error reading deletion order from stdin");
00970 break;
00971
00972 default:
00973 assert (0);
00974 }
00975 }
00976
00977
00978
00979 unsigned
00980 time_seed (void)
00981 {
00982 time_t timeval;
00983 unsigned char *ptr;
00984 unsigned seed;
00985 size_t i;
00986
00987 timeval = time (NULL);
00988 ptr = (unsigned char *) &timeval;
00989
00990 seed = 0;
00991 for (i = 0; i < sizeof timeval; i++)
00992 seed = seed * (UCHAR_MAX + 2u) + ptr[i];
00993
00994 return seed;
00995 }
00996
00997 int
00998 main (int argc, char *argv[])
00999 {
01000 struct test_options opts;
01001 int *insert, *delete;
01002 int success;
01003
01004
01005 pgm_name = argv[0] != NULL && argv[0][0] != '\0' ? argv[0] : "bst-test";
01006
01007
01008 parse_command_line (argv, &opts);
01009
01010 if (opts.verbosity >= 0)
01011 fputs ("bst-test for GNU libavl 2.0.2; use --help to get help.\n", stdout);
01012
01013 if (!opts.seed_given)
01014 opts.seed = time_seed () % 32768u;
01015
01016 insert = xmalloc (sizeof *insert * opts.node_cnt);
01017 delete = xmalloc (sizeof *delete * opts.node_cnt);
01018
01019
01020 success = 1;
01021 while (opts.iter_cnt--)
01022 {
01023 struct mt_allocator *alloc;
01024
01025 if (opts.verbosity >= 0)
01026 {
01027 printf ("Testing seed=%u", opts.seed);
01028 if (opts.alloc_incr)
01029 printf (", alloc arg=%d", opts.alloc_arg[0]);
01030 printf ("...\n");
01031 fflush (stdout);
01032 }
01033
01034
01035
01036
01037 srand (opts.seed);
01038 gen_insertions (opts.node_cnt, opts.insert_order, insert);
01039
01040 srand (++opts.seed);
01041 gen_deletions (opts.node_cnt, opts.delete_order, insert, delete);
01042
01043 if (opts.verbosity >= 1)
01044 {
01045 int i;
01046
01047 printf (" Insertion order:");
01048 for (i = 0; i < opts.node_cnt; i++)
01049 printf (" %d", insert[i]);
01050 printf (".\n");
01051
01052 if (opts.test == TST_CORRECTNESS)
01053 {
01054 printf ("Deletion order:");
01055 for (i = 0; i < opts.node_cnt; i++)
01056 printf (" %d", delete[i]);
01057 printf (".\n");
01058 }
01059 }
01060
01061 alloc = mt_create (opts.alloc_policy, opts.alloc_arg, opts.verbosity);
01062
01063 {
01064 int okay;
01065 struct libavl_allocator *a = mt_allocator (alloc);
01066
01067 switch (opts.test)
01068 {
01069 case TST_CORRECTNESS:
01070 okay = test_correctness (a, insert, delete, opts.node_cnt,
01071 opts.verbosity);
01072 break;
01073
01074 case TST_OVERFLOW:
01075 okay = test_overflow (a, insert, opts.node_cnt, opts.verbosity);
01076 break;
01077
01078 case TST_NULL:
01079 okay = 1;
01080 break;
01081
01082 default:
01083 assert (0);
01084 }
01085
01086 if (okay)
01087 {
01088 if (opts.verbosity >= 1)
01089 printf (" No errors.\n");
01090 }
01091 else
01092 {
01093 success = 0;
01094 printf (" Error!\n");
01095 }
01096 }
01097
01098 mt_destroy (alloc);
01099 opts.alloc_arg[0] += opts.alloc_incr;
01100
01101 if (!success && !opts.nonstop)
01102 break;
01103 }
01104
01105 free (delete);
01106 free (insert);
01107
01108 return success ? EXIT_SUCCESS : EXIT_FAILURE;
01109 }