mirror of
https://https.git.savannah.gnu.org/git/gnulib.git
synced 2026-06-15 23:35:50 +00:00
430 lines
11 KiB
C
430 lines
11 KiB
C
/* Test of bitset.
|
|
Copyright (C) 2018-2026 Free Software Foundation, Inc.
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
|
|
#include <config.h>
|
|
|
|
#include "bitset.h"
|
|
|
|
#include "macros.h"
|
|
|
|
#define RANDOM(n) (rand () % (n))
|
|
|
|
static void
|
|
assert_bitset_equal (bitset bs1, bitset bs2)
|
|
{
|
|
debug_bitset (bs1);
|
|
debug_bitset (bs2);
|
|
ASSERT (bitset_size (bs1) == bitset_size (bs2));
|
|
for (bitset_bindex i = 0; i < bitset_size (bs1); ++i)
|
|
ASSERT (bitset_test (bs1, i) == bitset_test (bs2, i));
|
|
}
|
|
|
|
static void
|
|
bitset_random (bitset bs)
|
|
{
|
|
for (bitset_bindex i = 0; i < bitset_size (bs); ++i)
|
|
bitset_set (bs, RANDOM (2));
|
|
}
|
|
|
|
|
|
/* Check various operations on random bitsets with two different
|
|
implementations. */
|
|
|
|
static void
|
|
compare (enum bitset_attr a, enum bitset_attr b)
|
|
{
|
|
/* bitset_list (used in many operations) uses a cache whose size is
|
|
BITSET_LIST_SIZE */
|
|
const int nbits = RANDOM (2 * BITSET_LIST_SIZE);
|
|
|
|
/* Four read only random initial values of type A. */
|
|
const bitset asrc0 = bitset_create (nbits, a);
|
|
bitset_random (asrc0);
|
|
const bitset asrc1 = bitset_create (nbits, a);
|
|
bitset_random (asrc1);
|
|
const bitset asrc2 = bitset_create (nbits, a);
|
|
bitset_random (asrc2);
|
|
const bitset asrc3 = bitset_create (nbits, a);
|
|
bitset_random (asrc3);
|
|
|
|
/* Four read only values of type B, equal to the values of type A. */
|
|
const bitset bsrc0 = bitset_create (nbits, b);
|
|
bitset_copy (bsrc0, asrc0);
|
|
const bitset bsrc1 = bitset_create (nbits, b);
|
|
bitset_copy (bsrc1, asrc1);
|
|
const bitset bsrc2 = bitset_create (nbits, b);
|
|
bitset_copy (bsrc2, asrc2);
|
|
const bitset bsrc3 = bitset_create (nbits, b);
|
|
bitset_copy (bsrc3, asrc3);
|
|
|
|
/* Destinations for each operation. */
|
|
bitset adst = bitset_create (nbits, a);
|
|
bitset bdst = bitset_create (nbits, b);
|
|
|
|
/* count */
|
|
ASSERT (bitset_count (asrc0) == bitset_count (bsrc0));
|
|
|
|
/* not */
|
|
bitset_not (adst, asrc0);
|
|
bitset_not (bdst, bsrc0);
|
|
assert_bitset_equal (adst, bdst);
|
|
|
|
/* and */
|
|
bitset_and (adst, asrc0, asrc1);
|
|
bitset_and (bdst, bsrc0, bsrc1);
|
|
assert_bitset_equal (adst, bdst);
|
|
ASSERT (bitset_and_cmp (adst, asrc0, asrc1)
|
|
== bitset_and_cmp (bdst, bsrc0, bsrc1));
|
|
assert_bitset_equal (adst, bdst);
|
|
|
|
/* andn */
|
|
bitset_andn (adst, asrc0, asrc1);
|
|
bitset_andn (bdst, bsrc0, bsrc1);
|
|
assert_bitset_equal (adst, bdst);
|
|
ASSERT (bitset_andn_cmp (adst, asrc0, asrc1)
|
|
== bitset_andn_cmp (bdst, bsrc0, bsrc1));
|
|
assert_bitset_equal (adst, bdst);
|
|
|
|
/* or */
|
|
bitset_or (adst, asrc0, asrc1);
|
|
bitset_or (bdst, bsrc0, bsrc1);
|
|
assert_bitset_equal (adst, bdst);
|
|
ASSERT (bitset_or_cmp (adst, asrc0, asrc1)
|
|
== bitset_or_cmp (bdst, bsrc0, bsrc1));
|
|
assert_bitset_equal (adst, bdst);
|
|
|
|
/* xor */
|
|
bitset_xor (adst, asrc0, asrc1);
|
|
bitset_xor (bdst, bsrc0, bsrc1);
|
|
assert_bitset_equal (adst, bdst);
|
|
ASSERT (bitset_xor_cmp (adst, asrc0, asrc1)
|
|
== bitset_xor_cmp (bdst, bsrc0, bsrc1));
|
|
assert_bitset_equal (adst, bdst);
|
|
|
|
/* and_or */
|
|
bitset_and_or (adst, asrc0, asrc1, asrc2);
|
|
bitset_and_or (bdst, bsrc0, bsrc1, bsrc2);
|
|
assert_bitset_equal (adst, bdst);
|
|
ASSERT (bitset_and_or_cmp (adst, asrc0, asrc1, asrc2)
|
|
== bitset_and_or_cmp (bdst, bsrc0, bsrc1, bsrc2));
|
|
assert_bitset_equal (adst, bdst);
|
|
|
|
/* andn_or */
|
|
bitset_andn_or (adst, asrc0, asrc1, asrc2);
|
|
bitset_andn_or (bdst, bsrc0, bsrc1, bsrc2);
|
|
assert_bitset_equal (adst, bdst);
|
|
ASSERT (bitset_andn_or_cmp (adst, asrc0, asrc1, asrc2)
|
|
== bitset_andn_or_cmp (bdst, bsrc0, bsrc1, bsrc2));
|
|
assert_bitset_equal (adst, bdst);
|
|
|
|
/* or_and */
|
|
bitset_or_and (adst, asrc0, asrc1, asrc2);
|
|
bitset_or_and (bdst, bsrc0, bsrc1, bsrc2);
|
|
assert_bitset_equal (adst, bdst);
|
|
ASSERT (bitset_or_and_cmp (adst, asrc0, asrc1, asrc2)
|
|
== bitset_or_and_cmp (bdst, bsrc0, bsrc1, bsrc2));
|
|
assert_bitset_equal (adst, bdst);
|
|
|
|
/* ones */
|
|
bitset_ones (adst);
|
|
bitset_ones (bdst);
|
|
assert_bitset_equal (adst, bdst);
|
|
|
|
/* zero */
|
|
bitset_zero (adst);
|
|
bitset_zero (bdst);
|
|
assert_bitset_equal (adst, bdst);
|
|
|
|
/* first and last and FOR_EACH. */
|
|
/* Work on bdst to exercise all the bitset types (adst is
|
|
BITSET_VARIABLE). */
|
|
bitset_copy (bdst, bsrc0);
|
|
debug_bitset (bdst);
|
|
debug_bitset (bsrc0);
|
|
bitset_copy (adst, bdst);
|
|
|
|
/* count. */
|
|
ASSERT (bitset_count (adst) == bitset_count (bdst));
|
|
|
|
/* first and last */
|
|
{
|
|
bitset_bindex first = bitset_first (adst);
|
|
ASSERT (first == bitset_first (bdst));
|
|
|
|
bitset_bindex last = bitset_last (adst);
|
|
ASSERT (last == bitset_last (bdst));
|
|
|
|
ASSERT (first <= last);
|
|
}
|
|
|
|
|
|
/* FOR_EACH. */
|
|
{
|
|
bitset_iterator iter;
|
|
bitset_bindex j;
|
|
bitset_bindex first = bitset_first (bdst);
|
|
bitset_bindex last = bitset_last (bdst);
|
|
bool seen_first = false;
|
|
bool seen_last = false;
|
|
BITSET_FOR_EACH (iter, bdst, j, 0)
|
|
{
|
|
ASSERT (first <= j && j <= last);
|
|
ASSERT (bitset_test (bdst, j));
|
|
if (j == first)
|
|
seen_first = true;
|
|
if (j == last)
|
|
seen_last = true;
|
|
}
|
|
if (first == BITSET_BINDEX_MAX)
|
|
{
|
|
ASSERT (!seen_first);
|
|
ASSERT (!seen_last);
|
|
}
|
|
else
|
|
{
|
|
ASSERT (seen_first);
|
|
ASSERT (seen_last);
|
|
}
|
|
}
|
|
|
|
/* FOR_EACH_REVERSE. */
|
|
{
|
|
bitset_iterator iter;
|
|
bitset_bindex j;
|
|
bitset_bindex first = bitset_first (bdst);
|
|
bitset_bindex last = bitset_last (bdst);
|
|
bool seen_first = false;
|
|
bool seen_last = false;
|
|
BITSET_FOR_EACH_REVERSE (iter, bdst, j, 0)
|
|
{
|
|
ASSERT (first <= j && j <= last);
|
|
ASSERT (bitset_test (bdst, j));
|
|
if (j == first)
|
|
seen_first = true;
|
|
if (j == last)
|
|
seen_last = true;
|
|
}
|
|
if (first == BITSET_BINDEX_MAX)
|
|
{
|
|
ASSERT (!seen_first);
|
|
ASSERT (!seen_last);
|
|
}
|
|
else
|
|
{
|
|
ASSERT (seen_first);
|
|
ASSERT (seen_last);
|
|
}
|
|
}
|
|
|
|
|
|
/* resize.
|
|
|
|
ARRAY bitsets cannot be resized. */
|
|
if (bitset_type_get (bsrc0) != BITSET_ARRAY)
|
|
{
|
|
const int nbits_new = RANDOM (256);
|
|
bitset_copy (adst, asrc0);
|
|
bitset_copy (bdst, bsrc0);
|
|
ASSERT (nbits_new == bitset_resize (adst, nbits_new));
|
|
ASSERT (nbits_new == bitset_resize (bdst, nbits_new));
|
|
assert_bitset_equal (adst, bdst);
|
|
}
|
|
|
|
bitset_free (bdst);
|
|
bitset_free (bsrc3);
|
|
bitset_free (bsrc2);
|
|
bitset_free (bsrc1);
|
|
bitset_free (bsrc0);
|
|
bitset_free (adst);
|
|
bitset_free (asrc3);
|
|
bitset_free (asrc2);
|
|
bitset_free (asrc1);
|
|
bitset_free (asrc0);
|
|
}
|
|
|
|
|
|
/* Check empty bitsets. */
|
|
|
|
static void
|
|
check_zero (bitset bs)
|
|
{
|
|
fprintf (stderr, "check_zero\n");
|
|
bitset_zero (bs);
|
|
|
|
/* count. */
|
|
ASSERT (bitset_count (bs) == 0);
|
|
|
|
/* first and last */
|
|
ASSERT (bitset_first (bs) == BITSET_BINDEX_MAX);
|
|
ASSERT (bitset_last (bs) == BITSET_BINDEX_MAX);
|
|
|
|
/* FOR_EACH. */
|
|
{
|
|
bitset_iterator iter;
|
|
_GL_UNUSED bitset_bindex i;
|
|
BITSET_FOR_EACH (iter, bs, i, 0)
|
|
ASSERT (0);
|
|
BITSET_FOR_EACH_REVERSE (iter, bs, i, 0)
|
|
ASSERT (0);
|
|
}
|
|
}
|
|
|
|
/* Exercise on a single-bit values: it's easy to get the handling of
|
|
the most significant bit wrong. */
|
|
|
|
static void
|
|
check_one_bit (bitset bs, int bitno)
|
|
{
|
|
fprintf (stderr, "check_one_bit(%d)\n", bitno);
|
|
bitset_zero (bs);
|
|
bitset_set (bs, bitno);
|
|
|
|
/* count. */
|
|
ASSERT (bitset_count (bs) == 1);
|
|
|
|
/* test. */
|
|
ASSERT (bitset_test (bs, bitno));
|
|
|
|
/* first and last */
|
|
ASSERT (bitset_first (bs) == bitno);
|
|
ASSERT (bitset_last (bs) == bitno);
|
|
|
|
/* FOR_EACH. */
|
|
{
|
|
bitset_iterator iter;
|
|
bitset_bindex i;
|
|
BITSET_FOR_EACH (iter, bs, i, 0)
|
|
ASSERT (i == bitno);
|
|
|
|
BITSET_FOR_EACH_REVERSE (iter, bs, i, 0)
|
|
ASSERT (i == bitno);
|
|
}
|
|
}
|
|
|
|
/* Check full bitsets. */
|
|
|
|
static void
|
|
check_ones (bitset bs)
|
|
{
|
|
fprintf (stderr, "check_ones\n");
|
|
const bitset_bindex size = bitset_size (bs);
|
|
|
|
bitset_ones (bs);
|
|
debug_bitset (bs);
|
|
|
|
/* count. */
|
|
ASSERT (bitset_count (bs) == size);
|
|
|
|
/* first and last */
|
|
ASSERT (bitset_first (bs) == 0);
|
|
ASSERT (bitset_last (bs) == size - 1);
|
|
|
|
/* FOR_EACH. */
|
|
{
|
|
bitset_iterator iter;
|
|
bitset_bindex i;
|
|
bitset_bindex count = 0;
|
|
BITSET_FOR_EACH (iter, bs, i, 0)
|
|
ASSERT (i == count++);
|
|
ASSERT (count == size);
|
|
BITSET_FOR_EACH_REVERSE (iter, bs, i, 0)
|
|
ASSERT (i == --count);
|
|
ASSERT (count == 0);
|
|
}
|
|
}
|
|
|
|
/* Check various operations against expected values for a bitset
|
|
having attributes ATTR. */
|
|
|
|
static void
|
|
check_attributes (enum bitset_attr attr, int nbits)
|
|
{
|
|
bitset bs0 = bitset_create (nbits, attr);
|
|
ASSERT (bitset_size (bs0) == nbits);
|
|
ASSERT (bitset_count (bs0) == 0);
|
|
ASSERT (bitset_empty_p (bs0));
|
|
|
|
bitset bs1 = bitset_create (nbits, attr);
|
|
bitset_set (bs1, 1);
|
|
bitset_set (bs1, 3);
|
|
bitset_set (bs1, 5);
|
|
ASSERT (bitset_count (bs1) == 3);
|
|
ASSERT (!bitset_empty_p (bs1));
|
|
|
|
bitset bs2 = bitset_create (nbits, attr);
|
|
bitset_set (bs2, 0);
|
|
bitset_set (bs2, 2);
|
|
bitset_set (bs2, 4);
|
|
|
|
/* disjoint_p */
|
|
ASSERT (bitset_disjoint_p (bs1, bs2));
|
|
|
|
/* and */
|
|
bitset bs = bitset_create (nbits, attr);
|
|
bitset_and (bs, bs1, bs2);
|
|
ASSERT (bitset_count (bs) == 0);
|
|
|
|
/* or */
|
|
bitset_or (bs, bs1, bs2);
|
|
ASSERT (bitset_count (bs) == 6);
|
|
|
|
check_zero (bs);
|
|
check_ones (bs);
|
|
|
|
/* Exercise on all the single-bit values: it's easy to get the
|
|
handling of the most significant bit wrong. */
|
|
for (int bitno = 0; bitno < nbits; ++bitno)
|
|
check_one_bit (bs, bitno);
|
|
|
|
bitset_free (bs);
|
|
bitset_free (bs2);
|
|
bitset_free (bs1);
|
|
bitset_free (bs0);
|
|
}
|
|
|
|
int main (void)
|
|
{
|
|
bitset_stats_enable ();
|
|
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
/* table bitsets have elements that store 256 bits. bitset_list
|
|
(used in many operations) uses a cache whose size is
|
|
BITSET_LIST_SIZE. */
|
|
int nbits =
|
|
i == 0 ? 1
|
|
: i == 1 ? 32
|
|
: i == 2 ? 257
|
|
: (BITSET_LIST_SIZE + 1);
|
|
check_attributes (BITSET_FIXED, nbits);
|
|
check_attributes (BITSET_VARIABLE, nbits);
|
|
check_attributes (BITSET_DENSE, nbits);
|
|
check_attributes (BITSET_SPARSE, nbits);
|
|
check_attributes (BITSET_FRUGAL, nbits);
|
|
check_attributes (BITSET_GREEDY, nbits);
|
|
}
|
|
|
|
compare (BITSET_VARIABLE, BITSET_FIXED);
|
|
compare (BITSET_VARIABLE, BITSET_VARIABLE);
|
|
compare (BITSET_VARIABLE, BITSET_DENSE);
|
|
compare (BITSET_VARIABLE, BITSET_SPARSE);
|
|
compare (BITSET_VARIABLE, BITSET_FRUGAL);
|
|
compare (BITSET_VARIABLE, BITSET_GREEDY);
|
|
|
|
bitset_stats_dump (stderr);
|
|
return test_exit_status;
|
|
}
|