1 /* Produced by texiweb from libavl.w. */
3 /* libavl - library for manipulation of binary trees.
4 Copyright (C) 1998-2002, 2004 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 See the GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 The author may be contacted at <blp@gnu.org> on the Internet, or
22 write to Ben Pfaff, Stanford University, Computer Science Dept., 353
23 Serra Mall, Stanford CA 94305, USA.
35 /* Insertion order. */
38 INS_RANDOM
, /* Random order. */
39 INS_ASCENDING
, /* Ascending order. */
40 INS_DESCENDING
, /* Descending order. */
41 INS_BALANCED
, /* Balanced tree order. */
42 INS_ZIGZAG
, /* Zig-zag order. */
43 INS_ASCENDING_SHIFTED
, /* Ascending from middle, then beginning. */
44 INS_CUSTOM
, /* Custom order. */
46 INS_CNT
/* Number of insertion orders. */
52 DEL_RANDOM
, /* Random order. */
53 DEL_REVERSE
, /* Reverse of insertion order. */
54 DEL_SAME
, /* Same as insertion order. */
55 DEL_CUSTOM
, /* Custom order. */
57 DEL_CNT
/* Number of deletion orders. */
60 /* Memory tracking policy. */
63 MT_TRACK
, /* Track allocation for leak detection. */
64 MT_NO_TRACK
, /* No leak detection. */
65 MT_FAIL_COUNT
, /* Fail allocations after a while. */
66 MT_FAIL_PERCENT
, /* Fail allocations randomly. */
67 MT_SUBALLOC
/* Suballocate from larger blocks. */
70 /* A single command-line option. */
73 const char *long_name
; /* Long name (|"--name"|). */
74 int short_name
; /* Short name (|"-n"|); value returned. */
75 int has_arg
; /* Has a required argument? */
78 /* Test to perform. */
81 TST_CORRECTNESS
, /* Default tests. */
82 TST_OVERFLOW
, /* Stack overflow test. */
83 TST_NULL
/* No test, just overhead. */
86 /* Program options. */
89 enum test test
; /* Test to perform. */
90 enum insert_order insert_order
; /* Insertion order. */
91 enum delete_order delete_order
; /* Deletion order. */
93 enum mt_policy alloc_policy
; /* Allocation policy. */
94 int alloc_arg
[2]; /* Policy arguments. */
95 int alloc_incr
; /* Amount to increment |alloc_arg| each iteration. */
97 int node_cnt
; /* Number of nodes in tree. */
98 int iter_cnt
; /* Number of runs. */
100 int seed_given
; /* Seed provided on command line? */
101 unsigned seed
; /* Random number seed. */
103 int verbosity
; /* Verbosity level, 0=default. */
104 int nonstop
; /* Don't stop after one error? */
110 /* Utility functions. */
112 /* Comparison function for pointers to |int|s.
113 |param| is not used. */
115 compare_ints (const void *pa
, const void *pb
, void *param
)
128 /* Prints |message| on |stderr|, which is formatted as for |printf()|,
129 and terminates the program unsuccessfully. */
131 fail (const char *message
, ...)
135 fprintf (stderr
, "%s: ", pgm_name
);
137 va_start (args
, message
);
138 vfprintf (stderr
, message
, args
);
146 /* Allocates and returns a pointer to |size| bytes of memory.
147 Aborts if allocation fails. */
149 xmalloc (size_t size
)
151 void *block
= malloc (size
);
152 if (block
== NULL
&& size
!= 0)
153 fail ("out of memory");
157 /* Memory tracking allocator. */
159 /* A memory block. */
162 struct block
*next
; /* Next in linked list. */
164 int idx
; /* Allocation order index number. */
165 size_t size
; /* Size in bytes. */
166 size_t used
; /* MT_SUBALLOC: amount used so far. */
167 void *content
; /* Allocated region. */
170 /* Indexes into |arg[]| within |struct mt_allocator|. */
173 MT_COUNT
= 0, /* |MT_FAIL_COUNT|: Remaining successful allocations. */
174 MT_PERCENT
= 0, /* |MT_FAIL_PERCENT|: Failure percentage. */
175 MT_BLOCK_SIZE
= 0, /* |MT_SUBALLOC|: Size of block to suballocate. */
176 MT_ALIGN
= 1 /* |MT_SUBALLOC|: Alignment of suballocated blocks. */
179 /* Memory tracking allocator. */
182 struct libavl_allocator allocator
; /* Allocator. Must be first member. */
185 enum mt_policy policy
; /* Allocation policy. */
186 int arg
[2]; /* Policy arguments. */
187 int verbosity
; /* Message verbosity level. */
190 struct block
*head
, *tail
; /* Head and tail of block list. */
191 int alloc_idx
; /* Number of allocations so far. */
192 int block_cnt
; /* Number of still-allocated blocks. */
195 static void *mt_allocate (struct libavl_allocator
*, size_t);
196 static void mt_free (struct libavl_allocator
*, void *);
198 /* Initializes the memory manager for use
199 with allocation policy |policy| and policy arguments |arg[]|,
200 at verbosity level |verbosity|, where 0 is a ``normal'' value. */
201 struct mt_allocator
*
202 mt_create (enum mt_policy policy
, int arg
[2], int verbosity
)
204 struct mt_allocator
*mt
= xmalloc (sizeof *mt
);
206 mt
->allocator
.libavl_malloc
= mt_allocate
;
207 mt
->allocator
.libavl_free
= mt_free
;
212 mt
->verbosity
= verbosity
;
214 mt
->head
= mt
->tail
= NULL
;
221 /* Frees and destroys memory tracker |mt|,
222 reporting any memory leaks. */
224 mt_destroy (struct mt_allocator
*mt
)
228 if (mt
->block_cnt
== 0)
230 if (mt
->policy
!= MT_NO_TRACK
&& mt
->verbosity
>= 1)
231 printf (" No memory leaks.\n");
235 struct block
*iter
, *next
;
237 if (mt
->policy
!= MT_SUBALLOC
)
238 printf (" Memory leaks detected:\n");
239 for (iter
= mt
->head
; iter
!= NULL
; iter
= next
)
241 if (mt
->policy
!= MT_SUBALLOC
)
242 printf (" block #%d: %lu bytes\n",
243 iter
->idx
, (unsigned long) iter
->size
);
246 free (iter
->content
);
254 /* Returns the |struct libavl_allocator| associated with |mt|. */
256 mt_allocator (struct mt_allocator
*mt
)
258 return &mt
->allocator
;
261 /* Creates a new |struct block| containing |size| bytes of content
262 and returns a pointer to content. */
264 new_block (struct mt_allocator
*mt
, size_t size
)
268 /* Allocate and initialize new |struct block|. */
269 new = xmalloc (sizeof *new);
271 new->idx
= mt
->alloc_idx
++;
274 new->content
= xmalloc (size
);
276 /* Add block to linked list. */
277 if (mt
->head
== NULL
)
280 mt
->tail
->next
= new;
284 if (mt
->verbosity
>= 3)
285 printf (" block #%d: allocated %lu bytes\n",
286 new->idx
, (unsigned long) size
);
288 /* Finish up and return. */
293 /* Prints a message about a rejected allocation if appropriate. */
295 reject_request (struct mt_allocator
*mt
, size_t size
)
297 if (mt
->verbosity
>= 2)
298 printf (" block #%d: rejected request for %lu bytes\n",
299 mt
->alloc_idx
++, (unsigned long) size
);
302 /* Allocates and returns a block of |size| bytes. */
304 mt_allocate (struct libavl_allocator
*allocator
, size_t size
)
306 struct mt_allocator
*mt
= (struct mt_allocator
*) allocator
;
315 return new_block (mt
, size
);
318 return xmalloc (size
);
321 if (mt
->arg
[MT_COUNT
] == 0)
323 reject_request (mt
, size
);
327 return new_block (mt
, size
);
329 case MT_FAIL_PERCENT
:
330 if (rand () / (RAND_MAX
/ 100 + 1) < mt
->arg
[MT_PERCENT
])
332 reject_request (mt
, size
);
336 return new_block (mt
, size
);
340 || mt
->tail
->used
+ size
> (size_t) mt
->arg
[MT_BLOCK_SIZE
])
341 new_block (mt
, mt
->arg
[MT_BLOCK_SIZE
]);
342 if (mt
->tail
->used
+ size
<= (size_t) mt
->arg
[MT_BLOCK_SIZE
])
344 void *p
= (char *) mt
->tail
->content
+ mt
->tail
->used
;
345 size
= ((size
+ mt
->arg
[MT_ALIGN
] - 1)
346 / mt
->arg
[MT_ALIGN
] * mt
->arg
[MT_ALIGN
]);
347 mt
->tail
->used
+= size
;
348 if (mt
->verbosity
>= 3)
349 printf (" block #%d: suballocated %lu bytes\n",
350 mt
->tail
->idx
, (unsigned long) size
);
354 fail ("blocksize %lu too small for %lu-byte allocation",
355 (unsigned long) mt
->tail
->size
, (unsigned long) size
);
362 /* Releases |block| previously returned by |mt_allocate()|. */
364 mt_free (struct libavl_allocator
*allocator
, void *block
)
366 struct mt_allocator
*mt
= (struct mt_allocator
*) allocator
;
367 struct block
*iter
, *prev
;
370 if (block
== NULL
|| mt
->policy
== MT_NO_TRACK
)
375 if (mt
->policy
== MT_SUBALLOC
)
378 /* Search for |block| within the list of allocated blocks. */
379 for (prev
= NULL
, iter
= mt
->head
; iter
; prev
= iter
, iter
= iter
->next
)
381 if (iter
->content
== block
)
383 /* Block found. Remove it from the list. */
384 struct block
*next
= iter
->next
;
394 if (mt
->verbosity
>= 4)
395 printf (" block #%d: freed %lu bytes\n",
396 iter
->idx
, (unsigned long) iter
->size
);
399 free (iter
->content
);
402 /* Finish up and return. */
408 /* Block not in list. */
409 printf (" attempt to free unknown block %p (already freed?)\n", block
);
412 /* Option parsing state. */
415 const struct option
*options
; /* List of options. */
416 char **arg_next
; /* Remaining arguments. */
417 char *short_next
; /* When non-null, unparsed short options. */
420 /* Creates and returns a command-line options parser.
421 |args| is a null-terminated array of command-line arguments, not
422 including program name. */
423 static struct option_state
*
424 option_init (const struct option
*options
, char **args
)
426 struct option_state
*state
;
428 assert (options
!= NULL
&& args
!= NULL
);
430 state
= xmalloc (sizeof *state
);
431 state
->options
= options
;
432 state
->arg_next
= args
;
433 state
->short_next
= NULL
;
438 /* Parses a short option whose single-character name is pointed to by
439 |state->short_next|. Advances past the option so that the next one
440 will be parsed in the next call to |option_get()|. Sets |*argp| to
441 the option's argument, if any. Returns the option's short name. */
443 handle_short_option (struct option_state
*state
, char **argp
)
445 const struct option
*o
;
447 assert (state
!= NULL
448 && state
->short_next
!= NULL
&& *state
->short_next
!= '\0'
449 && state
->options
!= NULL
);
451 /* Find option in |o|. */
452 for (o
= state
->options
; ; o
++)
453 if (o
->long_name
== NULL
)
454 fail ("unknown option `-%c'; use --help for help", *state
->short_next
);
455 else if (o
->short_name
== *state
->short_next
)
459 /* Handle argument. */
462 if (*state
->arg_next
== NULL
|| **state
->arg_next
== '-')
463 fail ("`-%c' requires an argument; use --help for help");
465 *argp
= *state
->arg_next
++;
468 return o
->short_name
;
471 /* Parses a long option whose command-line argument is pointed to by
472 |*state->arg_next|. Advances past the option so that the next one
473 will be parsed in the next call to |option_get()|. Sets |*argp| to
474 the option's argument, if any. Returns the option's identifier. */
476 handle_long_option (struct option_state
*state
, char **argp
)
478 const struct option
*o
; /* Iterator on options. */
479 char name
[16]; /* Option name. */
480 const char *arg
; /* Option argument. */
482 assert (state
!= NULL
483 && state
->arg_next
!= NULL
&& *state
->arg_next
!= NULL
484 && state
->options
!= NULL
487 /* Copy the option name into |name|
488 and put a pointer to its argument, or |NULL| if none, into |arg|. */
490 const char *p
= *state
->arg_next
+ 2;
491 const char *q
= p
+ strcspn (p
, "=");
492 size_t name_len
= q
- p
;
494 if (name_len
> (sizeof name
) - 1)
495 name_len
= (sizeof name
) - 1;
496 memcpy (name
, p
, name_len
);
497 name
[name_len
] = '\0';
499 arg
= (*q
== '=') ? q
+ 1 : NULL
;
502 /* Find option in |o|. */
503 for (o
= state
->options
; ; o
++)
504 if (o
->long_name
== NULL
)
505 fail ("unknown option --%s; use --help for help", name
);
506 else if (!strcmp (name
, o
->long_name
))
509 /* Make sure option has an argument if it should. */
510 if ((arg
!= NULL
) != (o
->has_arg
!= 0))
513 fail ("--%s can't take an argument; use --help for help", name
);
515 fail ("--%s requires an argument; use --help for help", name
);
518 /* Advance and return. */
520 *argp
= (char *) arg
;
521 return o
->short_name
;
524 /* Retrieves the next option in the state vector |state|.
525 Returns the option's identifier, or -1 if out of options.
526 Stores the option's argument, or |NULL| if none, into |*argp|. */
528 option_get (struct option_state
*state
, char **argp
)
530 assert (state
!= NULL
&& argp
!= NULL
);
532 /* No argument by default. */
535 /* Deal with left-over short options. */
536 if (state
->short_next
!= NULL
)
538 if (*state
->short_next
!= '\0')
539 return handle_short_option (state
, argp
);
541 state
->short_next
= NULL
;
544 /* Out of options? */
545 if (*state
->arg_next
== NULL
)
551 /* Non-option arguments not supported. */
552 if ((*state
->arg_next
)[0] != '-')
553 fail ("non-option arguments encountered; use --help for help");
554 if ((*state
->arg_next
)[1] == '\0')
555 fail ("unknown option `-'; use --help for help");
557 /* Handle the option. */
558 if ((*state
->arg_next
)[1] == '-')
559 return handle_long_option (state
, argp
);
562 state
->short_next
= *state
->arg_next
+ 1;
564 return handle_short_option (state
, argp
);
568 /* Command line parser. */
570 /* If |a| is a prefix for |b| or vice versa, returns the length of the
572 Otherwise, returns 0. */
574 match_len (const char *a
, const char *b
)
578 for (cnt
= 0; *a
== *b
&& *a
!= '\0'; a
++, b
++)
581 return (*a
!= *b
&& *a
!= '\0' && *b
!= '\0') ? 0 : cnt
;
584 /* |s| should point to a decimal representation of an integer.
585 Returns the value of |s|, if successful, or 0 on failure. */
589 long x
= strtol (s
, NULL
, 10);
590 return x
>= INT_MIN
&& x
<= INT_MAX
? x
: 0;
593 /* Print helpful syntax message and exit. */
597 static const char *help
[] =
599 "bst-test, unit test for GNU libavl.\n\n",
600 "Usage: %s [OPTION]...\n\n",
601 "In the option descriptions below, CAPITAL denote arguments.\n",
602 "If a long option shows an argument as mandatory, then it is\n",
603 "mandatory for the equivalent short option also. See the GNU\n",
604 "libavl manual for more information.\n\n",
605 "-t, --test=TEST Sets test to perform. TEST is one of:\n",
606 " correctness insert/delete/... (default)\n",
607 " overflow stack overflow test\n",
608 " benchmark benchmark test\n",
610 "-s, --size=TREE-SIZE Sets tree size in nodes (default 16).\n",
611 "-r, --repeat=COUNT Repeats operation COUNT times (default 16).\n",
612 "-i, --insert=ORDER Sets the insertion order. ORDER is one of:\n",
613 " random random permutation (default)\n",
614 " ascending ascending order 0...n-1\n",
615 " descending descending order n-1...0\n",
616 " balanced balanced tree order\n",
617 " zigzag zig-zag tree\n",
618 " asc-shifted n/2...n-1, 0...n/2-1\n",
619 " custom custom, read from stdin\n",
620 "-d, --delete=ORDER Sets the deletion order. ORDER is one of:\n",
621 " random random permutation (default)\n",
622 " reverse reverse order of insertion\n",
623 " same same as insertion order\n",
624 " custom custom, read from stdin\n",
625 "-a, --alloc=POLICY Sets allocation policy. POLICY is one of:\n",
626 " track track memory leaks (default)\n",
627 " no-track turn off leak detection\n",
628 " fail-CNT fail after CNT allocations\n",
629 " fail%%PCT fail random PCT%% of allocations\n",
630 " sub-B,A divide B-byte blocks in A-byte units\n",
631 " (Ignored for `benchmark' test.)\n",
632 "-A, --incr=INC Fail policies: arg increment per repetition.\n",
633 "-S, --seed=SEED Sets initial number seed to SEED.\n",
634 " (default based on system time)\n",
635 "-n, --nonstop Don't stop after a single error.\n",
636 "-q, --quiet Turns down verbosity level.\n",
637 "-v, --verbose Turns up verbosity level.\n",
638 "-h, --help Displays this help screen.\n",
639 "-V, --version Reports version and copyright information.\n",
644 for (p
= help
; *p
!= NULL
; p
++)
645 printf (*p
, pgm_name
);
650 /* Parses command-line arguments from null-terminated array |args|.
651 Sets up |options| appropriately to correspond. */
653 parse_command_line (char **args
, struct test_options
*options
)
655 static const struct option option_tab
[] =
664 {"operation", 'o', 1},
674 struct option_state
*state
;
676 /* Default options. */
677 options
->test
= TST_CORRECTNESS
;
678 options
->insert_order
= INS_RANDOM
;
679 options
->delete_order
= DEL_RANDOM
;
680 options
->alloc_policy
= MT_TRACK
;
681 options
->alloc_arg
[0] = 0;
682 options
->alloc_arg
[1] = 0;
683 options
->alloc_incr
= 0;
684 options
->node_cnt
= 15;
685 options
->iter_cnt
= 15;
686 options
->seed_given
= 0;
687 options
->verbosity
= 0;
688 options
->nonstop
= 0;
693 state
= option_init (option_tab
, args
+ 1);
697 int id
= option_get (state
, &arg
);
704 if (match_len (arg
, "correctness") >= 3)
705 options
->test
= TST_CORRECTNESS
;
706 else if (match_len (arg
, "overflow") >= 3)
707 options
->test
= TST_OVERFLOW
;
708 else if (match_len (arg
, "null") >= 3)
709 options
->test
= TST_NULL
;
711 fail ("unknown test \"%s\"", arg
);
716 static const char *orders
[INS_CNT
] =
718 "random", "ascending", "descending",
719 "balanced", "zigzag", "asc-shifted", "custom",
724 assert (sizeof orders
/ sizeof *orders
== INS_CNT
);
725 for (iter
= orders
; ; iter
++)
726 if (iter
>= orders
+ INS_CNT
)
727 fail ("unknown order \"%s\"", arg
);
728 else if (match_len (*iter
, arg
) >= 3)
730 options
->insert_order
= iter
- orders
;
738 static const char *orders
[DEL_CNT
] =
740 "random", "reverse", "same", "custom",
745 assert (sizeof orders
/ sizeof *orders
== DEL_CNT
);
746 for (iter
= orders
; ; iter
++)
747 if (iter
>= orders
+ DEL_CNT
)
748 fail ("unknown order \"%s\"", arg
);
749 else if (match_len (*iter
, arg
) >= 3)
751 options
->delete_order
= iter
- orders
;
758 if (match_len (arg
, "track") >= 3)
759 options
->alloc_policy
= MT_TRACK
;
760 else if (match_len (arg
, "no-track") >= 3)
761 options
->alloc_policy
= MT_NO_TRACK
;
762 else if (!strncmp (arg
, "fail", 3))
764 const char *p
= arg
+ strcspn (arg
, "-%");
766 options
->alloc_policy
= MT_FAIL_COUNT
;
768 options
->alloc_policy
= MT_FAIL_PERCENT
;
770 fail ("invalid allocation policy \"%s\"", arg
);
772 options
->alloc_arg
[0] = stoi (p
+ 1);
774 else if (!strncmp (arg
, "suballoc", 3))
776 const char *p
= strchr (arg
, '-');
777 const char *q
= strchr (arg
, ',');
778 if (p
== NULL
|| q
== NULL
)
779 fail ("invalid allocation policy \"%s\"", arg
);
781 options
->alloc_policy
= MT_SUBALLOC
;
782 options
->alloc_arg
[0] = stoi (p
+ 1);
783 options
->alloc_arg
[1] = stoi (q
+ 1);
784 if (options
->alloc_arg
[MT_BLOCK_SIZE
] < 32)
785 fail ("block size too small");
786 else if (options
->alloc_arg
[MT_ALIGN
]
787 > options
->alloc_arg
[MT_BLOCK_SIZE
])
788 fail ("alignment cannot be greater than block size");
789 else if (options
->alloc_arg
[MT_ALIGN
] < 1)
790 fail ("alignment must be at least 1");
795 options
->alloc_incr
= stoi (arg
);
799 options
->node_cnt
= stoi (arg
);
800 if (options
->node_cnt
< 1)
801 fail ("bad tree size \"%s\"", arg
);
805 options
->iter_cnt
= stoi (arg
);
806 if (options
->iter_cnt
< 1)
807 fail ("bad repeat count \"%s\"", arg
);
811 options
->seed_given
= 1;
812 options
->seed
= strtoul (arg
, NULL
, 0);
816 options
->nonstop
= 1;
820 options
->verbosity
--;
824 options
->verbosity
++;
832 fputs ("GNU libavl 2.0.2\n"
833 "Copyright (C) 1998-2002, 2004 "
834 "Free Software Foundation, Inc.\n"
835 "This program comes with NO WARRANTY, not even for\n"
836 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
837 "You may redistribute copies under the terms of the\n"
838 "GNU General Public License. For more information on\n"
839 "these matters, see the file named COPYING.\n",
849 /* Fills the |n| elements of |array[]| with a random permutation of the
850 integers between |0| and |n - 1|. */
852 permuted_integers (int array
[], size_t n
)
856 for (i
= 0; i
< n
; i
++)
859 for (i
= 0; i
< n
; i
++)
861 size_t j
= i
+ (unsigned) rand () / (RAND_MAX
/ (n
- i
) + 1);
868 /* Generates a list of integers that produce a balanced tree when
869 inserted in order into a binary tree in the usual way.
870 |min| and |max| inclusively bound the values to be inserted.
871 Output is deposited starting at |*array|. */
873 gen_balanced_tree (int min
, int max
, int **array
)
880 i
= (min
+ max
+ 1) / 2;
882 gen_balanced_tree (min
, i
- 1, array
);
883 gen_balanced_tree (i
+ 1, max
, array
);
887 /* Generates a permutation of the integers |0| to |n - 1| into
888 |insert[]| according to |insert_order|. */
890 gen_insertions (size_t n
, enum insert_order insert_order
, int insert
[])
894 switch (insert_order
)
897 permuted_integers (insert
, n
);
901 for (i
= 0; i
< n
; i
++)
906 for (i
= 0; i
< n
; i
++)
907 insert
[i
] = n
- i
- 1;
911 gen_balanced_tree (0, n
- 1, &insert
);
915 for (i
= 0; i
< n
; i
++)
919 insert
[i
] = n
- i
/ 2 - 1;
922 case INS_ASCENDING_SHIFTED
:
923 for (i
= 0; i
< n
; i
++)
925 insert
[i
] = i
+ n
/ 2;
926 if ((size_t) insert
[i
] >= n
)
932 for (i
= 0; i
< n
; i
++)
933 if (scanf ("%d", &insert
[i
]) == 0)
934 fail ("error reading insertion order from stdin");
942 /* Generates a permutation of the integers |0| to |n - 1| into
943 |delete[]| according to |delete_order| and |insert[]|. */
945 gen_deletions (size_t n
, enum delete_order delete_order
,
946 const int *insert
, int *delete)
950 switch (delete_order
)
953 permuted_integers (delete, n
);
957 for (i
= 0; i
< n
; i
++)
958 delete[i
] = insert
[n
- i
- 1];
962 for (i
= 0; i
< n
; i
++)
963 delete[i
] = insert
[i
];
967 for (i
= 0; i
< n
; i
++)
968 if (scanf ("%d", &delete[i
]) == 0)
969 fail ("error reading deletion order from stdin");
977 /* Choose and return an initial random seed based on the current time.
978 Based on code by Lawrence Kirby <fred@genesis.demon.co.uk>. */
982 time_t timeval
; /* Current time. */
983 unsigned char *ptr
; /* Type punned pointed into timeval. */
984 unsigned seed
; /* Generated seed. */
987 timeval
= time (NULL
);
988 ptr
= (unsigned char *) &timeval
;
991 for (i
= 0; i
< sizeof timeval
; i
++)
992 seed
= seed
* (UCHAR_MAX
+ 2u) + ptr
[i
];
998 main (int argc
, char *argv
[])
1000 struct test_options opts
; /* Command-line options. */
1001 int *insert
, *delete; /* Insertion and deletion orders. */
1002 int success
; /* Everything okay so far? */
1004 /* Initialize |pgm_name|, using |argv[0]| if sensible. */
1005 pgm_name
= argv
[0] != NULL
&& argv
[0][0] != '\0' ? argv
[0] : "bst-test";
1007 /* Parse command line into |options|. */
1008 parse_command_line (argv
, &opts
);
1010 if (opts
.verbosity
>= 0)
1011 fputs ("bst-test for GNU libavl 2.0.2; use --help to get help.\n", stdout
);
1013 if (!opts
.seed_given
)
1014 opts
.seed
= time_seed () % 32768u;
1016 insert
= xmalloc (sizeof *insert
* opts
.node_cnt
);
1017 delete = xmalloc (sizeof *delete * opts
.node_cnt
);
1019 /* Run the tests. */
1021 while (opts
.iter_cnt
--)
1023 struct mt_allocator
*alloc
;
1025 if (opts
.verbosity
>= 0)
1027 printf ("Testing seed=%u", opts
.seed
);
1028 if (opts
.alloc_incr
)
1029 printf (", alloc arg=%d", opts
.alloc_arg
[0]);
1034 /* Generate insertion and deletion order.
1035 Seed them separately to ensure deletion order is
1036 independent of insertion order. */
1038 gen_insertions (opts
.node_cnt
, opts
.insert_order
, insert
);
1040 srand (++opts
.seed
);
1041 gen_deletions (opts
.node_cnt
, opts
.delete_order
, insert
, delete);
1043 if (opts
.verbosity
>= 1)
1047 printf (" Insertion order:");
1048 for (i
= 0; i
< opts
.node_cnt
; i
++)
1049 printf (" %d", insert
[i
]);
1052 if (opts
.test
== TST_CORRECTNESS
)
1054 printf ("Deletion order:");
1055 for (i
= 0; i
< opts
.node_cnt
; i
++)
1056 printf (" %d", delete[i
]);
1061 alloc
= mt_create (opts
.alloc_policy
, opts
.alloc_arg
, opts
.verbosity
);
1065 struct libavl_allocator
*a
= mt_allocator (alloc
);
1069 case TST_CORRECTNESS
:
1070 okay
= test_correctness (a
, insert
, delete, opts
.node_cnt
,
1075 okay
= test_overflow (a
, insert
, opts
.node_cnt
, opts
.verbosity
);
1088 if (opts
.verbosity
>= 1)
1089 printf (" No errors.\n");
1094 printf (" Error!\n");
1099 opts
.alloc_arg
[0] += opts
.alloc_incr
;
1101 if (!success
&& !opts
.nonstop
)
1108 return success
? EXIT_SUCCESS
: EXIT_FAILURE
;