1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 /* This is a test program for the routines defined in
18 range-tower.c. This test program aims to be as comprehensive as
19 possible. With -DNDEBUG, "gcov -b" should report 100%
20 coverage of lines and branches in range-tower.c routines.
21 (Without -DNDEBUG, branches caused by failed assertions will
22 not be taken.) "valgrind --leak-check=yes
23 --show-reachable=yes" should give a clean report, both with
24 and without -DNDEBUG. */
30 #include "libpspp/range-tower.h"
38 #include "libpspp/compiler.h"
39 #include "libpspp/pool.h"
41 #include "gl/minmax.h"
42 #include "gl/xalloc.h"
44 /* Exit with a failure code.
45 (Place a breakpoint on this function while debugging.) */
52 /* If OK is not true, prints a message about failure on the
53 current source file and the given LINE and terminates. */
55 check_func (bool ok, int line)
59 fprintf (stderr, "%s:%d: check failed\n", __FILE__, line);
64 /* Verifies that EXPR evaluates to true.
65 If not, prints a message citing the calling line number and
67 #define check(EXPR) check_func ((EXPR), __LINE__)
69 /* A contiguous region. */
72 unsigned long int start; /* Start of region. */
73 unsigned long int end; /* One past the end. */
76 /* Number of bits in an unsigned int. */
77 #define UINT_BIT (CHAR_BIT * sizeof (unsigned int))
79 /* Returns the number of contiguous 1-bits in X starting from bit
81 This implementation is designed to be obviously correct, not
84 count_one_bits (unsigned long int x)
95 /* Searches the bits in PATTERN from right to left starting from
96 bit OFFSET for one or more 1-bits. If any are found, sets
97 *START to the bit index of the first and *WIDTH to the number
98 of contiguous 1-bits and returns true. Otherwise, returns
100 This implementation is designed to be obviously correct, not
103 next_region (unsigned int pattern, unsigned int offset,
104 unsigned long int *start, unsigned long int *width)
108 assert (offset <= UINT_BIT);
109 for (i = offset; i < UINT_BIT; i++)
110 if (pattern & (1u << i))
113 *width = count_one_bits (pattern >> i);
119 /* Searches the bits in PATTERN from left to right starting from
120 just beyond bit OFFSET for one or more 1-bits. If any are
121 found, sets *START to the bit index of the first and *WIDTH to
122 the number of contiguous 1-bits and returns true. Otherwise,
124 This implementation is designed to be obviously correct, not
127 prev_region (unsigned int pattern, unsigned int offset,
128 unsigned long int *start, unsigned long int *width)
132 assert (offset <= UINT_BIT);
133 for (i = offset; i-- > 0;)
134 if (pattern & (1u << i))
138 while (i-- > 0 && pattern & (1u << i))
148 /* Searches the bits in PATTERN from right to left starting from
149 bit OFFSET. Returns the bit index of the first 1-bit found,
150 or ULONG_MAX if none is found. */
151 static unsigned long int
152 next_1bit (unsigned int pattern, unsigned int offset,
153 unsigned long int pattern_offset)
155 for (; offset < UINT_BIT; offset++)
156 if (pattern & (1u << offset))
157 return offset + pattern_offset;
162 print_structure (const struct abt_node *node_)
164 struct range_tower_node *node;
168 node = ABT_DATA (node_, struct range_tower_node, abt_node);
169 printf ("%lu+%lu/%d", node->n_zeros, node->n_ones, node->abt_node.level);
170 if (node->abt_node.down[0] || node->abt_node.down[1])
173 print_structure (node->abt_node.down[0]);
175 print_structure (node->abt_node.down[1]);
180 /* Prints the regions in RT to stdout. */
182 print_regions (const struct range_tower *rt)
184 const struct range_tower_node *node;
186 printf ("contents:");
187 for (node = range_tower_first__ (rt); node != NULL;
188 node = range_tower_next__ (rt, node))
189 printf (" (%lu,%lu)", node->n_zeros, node->n_ones);
191 printf ("structure:");
192 print_structure (rt->abt.root);
197 check_tree (const struct abt_node *abt_node, unsigned long int *subtree_width)
199 const struct range_tower_node *node = range_tower_node_from_abt__ (abt_node);
200 unsigned long int left_width, right_width;
208 check_tree (node->abt_node.down[0], &left_width);
209 check_tree (node->abt_node.down[1], &right_width);
211 *subtree_width = node->n_zeros + node->n_ones + left_width + right_width;
212 check (node->subtree_width == *subtree_width);
215 /* Checks that the regions in RT match the bits in PATTERN. */
217 check_pattern (const struct range_tower *rt, unsigned int pattern,
218 unsigned long int offset)
220 const struct range_tower_node *node;
221 unsigned long int start, start2, width;
222 unsigned long int tree_width;
223 unsigned long int s1, s2;
226 check_tree (rt->abt.root, &tree_width);
227 check (tree_width == ULONG_MAX);
229 if (offset > ULONG_MAX - 32)
231 pattern <<= offset - (ULONG_MAX - 32);
232 offset = ULONG_MAX - 32;
235 for (node = rand () % 2 ? range_tower_first (rt) : range_tower_next (rt, NULL),
237 next_region (pattern, start + width, &start, &width);
238 node = range_tower_next (rt, node))
240 unsigned long int node_start;
243 check (node != NULL);
244 check (range_tower_node_get_start (node) == start + offset);
245 check (range_tower_node_get_end (node) == start + offset + width);
246 check (range_tower_node_get_width (node) == width);
248 x = start + offset - node->n_zeros;
249 check (range_tower_lookup (rt, x, &node_start) == node);
250 check (node_start == start + offset - node->n_zeros);
252 x = start + offset + width - 1;
253 check (range_tower_lookup (rt, x, &node_start) == node);
254 check (node_start == start + offset - node->n_zeros);
256 check (node == NULL);
259 RANGE_TOWER_FOR_EACH (node, start2, rt)
261 check (next_region (pattern, start + width, &start, &width));
262 check (start + offset == start2);
263 check (range_tower_node_get_width (node) == width);
265 check (!next_region (pattern, start + width, &start, &width));
267 for (node = rand () % 2 ? range_tower_last (rt) : range_tower_prev (rt, NULL),
269 prev_region (pattern, start, &start, &width);
270 node = range_tower_prev (rt, node))
272 check (node != NULL);
273 check (range_tower_node_get_start (node) == offset + start);
274 check (range_tower_node_get_end (node) == offset + start + width);
275 check (range_tower_node_get_width (node) == width);
277 check (node == NULL);
279 /* Scan from all possible positions, resetting the cache each
280 time, to ensure that we get the correct answers without
282 for (start = 0; start <= 32; start++)
284 struct range_tower *nonconst_rt = CONST_CAST (struct range_tower *, rt);
286 nonconst_rt->cache_end = 0;
287 s1 = range_tower_scan (rt, offset + start);
288 s2 = next_1bit (pattern, start, offset);
292 /* Scan in forward order to exercise expected cache behavior. */
293 for (s1 = range_tower_scan (rt, 0), s2 = next_1bit (pattern, 0, offset); ;
294 s1 = range_tower_scan (rt, s1 + 1), s2 = next_1bit (pattern, (s2 - offset) + 1, offset))
301 /* Scan in random order to frustrate cache. */
302 for (i = 0; i < 32; i++)
304 start = rand () % 32;
305 s1 = range_tower_scan (rt, start + offset);
306 s2 = next_1bit (pattern, start, offset);
310 /* Test range_tower_scan() with negative cache. */
311 check (!range_tower_contains (rt, 999));
313 check (range_tower_scan (rt, 1111) == ULONG_MAX);
315 /* Check for containment without caching. */
316 for (i = 0; i < UINT_BIT; i++)
318 struct range_tower *nonconst_rt = CONST_CAST (struct range_tower *, rt);
319 nonconst_rt->cache_end = 0;
320 check (range_tower_contains (rt, i + offset)
321 == ((pattern & (1u << i)) != 0));
324 /* Check for containment with caching. */
325 for (i = 0; i < UINT_BIT; i++)
326 check (range_tower_contains (rt, i + offset)
327 == ((pattern & (1u << i)) != 0));
329 check (!range_tower_contains (rt,
330 UINT_BIT + rand () % (ULONG_MAX - UINT_BIT * 2)));
332 check (range_tower_is_empty (rt) == (pattern == 0));
335 /* Creates and returns a range tower that contains regions for the
336 bits tower in PATTERN. */
337 static struct range_tower *
338 make_pattern (unsigned int pattern, unsigned long int offset)
340 unsigned long int start = 0;
341 unsigned long int width = 0;
342 struct range_tower *rt = range_tower_create_pool (NULL);
343 while (next_region (pattern, start + width, &start, &width))
344 range_tower_set1 (rt, start + offset, width);
345 check_pattern (rt, pattern, offset);
349 /* Returns an unsigned int with bits OFS...OFS+CNT (exclusive)
350 tower to 1, other bits tower to 0. */
352 bit_range (unsigned int ofs, unsigned int cnt)
354 assert (ofs < UINT_BIT);
355 assert (cnt <= UINT_BIT);
356 assert (ofs + cnt <= UINT_BIT);
358 return cnt < UINT_BIT ? ((1u << cnt) - 1) << ofs : UINT_MAX;
361 /* Tests setting all possible ranges of 1s into all possible range sets (up to
362 a small maximum number of bits). */
366 const int positions = 9;
367 unsigned int init_pat;
371 for (k = 0; k < 2; k++)
372 for (init_pat = 0; init_pat < (1u << positions); init_pat++)
373 for (start = 0; start < positions; start++)
374 for (width = 0; width + start <= positions; width++)
376 unsigned long int offset = k ? ULONG_MAX - positions : 0;
377 struct range_tower *rt, *rt2;
378 unsigned int final_pat;
380 rt = make_pattern (init_pat, offset);
381 range_tower_set1 (rt, offset + start, width);
382 final_pat = init_pat | bit_range (start, width);
383 check_pattern (rt, final_pat, offset);
384 rt2 = range_tower_clone (rt, NULL);
385 check_pattern (rt2, final_pat, offset);
386 range_tower_destroy (rt);
387 range_tower_destroy (rt2);
391 /* Tests setting all possible ranges of 0s into all possible range sets (up to
392 a small maximum number of bits). */
396 const int positions = 9;
397 unsigned int init_pat;
400 for (k = 0; k < 2; k++)
401 for (init_pat = 0; init_pat < (1u << positions); init_pat++)
402 for (start = 0; start < positions; start++)
403 for (width = 0; start + width <= positions; width++)
405 unsigned long int offset = k ? ULONG_MAX - positions : 0;
406 struct range_tower *rt;
407 unsigned int final_pat;
409 rt = make_pattern (init_pat, offset);
410 range_tower_set0 (rt, offset + start, width);
411 final_pat = init_pat & ~bit_range (start, width);
412 check_pattern (rt, final_pat, offset);
413 range_tower_destroy (rt);
417 /* Tests inserting all possible ranges of 0s into all possible range sets (up
418 to a small maximum number of bits). */
422 const int positions = 9;
423 unsigned int init_pat;
426 for (k = 0; k < 2; k++)
427 for (init_pat = 0; init_pat < (1u << positions); init_pat++)
428 for (start = 0; start < positions; start++)
429 for (width = 0; start + width <= positions; width++)
431 unsigned long int offset = k ? ULONG_MAX - positions : 0;
432 struct range_tower *rt;
433 unsigned int final_pat;
435 rt = make_pattern (init_pat, offset);
436 range_tower_insert0 (rt, offset + start, width);
437 final_pat = init_pat & bit_range (0, start);
438 final_pat |= (init_pat & bit_range (start, positions - start)) << width;
439 check_pattern (rt, final_pat, offset);
440 range_tower_destroy (rt);
444 /* Tests inserting all possible ranges of 1s into all possible range sets (up
445 to a small maximum number of bits). */
449 const int positions = 9;
450 unsigned int init_pat;
453 for (k = 0; k < 2; k++)
454 for (init_pat = 0; init_pat < (1u << positions); init_pat++)
455 for (start = 0; start < positions; start++)
456 for (width = 0; start + width <= positions; width++)
458 struct range_tower *rt;
459 unsigned int final_pat;
461 rt = make_pattern (init_pat, 0);
462 range_tower_insert1 (rt, start, width);
463 final_pat = init_pat & bit_range (0, start);
464 final_pat |= bit_range (start, width);
465 final_pat |= (init_pat & bit_range (start, positions - start)) << width;
466 check_pattern (rt, final_pat, 0);
467 range_tower_destroy (rt);
471 /* Tests setting all possible ranges from all possible range sets (up to a
472 small maximum number of bits). */
476 const int positions = 9;
477 unsigned int init_pat;
480 for (k = 0; k < 2; k++)
481 for (init_pat = 0; init_pat < (1u << positions); init_pat++)
482 for (start = 0; start < positions; start++)
483 for (width = 0; start + width <= positions; width++)
485 unsigned long int offset = k ? ULONG_MAX - positions : 0;
486 struct range_tower *rt;
487 unsigned int final_pat;
489 rt = make_pattern (init_pat, offset);
490 range_tower_delete (rt, start + offset, width);
491 final_pat = init_pat & bit_range (0, start);
492 final_pat |= (init_pat & (UINT_MAX << (start + width))) >> width;
493 check_pattern (rt, final_pat, offset);
494 range_tower_destroy (rt);
498 /* Tests moving all possible ranges (up to a small maximum number of bits). */
502 const int positions = 9;
503 unsigned int init_pat;
504 int new_start, old_start, width, k;
506 for (k = 0; k < 2; k++)
507 for (init_pat = 0; init_pat < (1u << positions); init_pat++)
508 for (width = 0; width <= positions; width++)
509 for (new_start = 0; new_start + width <= positions; new_start++)
510 for (old_start = 0; old_start + width <= positions; old_start++)
512 unsigned long int offset = k ? ULONG_MAX - positions : 0;
513 struct range_tower *rt;
514 unsigned int final_pat;
516 if (new_start == old_start || width == 0)
517 final_pat = init_pat;
518 else if (new_start < old_start)
520 final_pat = init_pat & bit_range (0, new_start);
521 final_pat |= (init_pat & bit_range (old_start, width)) >> (old_start - new_start);
522 final_pat |= (init_pat & bit_range (new_start, old_start - new_start)) << width;
523 final_pat |= init_pat & bit_range (old_start + width, positions - (old_start + width));
527 final_pat = init_pat & bit_range (0, old_start);
528 final_pat |= (init_pat & bit_range (old_start + width, new_start - old_start)) >> width;
529 final_pat |= (init_pat & bit_range (old_start, width)) << (new_start - old_start);
530 final_pat |= init_pat & bit_range (new_start + width, positions - (new_start + width));
533 rt = make_pattern (init_pat, offset);
534 range_tower_move (rt, old_start + offset, new_start + offset,
536 check_pattern (rt, final_pat, offset);
537 range_tower_destroy (rt);
541 /* Tests freeing a range tower through a pool. */
546 struct range_tower *rt;
548 /* Destroy the range tower, then the pool.
549 Makes sure that this doesn't cause a double-free. */
550 pool = pool_create ();
551 rt = range_tower_create_pool (pool);
552 range_tower_set1 (rt, 1, 10);
553 range_tower_destroy (rt);
556 /* Just destroy the pool.
557 Makes sure that this doesn't cause a leak. */
558 pool = pool_create ();
559 rt = range_tower_create_pool (pool);
560 range_tower_set1 (rt, 1, 10);
564 /* Tests range_tower_destroy(NULL). */
566 test_destroy_null (void)
568 range_tower_destroy (NULL);
576 const char *description;
577 void (*function) (void);
580 static const struct test tests[] =
624 enum { N_TESTS = sizeof tests / sizeof *tests };
627 main (int argc, char *argv[])
633 fprintf (stderr, "exactly one argument required; use --help for help\n");
636 else if (!strcmp (argv[1], "--help"))
638 printf ("%s: test range tower library\n"
639 "usage: %s TEST-NAME\n"
640 "where TEST-NAME is one of the following:\n",
642 for (i = 0; i < N_TESTS; i++)
643 printf (" %s\n %s\n", tests[i].name, tests[i].description);
648 for (i = 0; i < N_TESTS; i++)
649 if (!strcmp (argv[1], tests[i].name))
651 tests[i].function ();
655 fprintf (stderr, "unknown test %s; use --help for help\n", argv[1]);