summaryrefslogtreecommitdiff
path: root/lib/lbitset.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/lbitset.c')
-rw-r--r--lib/lbitset.c1321
1 files changed, 1321 insertions, 0 deletions
diff --git a/lib/lbitset.c b/lib/lbitset.c
new file mode 100644
index 00000000..e400df3d
--- /dev/null
+++ b/lib/lbitset.c
@@ -0,0 +1,1321 @@
+/* Functions to support link list 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 "bitset.h"
+#include "obstack.h"
+#include <stdlib.h>
+
+# if WITH_DMALLOC
+# define DMALLOC_FUNC_CHECK
+# include <dmalloc.h>
+# endif /* WITH_DMALLOC */
+
+/* This file implements linked-list bitsets. These bitsets can be of
+ arbitrary length and are more efficient than arrays of bits for
+ large sparse sets.
+
+ Usually if all the bits in an element are zero we remove the element
+ from the list. However, a side effect of the bit caching is that we
+ do not always notice when an element becomes zero. Hence the
+ lbitset_weed function which removes zero elements. */
+
+enum lbitset_find_mode {LBITSET_FIND, LBITSET_CREATE, LBITSET_SUBST};
+
+static lbitset_elt lbitset_zero_elts[3]; /* Elements of all zero bits. */
+
+/* Obstack to allocate bitset elements from. */
+static struct obstack lbitset_obstack;
+static int lbitset_obstack_init = 0;
+static lbitset_elt *lbitset_free_list; /* Free list of bitset elements. */
+
+static lbitset_elt *lbitset_elt_alloc PARAMS ((void));
+static lbitset_elt *lbitset_elt_calloc PARAMS ((void));
+static void lbitset_elt_link PARAMS ((bitset, lbitset_elt *));
+static void lbitset_elt_unlink PARAMS ((bitset, lbitset_elt *));
+static void lbitset_elt_free PARAMS ((lbitset_elt *));
+static lbitset_elt *lbitset_elt_find PARAMS ((bitset, bitset_windex,
+ enum lbitset_find_mode));
+static int lbitset_elt_zero_p PARAMS ((lbitset_elt *));
+
+static void lbitset_prune PARAMS ((bitset, lbitset_elt *));
+static void lbitset_weed PARAMS ((bitset));
+static void lbitset_zero PARAMS((bitset));
+static int lbitset_equal_p PARAMS((bitset, bitset));
+static void lbitset_copy PARAMS((bitset, bitset));
+static int lbitset_copy_compare PARAMS((bitset, bitset));
+static void lbitset_set PARAMS((bitset, bitset_bindex));
+static void lbitset_reset PARAMS((bitset, bitset_bindex));
+static int lbitset_test PARAMS((bitset, bitset_bindex));
+static int lbitset_size PARAMS((bitset));
+static int lbitset_op1 PARAMS((bitset, enum bitset_ops));
+static int lbitset_op2 PARAMS((bitset, bitset, enum bitset_ops));
+static int lbitset_op3 PARAMS((bitset, bitset, bitset, enum bitset_ops));
+static int lbitset_op4 PARAMS((bitset, bitset, bitset, bitset,
+ enum bitset_ops));
+static int lbitset_list PARAMS((bitset, bitset_bindex *, bitset_bindex,
+ bitset_bindex *));
+static int lbitset_reverse_list PARAMS((bitset, bitset_bindex *, bitset_bindex,
+ bitset_bindex *));
+static void lbitset_free PARAMS((bitset));
+
+
+#define LBITSET_CURRENT1(X) (lbitset_elt *)((char *)(X) + ((char *)&(((lbitset_elt *)(X))->next) - (char *)&(((lbitset_elt *)(X))->words)))
+
+#define LBITSET_CURRENT(X) LBITSET_CURRENT1((X)->cdata)
+
+#define LBITSET_HEAD(X) ((X)->u.l.head)
+#define LBITSET_TAIL(X) ((X)->u.l.tail)
+
+/* Allocate a lbitset element. The bits are not cleared. */
+static inline lbitset_elt *
+lbitset_elt_alloc ()
+{
+ lbitset_elt *elt;
+
+ if (lbitset_free_list != 0)
+ {
+ elt = lbitset_free_list;
+ lbitset_free_list = elt->next;
+ }
+ else
+ {
+ /* We can't use gcc_obstack_init to initialize the obstack since
+ print-rtl.c now calls bitset functions, and bitset is linked
+ into the gen* functions. */
+ if (!lbitset_obstack_init)
+ {
+ lbitset_obstack_init = 1;
+
+ /* Let particular systems override the size of a chunk. */
+#ifndef OBSTACK_CHUNK_SIZE
+#define OBSTACK_CHUNK_SIZE 0
+#endif
+ /* Let them override the alloc and free routines too. */
+#ifndef OBSTACK_CHUNK_ALLOC
+#define OBSTACK_CHUNK_ALLOC xmalloc
+#endif
+#ifndef OBSTACK_CHUNK_FREE
+#define OBSTACK_CHUNK_FREE free
+#endif
+
+#if !defined(__GNUC__) || (__GNUC__ < 2)
+#define __alignof__(type) 0
+#endif
+
+ obstack_specify_allocation (&lbitset_obstack, OBSTACK_CHUNK_SIZE,
+ __alignof__ (lbitset_elt),
+ (void *(*) PARAMS ((long))) OBSTACK_CHUNK_ALLOC,
+ (void (*) PARAMS ((void *))) OBSTACK_CHUNK_FREE);
+ }
+
+ /* Perhaps we should add a number of new elements to the free
+ list. */
+ elt = (lbitset_elt *) obstack_alloc (&lbitset_obstack,
+ sizeof (lbitset_elt));
+ }
+
+ return elt;
+}
+
+
+/* Allocate a lbitset element. The bits are not cleared. */
+static inline lbitset_elt *
+lbitset_elt_calloc ()
+{
+ lbitset_elt *elt;
+
+ elt = lbitset_elt_alloc ();
+ memset (elt->words, 0, sizeof (elt->words));
+ return elt;
+}
+
+
+static inline void
+lbitset_elt_free (elt)
+ lbitset_elt *elt;
+{
+ elt->next = lbitset_free_list;
+ lbitset_free_list = elt;
+}
+
+
+/* Unlink element ELT from bitset BSET. */
+static inline void
+lbitset_elt_unlink (bset, elt)
+ bitset bset;
+ lbitset_elt *elt;
+{
+ lbitset_elt *next = elt->next;
+ lbitset_elt *prev = elt->prev;
+
+ if (prev)
+ prev->next = next;
+
+ if (next)
+ next->prev = prev;
+
+ if (LBITSET_HEAD (bset) == elt)
+ LBITSET_HEAD (bset) = next;
+ if (LBITSET_TAIL (bset) == elt)
+ LBITSET_TAIL (bset) = prev;
+
+ /* Update cache pointer. Since the first thing we try is to insert
+ before current, make current the next entry in preference to the
+ previous. */
+ if (LBITSET_CURRENT (bset) == elt)
+ {
+ if (next)
+ {
+ bset->cdata = next->words;
+ bset->cindex = next->index;
+ }
+ else if (prev)
+ {
+ bset->cdata = prev->words;
+ bset->cindex = prev->index;
+ }
+ else
+ {
+ bset->csize = 0;
+ bset->cdata = 0;
+ }
+ }
+
+ lbitset_elt_free (elt);
+}
+
+
+/* Cut the chain of bitset BSET before element ELT and free the
+ elements. */
+static inline void
+lbitset_prune (bset, elt)
+ bitset bset;
+ lbitset_elt *elt;
+{
+ lbitset_elt *next;
+
+ if (!elt)
+ return;
+
+ if (elt->prev)
+ {
+ LBITSET_TAIL (bset) = elt->prev;
+ bset->cdata = elt->prev->words;
+ bset->cindex = elt->prev->index;
+ elt->prev->next = 0;
+ }
+ else
+ {
+ LBITSET_HEAD (bset) = 0;
+ LBITSET_TAIL (bset) = 0;
+ bset->cdata = 0;
+ bset->csize = 0;
+ }
+
+ for (; elt; elt = next)
+ {
+ next = elt->next;
+ lbitset_elt_free (elt);
+ }
+}
+
+
+/* Return nonzero if all bits in an element are zero. */
+static inline int
+lbitset_elt_zero_p (elt)
+ lbitset_elt *elt;
+{
+ int i;
+
+ for (i = 0; i < LBITSET_ELT_WORDS; i++)
+ if (elt->words[i])
+ return 0;
+
+ return 1;
+}
+
+
+/* Link the bitset element into the current bitset linked list. */
+static inline void
+lbitset_elt_link (bset, elt)
+ bitset bset;
+ lbitset_elt *elt;
+{
+ bitset_windex index = elt->index;
+ lbitset_elt *ptr;
+ lbitset_elt *current;
+
+ if (bset->csize)
+ current = LBITSET_CURRENT (bset);
+ else
+ current = LBITSET_HEAD (bset);
+
+ /* If this is the first and only element, add it in. */
+ if (LBITSET_HEAD (bset) == 0)
+ {
+ elt->next = elt->prev = 0;
+ LBITSET_HEAD (bset) = elt;
+ LBITSET_TAIL (bset) = elt;
+ }
+
+ /* If this index is less than that of the current element, it goes
+ somewhere before the current element. */
+ else if (index < bset->cindex)
+ {
+ for (ptr = current;
+ ptr->prev && ptr->prev->index > index;
+ ptr = ptr->prev)
+ continue;
+
+ if (ptr->prev)
+ ptr->prev->next = elt;
+ else
+ LBITSET_HEAD (bset) = elt;
+
+ elt->prev = ptr->prev;
+ elt->next = ptr;
+ ptr->prev = elt;
+ }
+
+ /* Otherwise, it must go somewhere after the current element. */
+ else
+ {
+ for (ptr = current;
+ ptr->next && ptr->next->index < index;
+ ptr = ptr->next)
+ continue;
+
+ if (ptr->next)
+ ptr->next->prev = elt;
+ else
+ LBITSET_TAIL (bset) = elt;
+
+ elt->next = ptr->next;
+ elt->prev = ptr;
+ ptr->next = elt;
+ }
+
+ /* Set up so this is the first element searched. */
+ bset->cindex = index;
+ bset->csize = LBITSET_ELT_WORDS;
+ bset->cdata = elt->words;
+}
+
+
+static lbitset_elt *
+lbitset_elt_find (bset, index, mode)
+ bitset bset;
+ bitset_windex index;
+ enum lbitset_find_mode mode;
+{
+ lbitset_elt *elt;
+ lbitset_elt *current;
+
+ if (bset->csize)
+ {
+ current = LBITSET_CURRENT (bset);
+ /* Check if element is the cached element. */
+ if ((index - bset->cindex) < bset->csize)
+ return current;
+ }
+ else
+ {
+ current = LBITSET_HEAD (bset);
+ }
+
+ if (current)
+ {
+ if (index < bset->cindex)
+ {
+ for (elt = current;
+ elt->prev && elt->index > index;
+ elt = elt->prev)
+ continue;
+ }
+ else
+ {
+ for (elt = current;
+ elt->next && (elt->index + LBITSET_ELT_WORDS - 1) < index;
+ elt = elt->next)
+ continue;
+ }
+
+ /* `element' is the nearest to the one we want. If it's not the one
+ we want, the one we want does not exist. */
+ if (elt && (index - elt->index) < LBITSET_ELT_WORDS)
+ {
+ bset->cindex = elt->index;
+ bset->csize = LBITSET_ELT_WORDS;
+ bset->cdata = elt->words;
+ return elt;
+ }
+ }
+
+ switch (mode)
+ {
+ case LBITSET_FIND:
+ return 0;
+
+ case LBITSET_CREATE:
+ index = (index / (unsigned) LBITSET_ELT_WORDS) * LBITSET_ELT_WORDS;
+
+ elt = lbitset_elt_calloc ();
+ elt->index = index;
+ lbitset_elt_link (bset, elt);
+ return elt;
+
+ case LBITSET_SUBST:
+ return &lbitset_zero_elts[0];
+
+ default:
+ abort ();
+ }
+}
+
+
+/* Weed out the zero elements from the list. */
+static inline void
+lbitset_weed (bset)
+ bitset bset;
+{
+ lbitset_elt *elt;
+ lbitset_elt *next;
+
+ for (elt = LBITSET_HEAD (bset); elt; elt = next)
+ {
+ next = elt->next;
+ if (lbitset_elt_zero_p (elt))
+ lbitset_elt_unlink (bset, elt);
+ }
+}
+
+
+/* Set all bits in the bitset to zero. */
+static inline void
+lbitset_zero (bset)
+ bitset bset;
+{
+ lbitset_elt *head;
+
+ head = LBITSET_HEAD (bset);
+ if (!head)
+ return;
+
+ /* Clear a bitset by freeing the linked list at the head element. */
+ lbitset_prune (bset, head);
+}
+
+
+static inline int
+lbitset_equal_p (dst, src)
+ bitset dst;
+ bitset src;
+{
+ lbitset_elt *selt;
+ lbitset_elt *delt;
+ int j;
+
+ if (src == dst)
+ return 1;
+
+ lbitset_weed (src);
+ lbitset_weed (dst);
+ for (selt = LBITSET_HEAD (src), delt = LBITSET_HEAD (dst);
+ selt && delt; selt = selt->next, delt = delt->next)
+ {
+ if (selt->index != delt->index)
+ return 0;
+
+ for (j = 0; j < LBITSET_ELT_WORDS; j++)
+ if (delt->words[j] != selt->words[j])
+ return 0;
+ }
+ return ! selt && ! delt;
+}
+
+
+/* Copy bits from bitset SRC to bitset DST. */
+static inline void
+lbitset_copy (dst, src)
+ bitset dst;
+ bitset src;
+{
+ lbitset_elt *elt;
+ lbitset_elt *head;
+ lbitset_elt *prev;
+ lbitset_elt *tmp;
+
+ if (src == dst)
+ return;
+
+ lbitset_zero (dst);
+
+ head = LBITSET_HEAD (src);
+ if (!head)
+ return;
+
+ prev = 0;
+ for (elt = head; elt; elt = elt->next)
+ {
+ tmp = lbitset_elt_alloc ();
+ tmp->index = elt->index;
+ tmp->prev = prev;
+ tmp->next = 0;
+ if (prev)
+ prev->next = tmp;
+ else
+ LBITSET_HEAD (dst) = tmp;
+ prev = tmp;
+
+ memcpy (tmp->words, elt->words, sizeof (elt->words));
+ }
+ LBITSET_TAIL (dst) = tmp;
+
+ dst->csize = LBITSET_ELT_WORDS;
+ dst->cdata = LBITSET_HEAD (dst)->words;
+ dst->cindex = LBITSET_HEAD (dst)->index;
+}
+
+
+/* Copy bits from bitset SRC to bitset DST. Return non-zero if
+ bitsets different. */
+static inline int
+lbitset_copy_compare (dst, src)
+ bitset dst;
+ bitset src;
+{
+ if (src == dst)
+ return 0;
+
+ if (! LBITSET_HEAD (dst))
+ {
+ lbitset_copy (dst, src);
+ return LBITSET_HEAD (src) != 0;
+ }
+
+ if (lbitset_equal_p (dst, src))
+ return 0;
+
+ lbitset_copy (dst, src);
+ return 1;
+}
+
+
+/* Return size in bits of bitset SRC. */
+static int
+lbitset_size (src)
+ bitset src;
+{
+ lbitset_elt *elt;
+
+ elt = LBITSET_TAIL (src);
+ if (!elt)
+ return 0;
+
+ /* Return current size of bitset in bits. */
+ return (elt->index + LBITSET_ELT_WORDS) * BITSET_WORD_BITS;
+}
+
+
+/* Set bit BITNO in bitset DST. */
+static void
+lbitset_set (dst, bitno)
+ bitset dst;
+ bitset_bindex bitno;
+{
+ bitset_windex index = bitno / BITSET_WORD_BITS;
+
+ lbitset_elt_find (dst, index, LBITSET_CREATE);
+
+ dst->cdata[index - dst->cindex] |= (1 << (bitno % BITSET_WORD_BITS));
+}
+
+
+/* Reset bit BITNO in bitset DST. */
+static void
+lbitset_reset (dst, bitno)
+ bitset dst;
+ bitset_bindex bitno;
+{
+ bitset_windex index = bitno / BITSET_WORD_BITS;
+
+ if (!lbitset_elt_find (dst, index, LBITSET_FIND))
+ return;
+
+ dst->cdata[index - dst->cindex] &= ~(1 << (bitno % BITSET_WORD_BITS));
+
+ /* If all the data is zero, perhaps we should unlink it now... */
+}
+
+
+/* Test bit BITNO in bitset SRC. */
+static int
+lbitset_test (src, bitno)
+ bitset src;
+ bitset_bindex bitno;
+{
+ bitset_windex index = bitno / BITSET_WORD_BITS;
+
+ if (!lbitset_elt_find (src, index, LBITSET_FIND))
+ return 0;
+
+ return (src->cdata[index - src->cindex] >> (bitno % BITSET_WORD_BITS)) & 1;
+}
+
+
+static void
+lbitset_free (bset)
+ bitset bset;
+{
+ lbitset_zero (bset);
+}
+
+
+/* Find list of up to NUM bits set in BSET starting from and including
+ *NEXT and store in array LIST. Return with actual number of bits
+ found and with *NEXT indicating where search stopped. */
+static int
+lbitset_reverse_list (bset, list, num, next)
+ bitset bset;
+ bitset_bindex *list;
+ bitset_bindex num;
+ bitset_bindex *next;
+{
+ bitset_bindex rbitno;
+ bitset_bindex bitno;
+ unsigned int bitcnt;
+ bitset_bindex bitoff;
+ bitset_windex index;
+ bitset_bindex count;
+ lbitset_elt *elt;
+ bitset_word word;
+ bitset_bindex n_bits;
+
+ elt = LBITSET_TAIL (bset);
+ if (!elt)
+ return 0;
+
+ n_bits = (elt->index + LBITSET_ELT_WORDS) * BITSET_WORD_BITS;
+ rbitno = *next;
+
+ if (rbitno >= n_bits)
+ return 0;
+
+ bitno = n_bits - (rbitno + 1);
+
+ index = bitno / BITSET_WORD_BITS;
+
+ /* Skip back to starting element. */
+ for (; elt && elt->index > index; elt = elt->prev)
+ continue;
+
+ if (!elt)
+ return 0;
+
+ /* If num is 1, we could speed things up with a binary search
+ of the word of interest. */
+
+ count = 0;
+ bitcnt = bitno % BITSET_WORD_BITS;
+ bitoff = index * BITSET_WORD_BITS;
+
+ while (elt)
+ {
+ bitset_word *srcp = elt->words;
+
+ for (; (index - elt->index) < LBITSET_ELT_WORDS;
+ index--, bitoff -= BITSET_WORD_BITS,
+ bitcnt = BITSET_WORD_BITS - 1)
+ {
+ word = srcp[index - elt->index] << (BITSET_WORD_BITS - 1 - bitcnt);
+
+ for (; word; bitcnt--)
+ {
+ if (word & BITSET_MSB)
+ {
+ list[count++] = bitoff + bitcnt;
+ if (count >= num)
+ {
+ *next = n_bits - (bitoff + bitcnt);
+ return count;
+ }
+ }
+ word <<= 1;
+ }
+ }
+
+ elt = elt->prev;
+ if (elt)
+ {
+ index = elt->index + LBITSET_ELT_WORDS - 1;
+ bitoff = index * BITSET_WORD_BITS;
+ }
+ }
+
+ *next = n_bits - (bitoff + 1);
+ return count;
+}
+
+
+/* Find list of up to NUM bits set in BSET starting from and including
+ *NEXT and store in array LIST. Return with actual number of bits
+ found and with *NEXT indicating where search stopped. */
+static int
+lbitset_list (bset, list, num, next)
+ bitset bset;
+ bitset_bindex *list;
+ bitset_bindex num;
+ bitset_bindex *next;
+{
+ bitset_bindex bitno;
+ bitset_windex index;
+ bitset_bindex count;
+ lbitset_elt *elt;
+ lbitset_elt *head;
+ bitset_word word;
+
+ head = LBITSET_HEAD (bset);
+ if (!head)
+ return 0;
+
+ bitno = *next;
+ count = 0;
+
+ if (!bitno)
+ {
+ /* This is the most common case. */
+
+ /* Start with the first element. */
+ elt = head;
+ index = elt->index;
+ bitno = index * BITSET_WORD_BITS;
+ }
+ else
+ {
+ index = bitno / BITSET_WORD_BITS;
+
+ /* Skip to starting element. */
+ for (elt = head;
+ elt && (elt->index + LBITSET_ELT_WORDS - 1) < index;
+ elt = elt->next)
+ continue;
+
+ if (!elt)
+ return 0;
+
+ if (index < elt->index)
+ {
+ index = elt->index;
+ bitno = index * BITSET_WORD_BITS;
+ }
+ else
+ {
+ bitset_word *srcp = elt->words;
+
+ /* We are starting within an element. */
+
+ for (; (index - elt->index) < LBITSET_ELT_WORDS; index++)
+ {
+ word = srcp[index - elt->index] >> (bitno % BITSET_WORD_BITS);
+
+ for (; word; bitno++)
+ {
+ if (word & 1)
+ {
+ list[count++] = bitno;
+ if (count >= num)
+ {
+ *next = bitno + 1;
+ return count;
+ }
+ }
+ word >>= 1;
+ }
+ bitno = (index + 1) * BITSET_WORD_BITS;
+ }
+
+ elt = elt->next;
+ if (elt)
+ {
+ index = elt->index;
+ bitno = index * BITSET_WORD_BITS;
+ }
+ }
+ }
+
+
+ /* If num is 1, we could speed things up with a binary search
+ of the word of interest. */
+
+ while (elt)
+ {
+ int i;
+ bitset_word *srcp = elt->words;
+
+ if ((count + LBITSET_ELT_BITS) < num)
+ {
+ /* The coast is clear, plant boot! */
+
+#if LBITSET_ELT_WORDS == 2
+ word = srcp[0];
+ if (word)
+ {
+ if (! (word & 0xffff))
+ {
+ word >>= 16;
+ bitno += 16;
+ }
+ if (! (word & 0xff))
+ {
+ word >>= 8;
+ bitno += 8;
+ }
+ for (; word; bitno++)
+ {
+ if (word & 1)
+ list[count++] = bitno;
+ word >>= 1;
+ }
+ }
+ index++;
+ bitno = index * BITSET_WORD_BITS;
+
+ word = srcp[1];
+ if (word)
+ {
+ if (! (word & 0xffff))
+ {
+ word >>= 16;
+ bitno += 16;
+ }
+ for (; word; bitno++)
+ {
+ if (word & 1)
+ list[count++] = bitno;
+ word >>= 1;
+ }
+ }
+ index++;
+ bitno = index * BITSET_WORD_BITS;
+#else
+ for (i = 0; i < LBITSET_ELT_WORDS; i++)
+ {
+ word = srcp[i];
+ if (word)
+ {
+ if (! (word & 0xffff))
+ {
+ word >>= 16;
+ bitno += 16;
+ }
+ if (! (word & 0xff))
+ {
+ word >>= 8;
+ bitno += 8;
+ }
+ for (; word; bitno++)
+ {
+ if (word & 1)
+ list[count++] = bitno;
+ word >>= 1;
+ }
+ }
+ index++;
+ bitno = index * BITSET_WORD_BITS;
+ }
+#endif
+ }
+ else
+ {
+ /* Tread more carefully since we need to check
+ if array overflows. */
+
+ for (i = 0; i < LBITSET_ELT_WORDS; i++)
+ {
+ for (word = srcp[i]; word; bitno++)
+ {
+ if (word & 1)
+ {
+ list[count++] = bitno;
+ if (count >= num)
+ {
+ *next = bitno + 1;
+ return count;
+ }
+ }
+ word >>= 1;
+ }
+ index++;
+ bitno = index * BITSET_WORD_BITS;
+ }
+ }
+
+ elt = elt->next;
+ if (elt)
+ {
+ index = elt->index;
+ bitno = index * BITSET_WORD_BITS;
+ }
+ }
+
+ *next = bitno;
+ return count;
+}
+
+
+static int
+lbitset_op1 (dst, op)
+ bitset dst;
+ enum bitset_ops op;
+{
+ unsigned int i;
+ bitset_windex index;
+ lbitset_elt *elt;
+
+ switch (op)
+ {
+ case BITSET_ZERO:
+ lbitset_zero (dst);
+ break;
+
+ case BITSET_ONES:
+ /* This is a decidedly unfriendly operation for a linked list
+ bitset! */
+ elt = LBITSET_TAIL (dst);
+ /* Ignore empty set. */
+ if (!elt)
+ return 0;
+
+ index = elt->index;
+ for (i = 0; i < index; i += LBITSET_ELT_WORDS)
+ {
+ /* Create new elements if they cannot be found. */
+ elt = lbitset_elt_find (dst, i, LBITSET_CREATE);
+ memset (elt->words, ~0, sizeof (elt->words));
+ }
+ break;
+
+ case BITSET_EMPTY_P:
+ lbitset_weed (dst);
+ if (LBITSET_HEAD (dst))
+ return 0;
+ break;
+
+ default:
+ abort ();
+ }
+
+ return 1;
+}
+
+
+static int
+lbitset_op2 (dst, src, op)
+ bitset dst;
+ bitset src;
+ enum bitset_ops op;
+{
+ lbitset_elt *elt;
+ lbitset_elt *selt;
+ lbitset_elt *delt;
+ unsigned int i;
+ unsigned int j;
+ bitset_windex index;
+
+ switch (op)
+ {
+ case BITSET_COPY:
+ lbitset_copy (dst, src);
+ break;
+
+ case BITSET_NOT:
+ /* This is another unfriendly operation for a linked list
+ bitset! */
+ elt = LBITSET_TAIL (dst);
+ /* Ignore empty set. */
+ if (!elt)
+ return 0;
+
+ index = elt->index;
+ for (i = 0; i < index; i += LBITSET_ELT_WORDS)
+ {
+ /* Create new elements for dst if they cannot be found
+ or substitute zero elements if src elements not found. */
+ selt = lbitset_elt_find (dst, i, LBITSET_SUBST);
+ delt = lbitset_elt_find (dst, i, LBITSET_CREATE);
+
+ for (j = 0; j < LBITSET_ELT_WORDS; j++)
+ delt->words[j] = ~selt->words[j];
+ }
+ lbitset_weed (dst);
+ break;
+
+ case BITSET_EQUAL_P:
+ return lbitset_equal_p (dst, src);
+ break;
+
+ case BITSET_SUBSET_P:
+ for (selt = LBITSET_HEAD (src), delt = LBITSET_HEAD (dst);
+ selt || delt; selt = selt->next, delt = delt->next)
+ {
+ if (!selt)
+ selt = &lbitset_zero_elts[0];
+ else if (!delt)
+ delt = &lbitset_zero_elts[0];
+ else if (selt->index != delt->index)
+ {
+ if (selt->index < delt->index)
+ {
+ lbitset_zero_elts[2].next = delt;
+ delt = &lbitset_zero_elts[2];
+ }
+ else
+ {
+ lbitset_zero_elts[1].next = selt;
+ selt = &lbitset_zero_elts[1];
+ }
+ }
+
+ for (j = 0; j < LBITSET_ELT_WORDS; j++)
+ if (delt->words[j] != (selt->words[j] | delt->words[j]))
+ return 0;
+ }
+ break;
+
+ default:
+ abort ();
+ }
+
+ return 1;
+}
+
+
+static int
+lbitset_op3 (dst, src1, src2, op)
+ bitset dst;
+ bitset src1;
+ bitset src2;
+ enum bitset_ops op;
+{
+ lbitset_elt *selt1 = LBITSET_HEAD (src1);
+ lbitset_elt *selt2 = LBITSET_HEAD (src2);
+ lbitset_elt *delt = LBITSET_HEAD (dst);
+ bitset_windex index1;
+ bitset_windex index2;
+ bitset_windex index;
+ lbitset_elt *stmp1;
+ lbitset_elt *stmp2;
+ lbitset_elt *dtmp;
+ bitset_word *srcp1;
+ bitset_word *srcp2;
+ bitset_word *dstp;
+ int changed = 0;
+ unsigned int i;
+
+ /* Fast track common, simple cases. */
+ if (!selt2)
+ {
+ if (op == BITSET_AND)
+ {
+ lbitset_weed (dst);
+ changed = ! LBITSET_HEAD (dst);
+ lbitset_zero (dst);
+ return changed;
+ }
+ else if (op == BITSET_ANDN || op == BITSET_OR || op == BITSET_XOR)
+ {
+ return lbitset_copy_compare (dst, src1);
+ }
+ }
+ else if (!selt1)
+ {
+ if (op == BITSET_AND || op == BITSET_ANDN)
+ {
+ lbitset_weed (dst);
+ changed = ! LBITSET_HEAD (dst);
+ lbitset_zero (dst);
+ return changed;
+ }
+ else if (op == BITSET_OR || op == BITSET_XOR)
+ {
+ return lbitset_copy_compare (dst, src2);
+ }
+ }
+
+
+ LBITSET_HEAD (dst) = 0;
+ dst->csize = 0;
+
+ index1 = (selt1) ? selt1->index : BITSET_INDEX_MAX;
+ index2 = (selt2) ? selt2->index : BITSET_INDEX_MAX;
+
+ while (selt1 || selt2)
+ {
+ /* Figure out whether we need to substitute zero elements for
+ missing links. */
+ if (index1 == index2)
+ {
+ index = index1;
+ stmp1 = selt1;
+ stmp2 = selt2;
+ selt1 = selt1->next;
+ index1 = (selt1) ? selt1->index : BITSET_INDEX_MAX;
+ selt2 = selt2->next;
+ index2 = (selt2) ? selt2->index : BITSET_INDEX_MAX;
+ }
+ else if (index1 < index2)
+ {
+ index = index1;
+ stmp1 = selt1;
+ stmp2 = &lbitset_zero_elts[0];
+ selt1 = selt1->next;
+ index1 = (selt1) ? selt1->index : BITSET_INDEX_MAX;
+ }
+ else
+ {
+ index = index2;
+ stmp1 = &lbitset_zero_elts[0];
+ stmp2 = selt2;
+ selt2 = selt2->next;
+ index2 = (selt2) ? selt2->index : BITSET_INDEX_MAX;
+ }
+
+ /* Find the appropriate element from DST. Begin by discarding
+ elements that we've skipped. */
+ while (delt && delt->index < index)
+ {
+ changed = 1;
+ dtmp = delt;
+ delt = delt->next;
+ lbitset_elt_free (dtmp);
+ }
+ if (delt && delt->index == index)
+ {
+ dtmp = delt;
+ delt = delt->next;
+ }
+ else
+ dtmp = lbitset_elt_calloc ();
+
+ /* Do the operation, and if any bits are set, link it into the
+ linked list. */
+ srcp1 = stmp1->words;
+ srcp2 = stmp2->words;
+ dstp = dtmp->words;
+ switch (op)
+ {
+ case BITSET_OR:
+ for (i = 0; i < LBITSET_ELT_WORDS; i++, dstp++)
+ {
+ bitset_word tmp = *srcp1++ | *srcp2++;
+
+ if (*dstp != tmp)
+ {
+ changed = 1;
+ *dstp = tmp;
+ }
+ }
+ break;
+
+ case BITSET_AND:
+ for (i = 0; i < LBITSET_ELT_WORDS; i++, dstp++)
+ {
+ bitset_word tmp = *srcp1++ & *srcp2++;
+
+ if (*dstp != tmp)
+ {
+ changed = 1;
+ *dstp = tmp;
+ }
+ }
+ break;
+
+ case BITSET_XOR:
+ for (i = 0; i < LBITSET_ELT_WORDS; i++, dstp++)
+ {
+ bitset_word tmp = *srcp1++ ^ *srcp2++;
+
+ if (*dstp != tmp)
+ {
+ changed = 1;
+ *dstp = tmp;
+ }
+ }
+ break;
+
+ case BITSET_ANDN:
+ for (i = 0; i < LBITSET_ELT_WORDS; i++, dstp++)
+ {
+ bitset_word tmp = *srcp1++ & ~(*srcp2++);
+
+ if (*dstp != tmp)
+ {
+ changed = 1;
+ *dstp = tmp;
+ }
+ }
+ break;
+
+ case BITSET_ORN:
+ for (i = 0; i < LBITSET_ELT_WORDS; i++, dstp++)
+ {
+ bitset_word tmp = *srcp1++ | ~(*srcp2++);
+
+ if (*dstp != tmp)
+ {
+ changed = 1;
+ *dstp = tmp;
+ }
+ }
+ break;
+
+ default:
+ abort ();
+ }
+
+ if (! lbitset_elt_zero_p (dtmp))
+ {
+ dtmp->index = index;
+ /* Perhaps this could be optimised... */
+ lbitset_elt_link (dst, dtmp);
+ }
+ else
+ {
+ lbitset_elt_free (dtmp);
+ }
+ }
+
+ /* If we have elements of DST left over, free them all. */
+ if (delt)
+ {
+ changed = 1;
+ lbitset_prune (dst, delt);
+ }
+
+ return changed;
+}
+
+
+static int
+lbitset_op4 (dst, src1, src2, src3, op)
+ bitset dst;
+ bitset src1;
+ bitset src2;
+ bitset src3;
+ enum bitset_ops op;
+{
+ int changed = 0;
+ bitset tmp;
+
+#ifdef ENABLE_CHECKING
+ /* Check for compatiblity. */
+ if (src1->ops != dst->ops || src2->ops != dst->ops || src3->ops != dst->ops)
+ abort ();
+#endif
+
+ tmp = bitset_create (BITSET_LIST, 0);
+
+ switch (op)
+ {
+ case BITSET_OR_AND:
+ bitset_or (tmp, src1, src2);
+ changed = bitset_and (dst, src3, tmp);
+ break;
+
+ case BITSET_AND_OR:
+ bitset_and (tmp, src1, src2);
+ changed = bitset_or (dst, src3, tmp);
+ break;
+
+ case BITSET_ANDN_OR:
+ bitset_andn (tmp, src1, src2);
+ changed = bitset_or (dst, src3, tmp);
+ break;
+
+ default:
+ abort ();
+ }
+
+ bitset_free (tmp);
+ return changed;
+}
+
+
+/* Vector of operations for linked-list bitsets. */
+struct bitset_ops_struct lbitset_ops =
+ {
+ lbitset_set,
+ lbitset_reset,
+ lbitset_test,
+ lbitset_size,
+ lbitset_op1,
+ lbitset_op2,
+ lbitset_op3,
+ lbitset_op4,
+ lbitset_list,
+ lbitset_reverse_list,
+ lbitset_free,
+ BITSET_LIST
+ };
+
+
+/* Return size of initial structure. */
+int
+lbitset_bytes (n_bits)
+ bitset_bindex n_bits ATTRIBUTE_UNUSED;
+{
+ return sizeof (struct bitset_struct);
+}
+
+
+/* Initialize a bitset. */
+
+bitset
+lbitset_init (bset, n_bits)
+ bitset bset;
+ bitset_bindex n_bits ATTRIBUTE_UNUSED;
+{
+ LBITSET_HEAD (bset) = 0;
+ LBITSET_TAIL (bset) = 0;
+
+ bset->ops = &lbitset_ops;
+
+ bset->cindex = 0;
+ /* Disable cache until have some elements allocated.
+ If we have variable length arrays, then we may
+ need to allocate dummy element. */
+ bset->csize = 0;
+ bset->cdata = 0;
+ return bset;
+}
+
+
+void
+lbitset_release_memory ()
+{
+ lbitset_free_list = 0;
+ if (lbitset_obstack_init)
+ {
+ lbitset_obstack_init = 0;
+ obstack_free (&lbitset_obstack, NULL);
+ }
+}