summaryrefslogtreecommitdiff
path: root/lib/bitset.c
diff options
context:
space:
mode:
authorAkim Demaille <akim@epita.fr>2002-03-04 11:58:52 +0000
committerAkim Demaille <akim@epita.fr>2002-03-04 11:58:52 +0000
commit7086e7071e8bfa2012e9134530a158c88a832ba6 (patch)
tree8436d1b7ae0599951b8ae78a324e3fac89efb66b /lib/bitset.c
parent98254360e3cc22aa7a7aecaae477347ee0ecc638 (diff)
downloadbison-7086e7071e8bfa2012e9134530a158c88a832ba6.tar.gz
* lib/bitset-int.h, lib/bitset.c, lib/bitset.h, lib/bitsetv.c,
* lib/bitsetv.h, lib/ebitset.c, lib/ebitset.h, lib/lbitset.c, * lib/lbitset.h, lib/sbitset.c, lib/sbitset.h: New. * src/closure.c (fderives): Be an array of bitsets.
Diffstat (limited to 'lib/bitset.c')
-rw-r--r--lib/bitset.c835
1 files changed, 835 insertions, 0 deletions
diff --git a/lib/bitset.c b/lib/bitset.c
new file mode 100644
index 00000000..c68ed788
--- /dev/null
+++ b/lib/bitset.c
@@ -0,0 +1,835 @@
+/* General bitsets.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz).
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include "bitset.h"
+#include "obstack.h"
+
+static void bitset_print PARAMS ((FILE *, bitset, int));
+
+#if BITSET_CHECK
+#define BITSET__CHECK2(DST, SRC) \
+if ((DST)->OPS != (SRC)->OPS) abort ();
+
+#define BITSET__CHECK3(DST, SRC1, SRC2) \
+if ((DST)->OPS != (SRC1)->OPS || (DST)->OPS != (SRC2)->OPS) abort ();
+
+#define BITSET__CHECK4(DST, SRC1, SRC2) \
+if ((DST)->OPS != (SRC1)->OPS || (DST)->OPS != (SRC2)->OPS \
+ || (DST)->OPS != (SRC3)->OPS) abort ();
+#else
+#define BITSET__CHECK2(DST, SRC)
+
+#define BITSET__CHECK3(DST, SRC1, SRC2)
+
+#define BITSET__CHECK4(DST, SRC1, SRC2, SRC3)
+#endif
+
+#if BITSET_STATS
+#define BITSET_STATS_FILE "bitset.dat"
+
+#define BITSET_LOG_COUNT_BINS 10
+#define BITSET_LOG_SIZE_BINS 16
+#define BITSET_DENSITY_BINS 20
+
+struct bitset_type_stats_struct
+{
+ unsigned int xmallocs;
+ unsigned int xfrees;
+ unsigned int oballocs;
+ unsigned int obfrees;
+ unsigned int lists;
+ unsigned int list_counts[BITSET_LOG_COUNT_BINS];
+ unsigned int list_sizes[BITSET_LOG_SIZE_BINS];
+ unsigned int list_density[BITSET_DENSITY_BINS];
+};
+
+struct bitset_stats_struct
+{
+ unsigned int runs;
+ struct bitset_type_stats_struct types[BITSET_TYPE_NUM];
+};
+
+struct bitset_stats_struct bitset_stats_data;
+struct bitset_stats_struct *bitset_stats;
+
+static void bitset_percent_histogram_print PARAMS ((FILE *, const char *,
+ const char *,
+ unsigned int,
+ unsigned int *));
+static void bitset_log_histogram_print PARAMS ((FILE *, const char *,
+ const char *,
+ unsigned int, unsigned int *));
+static void bitset_stats_print_1 PARAMS ((FILE *, const char *,
+ struct bitset_type_stats_struct *));
+static void bitset_stats_print PARAMS ((FILE *, int));
+static void bitset_stats_read PARAMS ((void));
+static void bitset_stats_write PARAMS ((void));
+
+#define BITSET_STATS_XMALLOCS_INC(TYPE) \
+ if (bitset_stats) \
+ bitset_stats->types[(TYPE)].xmallocs++
+
+#define BITSET_STATS_XFREES_INC(BSET) \
+ if (bitset_stats) \
+ bitset_stats->types[(BSET)->ops->type].xfrees++
+
+#define BITSET_STATS_OBALLOCS_INC(TYPE) \
+ if (bitset_stats) \
+ bitset_stats->types[(TYPE)].oballocs++
+
+#define BITSET_STATS_OBFREES_INC(BSET) \
+ if (bitset_stats) \
+ bitset_stats->types[(BSET)->ops->type].obfrees++
+
+#define BITSET_STATS_LISTS_INC(BSET) \
+ if (bitset_stats) \
+ bitset_stats->types[(BSET)->ops->type].lists++
+
+#define BITSET_STATS_LIST_COUNTS_INC(BSET, I) \
+ if (bitset_stats) \
+ bitset_stats->types[(BSET)->ops->type].list_counts[(I)]++
+
+#define BITSET_STATS_LIST_SIZES_INC(BSET, I) \
+ if (bitset_stats) \
+ bitset_stats->types[(BSET)->ops->type].list_sizes[(I)]++
+
+#define BITSET_STATS_LIST_DENSITY_INC(BSET, I) \
+ if (bitset_stats) \
+ bitset_stats->types[(BSET)->ops->type].list_density[(I)]++
+
+#else
+#define BITSET_STATS_XMALLOCS_INC(TYPE)
+
+#define BITSET_STATS_XFREES_INC(BSET)
+
+#define BITSET_STATS_OBALLOCS_INC(TYPE)
+
+#define BITSET_STATS_OBFREES_INC(BSET)
+
+#define BITSET_STATS_LISTS_INC(BSET)
+
+#define BITSET_STATS_LIST_COUNTS_INC(BSET, I)
+
+#define BITSET_STATS_LIST_SIZES_INC(BSET, I)
+
+#define BITSET_STATS_LIST_DENSITY_INC(BSET, I)
+#endif /* BITSET_STATS */
+
+
+
+/* Return number of bytes required to create a N_BIT bitset
+ of TYPE. The bitset may grow to require more bytes than this. */
+int
+bitset_bytes (type, n_bits)
+ enum bitset_type type;
+ bitset_bindex n_bits;
+{
+ unsigned int bytes;
+
+ switch (type)
+ {
+ case BITSET_ARRAY:
+ bytes = sbitset_bytes (n_bits);
+ break;
+
+ case BITSET_LIST:
+ bytes = lbitset_bytes (n_bits);
+ break;
+
+ case BITSET_TABLE:
+ bytes = ebitset_bytes (n_bits);
+ break;
+
+ default:
+ abort ();
+ }
+
+ return bytes;
+}
+
+
+/* Initialise bitset BSET of TYPE for N_BITS. */
+bitset
+bitset_init (bset, n_bits, type)
+ bitset bset;
+ bitset_bindex n_bits;
+ enum bitset_type type;
+{
+ switch (type)
+ {
+ case BITSET_ARRAY:
+ return sbitset_init (bset, n_bits);
+
+ case BITSET_LIST:
+ return lbitset_init (bset, n_bits);
+
+ case BITSET_TABLE:
+ return ebitset_init (bset, n_bits);
+
+ default:
+ abort ();
+ }
+}
+
+
+/* Select a bitset type for a set of N_BITS and with attribute hints
+ specified by ATTR. For variable size bitsets, N_BITS is only a
+ hint and may be zero. */
+enum bitset_type
+bitset_type_choose (n_bits, attr)
+ bitset_bindex n_bits ATTRIBUTE_UNUSED;
+ unsigned int attr;
+{
+ enum bitset_type type;
+
+#ifdef ENABLE_CHECKING
+ /* Check attributes. */
+ if (attr & BITSET_FIXED && attr & BITSET_VARIABLE)
+ abort ();
+ if (attr & BITSET_SPARSE && attr & BITSET_DENSE)
+ abort ();
+
+ /* Note that sometimes we will be asked for a zero length
+ fixed size bitset. */
+#endif
+
+ /* Choose the type of bitset. */
+
+ type = BITSET_ARRAY;
+ /* Currently, the simple bitsets do not support a variable size. */
+ if (attr & BITSET_VARIABLE || attr & BITSET_SPARSE)
+ {
+ type = BITSET_LIST;
+ if (attr & BITSET_DENSE || attr & BITSET_GREEDY)
+ type = BITSET_TABLE;
+ }
+
+ return type;
+}
+
+
+/* Create a bitset of N_BITS of type TYPE. */
+bitset
+bitset_alloc (n_bits, type)
+ bitset_bindex n_bits;
+ enum bitset_type type;
+{
+ unsigned int bytes;
+ bitset bset;
+
+ BITSET_STATS_XMALLOCS_INC (type);
+
+ bytes = bitset_bytes (type, n_bits);
+
+ bset = (bitset) xmalloc (bytes);
+
+ return bitset_init (bset, n_bits, type);
+}
+
+
+/* Create a bitset of N_BITS of type TYPE. */
+bitset
+bitset_obstack_alloc (bobstack, n_bits, type)
+ struct obstack *bobstack;
+ bitset_bindex n_bits;
+ enum bitset_type type;
+{
+ unsigned int bytes;
+
+ BITSET_STATS_OBALLOCS_INC (type);
+
+ bytes = bitset_bytes (type, n_bits);
+
+ return bitset_init (obstack_alloc (bobstack, bytes), n_bits, type);
+}
+
+
+/* Create a bitset of N_BITS and with attribute hints specified by
+ ATTR. */
+bitset
+bitset_create (n_bits, attr)
+ bitset_bindex n_bits;
+ unsigned int attr;
+{
+ enum bitset_type type;
+
+ type = bitset_type_choose (n_bits, attr);
+
+ return bitset_alloc (n_bits, type);
+}
+
+
+/* Free bitset BSET. */
+void
+bitset_free (bset)
+ bitset bset;
+{
+ BITSET_STATS_XFREES_INC (bset);
+
+ if (bset->ops->free)
+ BITSET__FREE (bset);
+
+ bset->ops = NULL;
+ free (bset);
+}
+
+
+/* Free bitset BSET allocated on obstack. */
+void
+bitset_obstack_free (bset)
+ bitset bset;
+{
+ BITSET_STATS_OBFREES_INC (bset);
+
+ if (bset->ops->free)
+ BITSET__FREE (bset);
+ bset->ops = NULL;
+}
+
+
+/* Find next bit set in SRC starting from and including BITNO.
+ Return -1 if SRC empty. */
+int
+bitset_next (src, bitno)
+ bitset src;
+ bitset_bindex bitno;
+{
+ bitset_bindex val;
+ bitset_bindex next = bitno;
+
+ if (!bitset_list (src, &val, 1, &next))
+ return -1;
+ return val;
+}
+
+
+/* Find previous bit set in SRC starting from and including BITNO.
+ Return -1 if SRC empty. */
+int
+bitset_prev (src, bitno)
+ bitset src;
+ bitset_bindex bitno;
+{
+ bitset_bindex val;
+ bitset_bindex next = bitno;
+
+ if (!bitset_reverse_list (src, &val, 1, &next))
+ return -1;
+ return val;
+}
+
+
+/* Find first set bit. */
+int
+bitset_first (src)
+ bitset src;
+{
+ return bitset_next (src, 0);
+}
+
+
+/* Find last set bit. */
+int
+bitset_last (src)
+ bitset src;
+{
+ return bitset_prev (src, 0);
+}
+
+
+static void
+bitset_print (file, bset, verbose)
+ FILE *file;
+ bitset bset;
+ int verbose;
+{
+ unsigned int i, pos;
+
+ if (verbose)
+ fprintf (file, "n_bits = %d, set = {", bitset_size (bset));
+
+ pos = 30;
+ BITSET_EXECUTE (bset, 0, i,
+ {
+ if (pos > 70)
+ {
+ fprintf (file, "\n");
+ pos = 0;
+ }
+
+ fprintf (file, "%d ", i);
+ pos += 1 + (i >= 10) + (i >= 100);
+ });
+
+ if (verbose)
+ fprintf (file, "}\n");
+}
+
+
+int
+bitset_copy (dst, src)
+ bitset dst;
+ bitset src;
+{
+ unsigned int i;
+
+ if (dst->ops == src->ops)
+ return BITSET__COPY (dst, src);
+
+ /* Convert bitset types. We assume that the DST bitset
+ is large enough to hold the SRC bitset. */
+ bitset_zero (dst);
+ BITSET_EXECUTE (src, 0, i,
+ {
+ bitset_set (dst, i);
+ });
+
+ return 1;
+}
+
+
+/* Return size in bits of bitset SRC. */
+int
+bitset_size (src)
+ bitset src;
+{
+ return BITSET__SIZE (src);
+}
+
+
+/* DST = 0. */
+int
+bitset_zero (dst)
+ bitset dst;
+{
+ return BITSET__OP1 (dst, BITSET_ZERO);
+}
+
+
+/* DST = ~0. */
+int
+bitset_ones (dst)
+ bitset dst;
+{
+ return BITSET__OP1 (dst, BITSET_ONES);
+}
+
+
+/* Return non-zero if all bits in bitset SRC are reset. */
+int
+bitset_empty_p (src)
+ bitset src;
+{
+ return BITSET__OP1 (src, BITSET_EMPTY_P);
+}
+
+
+/* Return DST == DST | SRC. */
+int
+bitset_subset_p (dst, src)
+ bitset dst;
+ bitset src;
+{
+ return BITSET__OP2 (dst, src, BITSET_SUBSET_P);
+}
+
+
+/* Return DST == SRC. */
+int
+bitset_equal_p (dst, src)
+ bitset dst;
+ bitset src;
+{
+ BITSET__CHECK2 (dst, src);
+ return BITSET__OP2 (dst, src, BITSET_EQUAL_P);
+}
+
+
+/* DST = ~SRC. */
+int
+bitset_not (dst, src)
+ bitset dst;
+ bitset src;
+{
+ BITSET__CHECK2 (dst, src);
+ return BITSET__OP2 (dst, src, BITSET_NOT);
+}
+
+
+/* DST = SRC1 | SRC2. Return non-zero if DST != SRC1 | SRC2. */
+int
+bitset_or (dst, src1, src2)
+ bitset dst;
+ bitset src1;
+ bitset src2;
+{
+ BITSET__CHECK3 (dst, src1, src2);
+ return BITSET__OP3 (dst, src1, src2, BITSET_OR);
+}
+
+
+/* DST = SRC1 & SRC2. Return non-zero if DST != SRC1 & SRC2. */
+int
+bitset_and (dst, src1, src2)
+ bitset dst;
+ bitset src1;
+ bitset src2;
+{
+ BITSET__CHECK3 (dst, src1, src2);
+ return BITSET__OP3 (dst, src1, src2, BITSET_AND);
+}
+
+
+/* DST = SRC1 ^ SRC2. Return non-zero if DST != SRC1 ^ SRC2. */
+int
+bitset_xor (dst, src1, src2)
+ bitset dst;
+ bitset src1;
+ bitset src2;
+{
+ BITSET__CHECK3 (dst, src1, src2);
+ return BITSET__OP3 (dst, src1, src2, BITSET_XOR);
+}
+
+
+/* DST = SRC1 & ~SRC2. Return non-zero if DST != SRC1 & ~SRC2. */
+int
+bitset_andn (dst, src1, src2)
+ bitset dst;
+ bitset src1;
+ bitset src2;
+{
+ BITSET__CHECK3 (dst, src1, src2);
+ return BITSET__OP3 (dst, src1, src2, BITSET_ANDN);
+}
+
+
+/* DST = SRC1 | ~SRC2. Return non-zero if DST != SRC1 | ~SRC2. */
+int
+bitset_orn (dst, src1, src2)
+ bitset dst;
+ bitset src1;
+ bitset src2;
+{
+ BITSET__CHECK3 (dst, src1, src2);
+ return BITSET__OP3 (dst, src1, src2, BITSET_ORN);
+}
+
+
+/* DST = (SRC1 | SRC2) & SRC3. Return non-zero if
+ DST != (SRC1 | SRC2) & SRC3. */
+int
+bitset_or_and (dst, src1, src2, src3)
+ bitset dst;
+ bitset src1;
+ bitset src2;
+ bitset src3;
+{
+ BITSET__CHECK4 (dst, src1, src2, src3);
+ return BITSET__OP4 (dst, src1, src2, src3, BITSET_OR_AND);
+}
+
+
+/* DST = (SRC1 & SRC2) | SRC3. Return non-zero if
+ DST != (SRC1 & SRC2) | SRC3. */
+int
+bitset_and_or (dst, src1, src2, src3)
+ bitset dst;
+ bitset src1;
+ bitset src2;
+ bitset src3;
+{
+ BITSET__CHECK4 (dst, src1, src2, src3);
+ return BITSET__OP4 (dst, src1, src2, src3, BITSET_AND_OR);
+}
+
+
+/* Dump bitset BSET to FILE. */
+void
+bitset_dump (file, bset)
+ FILE *file;
+ bitset bset;
+{
+ bitset_print (file, bset, 0);
+}
+
+
+/* Function to be called from debugger to print bitset. */
+void
+debug_bitset (bset)
+ bitset bset;
+{
+ bitset_print (stderr, bset, 1);
+}
+
+
+/* Release memory associated with bitsets. */
+void
+bitset_release_memory ()
+{
+ lbitset_release_memory ();
+ ebitset_release_memory ();
+}
+
+
+#if BITSET_STATS
+int
+bitset_list (bset, list, num, next)
+ bitset bset;
+ bitset_bindex *list;
+ bitset_bindex num;
+ bitset_bindex *next;
+{
+ bitset_bindex count;
+
+ count = BITSET__LIST (bset, list, num, next);
+
+ if (bitset_stats)
+ {
+ bitset_bindex tmp;
+ bitset_bindex size;
+ bitset_bindex i;
+ enum bitset_type type;
+
+ type = bset->ops->type;
+ BITSET_STATS_LISTS_INC (bset);
+
+ /* Log histogram of number of set bits. */
+ for (i = 0, tmp = count; tmp; tmp >>= 1, i++)
+ continue;
+ if (i >= BITSET_LOG_COUNT_BINS)
+ i = BITSET_LOG_COUNT_BINS - 1;
+ BITSET_STATS_LIST_COUNTS_INC (bset, i);
+
+ /* Log histogram of number of bits in set. */
+ size = bitset_size (bset);
+ for (i = 0, tmp = size; tmp; tmp >>= 1, i++)
+ continue;
+ if (i >= BITSET_LOG_SIZE_BINS)
+ i = BITSET_LOG_SIZE_BINS - 1;
+ BITSET_STATS_LIST_SIZES_INC (bset, i);
+
+ /* Histogram of fraction of bits set. */
+ i = size ? (count * BITSET_DENSITY_BINS) / size : 0;
+ if (i >= BITSET_DENSITY_BINS)
+ i = BITSET_DENSITY_BINS - 1;
+ BITSET_STATS_LIST_DENSITY_INC (bset, i);
+ }
+ return count;
+}
+
+
+/* Print a percentage histogram with message MSG to FILE. */
+static void
+bitset_percent_histogram_print (file, name, msg, n_bins, bins)
+ FILE *file;
+ const char *name;
+ const char *msg;
+ unsigned int n_bins;
+ unsigned int *bins;
+{
+ unsigned int i;
+ unsigned int total;
+
+ total = 0;
+ for (i = 0; i < n_bins; i++)
+ total += bins[i];
+
+ if (!total)
+ return;
+
+ fprintf (file, "%s %s", name, msg);
+ for (i = 0; i < n_bins; i++)
+ fprintf (file, "%.0f-%.0f%%\t%8d (%5.1f%%)\n",
+ i * 100.0 / n_bins,
+ (i + 1) * 100.0 / n_bins,
+ bins[i], (100.0 * bins[i]) / total);
+}
+
+
+/* Print a log histogram with message MSG to FILE. */
+static void
+bitset_log_histogram_print (file, name, msg, n_bins, bins)
+ FILE *file;
+ const char *name;
+ const char *msg;
+ unsigned int n_bins;
+ unsigned int *bins;
+{
+ unsigned int i;
+ unsigned int total;
+ unsigned int max_width;
+
+ total = 0;
+ for (i = 0; i < n_bins; i++)
+ total += bins[i];
+
+ if (!total)
+ return;
+
+ /* 2 * ceil (log10(2) * (N - 1)) + 1 */
+ max_width = 2 * (unsigned int)(0.30103 * (n_bins - 1) + 0.9999) + 1;
+
+ fprintf (file, "%s %s", name, msg);
+ for (i = 0; i < 2; i++)
+ fprintf (file, "%*d\t%8d (%5.1f%%)\n",
+ max_width, i, bins[i], 100.0 * bins[i] / total);
+
+ /* Perhaps we should bail out once the histogram goes to zero. */
+ for (; i < n_bins; i++)
+ fprintf (file, "%*d-%d\t%8d (%5.1f%%)\n",
+ max_width - ((unsigned int) (0.30103 * (i) + 0.9999) + 1),
+ 1 << (i - 1), (1 << i) - 1, bins[i], (100.0 * bins[i]) / total);
+}
+
+
+/* Print bitset statistics to FILE. */
+static void
+bitset_stats_print_1 (file, name, stats)
+ FILE *file;
+ const char *name;
+ struct bitset_type_stats_struct *stats;
+{
+ if (!stats)
+ return;
+
+ fprintf (file, "%d %ss xmalloced, %d freed.\n",
+ stats->xmallocs, name, stats->xfrees);
+ fprintf (file, "%d %ss oballoced, %d freed.\n",
+ stats->oballocs, name, stats->obfrees);
+
+ fprintf (file, "%d bitset_lists\n", stats->lists);
+
+ bitset_log_histogram_print (file, name, "count log histogram\n",
+ BITSET_LOG_COUNT_BINS, stats->list_counts);
+
+ bitset_log_histogram_print (file, name, "size log histogram\n",
+ BITSET_LOG_SIZE_BINS, stats->list_sizes);
+
+ bitset_percent_histogram_print (file, name, "density histogram\n",
+ BITSET_DENSITY_BINS, stats->list_density);
+}
+
+
+/* Print all bitset statistics to FILE. */
+static void
+bitset_stats_print (file, verbose)
+ FILE *file;
+ int verbose ATTRIBUTE_UNUSED;
+{
+ int i;
+ static const char *names[] = BITSET__TYPE_NAMES;
+
+ if (!bitset_stats)
+ return;
+
+ fprintf (file, "Bitset statistics:\n\n");
+
+ if (bitset_stats->runs > 1)
+ fprintf (file, "Accumulated runs = %d\n", bitset_stats->runs);
+
+ for (i = 0; i < BITSET_TYPE_NUM; i++)
+ bitset_stats_print_1 (file, names[i], &bitset_stats->types[i]);
+}
+#endif /* BITSET_STATS */
+
+
+/* Initialise bitset statistics logging. */
+void
+bitset_stats_init ()
+{
+#if BITSET_STATS
+ bitset_stats = &bitset_stats_data;
+ bitset_stats_read ();
+#endif /* BITSET_STATS */
+}
+
+
+/* Read bitset statistics file. */
+static void
+bitset_stats_read ()
+{
+ FILE *file;
+
+ if (!bitset_stats)
+ return;
+
+ file = fopen (BITSET_STATS_FILE, "r");
+ if (file)
+ {
+ if (fread (&bitset_stats_data, sizeof (bitset_stats_data),
+ 1, file) != 1)
+ {
+ if (ferror (file))
+ perror ("Could not read stats file");
+ else
+ fprintf (stderr, "Bad stats file size\n");
+ }
+ fclose (file);
+ }
+ bitset_stats_data.runs++;
+}
+
+
+/* Write bitset statistics file. */
+static void
+bitset_stats_write ()
+{
+ FILE *file;
+
+ if (!bitset_stats)
+ return;
+
+ file = fopen (BITSET_STATS_FILE, "w");
+ if (file)
+ {
+ if (fwrite (&bitset_stats_data, sizeof (bitset_stats_data),
+ 1, file) != 1)
+ perror ("Could not write stats file");
+ fclose (file);
+ }
+ else
+ perror ("Could not open stats file for writing");
+}
+
+
+/* Dump bitset statistics to FILE. */
+void
+bitset_stats_dump (file)
+ FILE *file;
+{
+#if BITSET_STATS
+ bitset_stats_print (file, 0);
+ bitset_stats_write ();
+#endif /* BITSET_STATS */
+}
+
+
+/* Function to be called from debugger to print bitset stats. */
+void
+debug_bitset_stats (void)
+{
+#if BITSET_STATS
+ bitset_stats_print (stderr, 1);
+#endif /* BITSET_STATS */
+}