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+N (exclusive)
350 tower to 1, other bits tower to 0. */
352 bit_range (unsigned int ofs
, unsigned int n
)
354 assert (ofs
< UINT_BIT
);
355 assert (n
<= UINT_BIT
);
356 assert (ofs
+ n
<= UINT_BIT
);
358 return n
< UINT_BIT
? ((1u << n
) - 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]);