]> pd.if.org Git - pccts/blobdiff - support/set/set.c
auto commit for import
[pccts] / support / set / set.c
diff --git a/support/set/set.c b/support/set/set.c
new file mode 100755 (executable)
index 0000000..cc49e87
--- /dev/null
@@ -0,0 +1,792 @@
+/*     set.c
+
+       The following is a general-purpose set library originally developed
+       by Hank Dietz and enhanced by Terence Parr to allow dynamic sets.
+       
+       Sets are now structs containing the #words in the set and
+       a pointer to the actual set words.
+       
+       Generally, sets need not be explicitly allocated.  They are
+       created/extended/shrunk when appropriate (e.g. in set_of()).
+       HOWEVER, sets need to be destroyed (free()ed) when they go out of scope
+       or are otherwise no longer needed.  A routine is provided to
+       free a set.
+       
+       Sets can be explicitly created with set_new(s, max_elem).
+       
+       Sets can be declared to have minimum size to reduce realloc traffic.
+       Default minimum size = 1.
+       
+       Sets can be explicitly initialized to have no elements (set.n == 0)
+       by using the 'empty' initializer:
+       
+       Examples:
+               set a = empty;  -- set_deg(a) == 0
+               
+               return( empty );
+       
+       Example set creation and destruction:
+       
+       set
+       set_of2(e,g)
+       unsigned e,g;
+       {
+               set a,b,c;
+               
+               b = set_of(e);          -- Creates space for b and sticks in e
+               set_new(c, g);          -- set_new(); set_orel() ==> set_of()
+               set_orel(g, &c);
+               a = set_or(b, c);
+               .
+               .
+               .
+               set_free(b);
+               set_free(c);
+               return( a );
+       }
+
+       1987 by Hank Dietz
+       
+       Modified by:
+               Terence Parr
+               Purdue University
+               October 1989
+
+       Made it smell less bad to C++ 7/31/93 -- TJP
+*/
+
+#include <stdio.h>
+#ifdef __cplusplus
+#ifndef __STDC__
+#define __STDC__
+#endif
+#endif
+#ifdef __STDC__
+#include <stdlib.h>
+#else
+#include <malloc.h>
+#endif
+#include <string.h>
+
+#include "set.h"
+
+/* elems can be a maximum of 32 bits */
+static unsigned bitmask[] = {
+       0x00000001, 0x00000002, 0x00000004, 0x00000008,
+       0x00000010, 0x00000020, 0x00000040, 0x00000080,
+       0x00000100, 0x00000200, 0x00000400, 0x00000800,
+       0x00001000, 0x00002000, 0x00004000, 0x00008000,
+#if !defined(PC) || defined(PC32)
+       0x00010000, 0x00020000, 0x00040000, 0x00080000,
+       0x00100000, 0x00200000, 0x00400000, 0x00800000,
+       0x01000000, 0x02000000, 0x04000000, 0x08000000,
+       0x10000000, 0x20000000, 0x40000000, 0x80000000
+#endif
+};
+
+set empty = set_init;
+static unsigned min=1;
+
+#define StrSize                200
+
+#ifdef MEMCHK
+#define CHK(a)                                 \
+       if ( a.setword != NULL )        \
+         if ( !valid(a.setword) )      \
+               {fprintf(stderr, "%s(%d): invalid set\n",__FILE__,__LINE__); exit(-1);}
+#else
+#define CHK(a)
+#endif
+
+/*
+ * Set the minimum size (in words) of a set to reduce realloc calls
+ */
+void
+#ifdef __STDC__
+set_size( unsigned n )
+#else
+set_size( n )
+unsigned n;
+#endif
+{
+       min = n;
+}
+
+unsigned int
+#ifdef __STDC__
+set_deg( set a )
+#else
+set_deg( a )
+set a;
+#endif
+{
+       /* Fast compute degree of a set... the number
+          of elements present in the set.  Assumes
+          that all word bits are used in the set
+          and that SETSIZE(a) is a multiple of WORDSIZE.
+       */
+       register unsigned *p = &(a.setword[0]);
+       register unsigned *endp = &(a.setword[a.n]);
+       register unsigned degree = 0;
+
+       CHK(a);
+       if ( a.n == 0 ) return(0);
+       while ( p < endp )
+       {
+               register unsigned t = *p;
+               register unsigned *b = &(bitmask[0]);
+               do {
+                       if (t & *b) ++degree;
+               } while (++b < &(bitmask[WORDSIZE]));
+               p++;
+       }
+
+       return(degree);
+}
+
+set
+#ifdef __STDC__
+set_or( set b, set c )
+#else
+set_or( b, c )
+set b;
+set c;
+#endif
+{
+       /* Fast set union operation */
+       /* resultant set size is max(b, c); */
+       set *big;
+       set t;
+       unsigned int m,n;
+       register unsigned *r, *p, *q, *endp;
+
+       CHK(b); CHK(c);
+       t = empty;
+       if (b.n > c.n) {big= &b; m=b.n; n=c.n;} else {big= &c; m=c.n; n=b.n;}
+       set_ext(&t, m);
+       r = t.setword;
+
+       /* Or b,c until max of smaller set */
+       q = c.setword;
+       p = b.setword;
+       endp = &(b.setword[n]);
+       while ( p < endp ) *r++ = *p++ | *q++;  
+
+       /* Copy rest of bigger set into result */
+       p = &(big->setword[n]);
+       endp = &(big->setword[m]);
+       while ( p < endp ) *r++ = *p++;
+
+       return(t);
+}
+
+set
+#ifdef __STDC__
+set_and( set b, set c )
+#else
+set_and( b, c )
+set b;
+set c;
+#endif
+{
+       /* Fast set intersection operation */
+       /* resultant set size is min(b, c); */
+       set t;
+       unsigned int n;
+       register unsigned *r, *p, *q, *endp;
+
+       CHK(b); CHK(c);
+       t = empty;
+       n = (b.n > c.n) ? c.n : b.n;
+       if ( n == 0 ) return t;         /* TJP 4-27-92 fixed for empty set */
+       set_ext(&t, n);
+       r = t.setword;
+
+       /* & b,c until max of smaller set */
+       q = c.setword;
+       p = b.setword;
+       endp = &(b.setword[n]);
+       while ( p < endp ) *r++ = *p++ & *q++;  
+
+       return(t);
+}
+
+set
+#ifdef __STDC__
+set_dif( set b, set c )
+#else
+set_dif( b, c )
+set b;
+set c;
+#endif
+{
+       /* Fast set difference operation b - c */
+       /* resultant set size is size(b) */
+       set t;
+       unsigned int n;
+       register unsigned *r, *p, *q, *endp;
+
+       CHK(b); CHK(c);
+       t = empty;
+       n = (b.n <= c.n) ? b.n : c.n ;
+       if ( b.n == 0 ) return t;               /* TJP 4-27-92 fixed for empty set */
+                                                                       /* WEC 12-1-92 fixed for c.n = 0 */
+       set_ext(&t, b.n);
+       r = t.setword;
+
+       /* Dif b,c until smaller set size */
+       q = c.setword;
+       p = b.setword;
+       endp = &(b.setword[n]);
+       while ( p < endp ) *r++ = *p++ & (~ *q++);      
+
+       /* Copy rest of b into result if size(b) > c */
+       if ( b.n > n )
+       {
+               p = &(b.setword[n]);
+               endp = &(b.setword[b.n]);
+               while ( p < endp ) *r++ = *p++;
+       }
+
+       return(t);
+}
+
+set
+#ifdef __STDC__
+set_of( unsigned b )
+#else
+set_of( b )
+unsigned b;
+#endif
+{
+       /* Fast singleton set constructor operation */
+       static set a;
+
+       if ( b == nil ) return( empty );
+       set_new(a, b);
+       a.setword[DIVWORD(b)] = bitmask[MODWORD(b)];
+
+       return(a);
+}
+
+/*
+ * Extend (or shrink) the set passed in to have n words.
+ *
+ * if n is smaller than the minimum, boost n to have the minimum.
+ * if the new set size is the same as the old one, do nothing.
+ *
+ * TJP 4-27-92 Fixed so won't try to alloc 0 bytes
+ */
+void
+#ifdef __STDC__
+set_ext( set *a, unsigned int n )
+#else
+set_ext( a, n )
+set *a;
+unsigned int n;
+#endif
+{
+       register unsigned *p;
+       register unsigned *endp;
+       unsigned int size;
+       
+       CHK((*a));
+    if ( a->n == 0 )
+    {
+               if ( n == 0 ) return;
+        a->setword = (unsigned *) calloc(n, BytesPerWord);
+        if ( a->setword == NULL )
+        {
+            fprintf(stderr, "set_ext(%d words): cannot allocate set\n", n);
+            exit(-1);
+        }
+        a->n = n;
+        return;
+    }
+       if ( n < min ) n = min;
+       if ( a->n == n || n == 0 ) return;
+       size = a->n;
+       a->n = n;
+       a->setword = (unsigned *) realloc( (char *)a->setword, (n*BytesPerWord) );
+       if ( a->setword == NULL )
+       {
+               fprintf(stderr, "set_ext(%d words): cannot allocate set\n", n);
+               exit(-1);
+       }
+
+       p    = &(a->setword[size]);             /* clear from old size to new size */
+       endp = &(a->setword[a->n]);
+       do {
+               *p++ = 0;
+       } while ( p < endp );
+}
+
+set
+#ifdef __STDC__
+set_not( set a )
+#else
+set_not( a )
+set a;
+#endif
+{
+       /* Fast not of set a (assumes all bits used) */
+       /* size of resultant set is size(a) */
+       /* ~empty = empty cause we don't know how bit to make set */
+       set t;
+       register unsigned *r;
+       register unsigned *p = a.setword;
+       register unsigned *endp = &(a.setword[a.n]);
+
+       CHK(a);
+       t = empty;
+       if ( a.n == 0 ) return( empty );
+       set_ext(&t, a.n);
+       r = t.setword;
+       
+       do {
+               *r++ = (~ *p++);
+       } while ( p < endp );
+
+       return(t);
+}
+
+int
+#ifdef __STDC__
+set_equ( set a, set b )
+#else
+set_equ( a, b )
+set a;
+set b;
+#endif
+{
+       /* Fast set equality comparison operation */
+       register unsigned *p = a.setword;
+       register unsigned *q = b.setword;
+       register unsigned *endp = &(a.setword[a.n]);
+
+       CHK(a); CHK(b);
+/*     if ( a.n != b.n ) return(0);*/
+       if ( set_deg(a) != set_deg(b) ) return(0);
+       else if ( a.n==0 ) return(1);   /* empty == empty */
+       
+       do {
+               if (*p != *q) return(0);
+               ++q;
+       } while ( ++p < endp );
+
+       return(1);
+}
+
+int
+#ifdef __STDC__
+set_sub( set a, set b )
+#else
+set_sub( a, b )
+set a;
+set b;
+#endif
+{
+       /* Fast check for a is a proper subset of b (alias a < b) */
+       register unsigned *p = a.setword;
+       register unsigned *q = b.setword;
+       register unsigned *endp = &(a.setword[a.n]);
+       register int asubset = 0;
+
+       CHK(a); CHK(b);
+       if ( set_deg(a) > set_deg(b) ) return(0);
+       if ( set_deg(a)==0 && set_deg(b)==0) return(1);/* empty prop sub of empty */
+       if ( set_deg(a) == 0 ) return(1);               /* empty is sub of everything */
+#ifdef DUH
+/* Was: */
+       if ( a.n > b.n ) return(0);
+       if (a.n==0 && b.n==0) return(1);/* empty prop sub of empty */
+       if ( a.n == 0 ) return(1);              /* empty is sub of everything */
+#endif
+
+       do {
+               /* Prune tests based on guess that most set words
+                  will match, particularly if a is a subset of b.
+               */
+               if (*p != *q) {
+                       if (*p & ~(*q)) {
+                               /* Fail -- a contains something b does not */
+                               return(0);
+                       }
+                       /* At least this word was a proper subset, hence
+                          even if all other words are equal, a is a
+                          proper subset of b.
+                       */
+                       asubset = 1;
+               }
+               ++q;
+       } while (++p < endp);
+
+       /* at this point, a,b are equ or a subset */
+       if ( asubset || b.n == a.n ) return(asubset);
+       
+       /* if !asubset, size(b) > size(a), then a=b and must check rest of b */
+       p = q;
+       endp = &(b.setword[b.n]);
+       do
+       {
+               if ( *p++ ) return(1);
+       } while ( p < endp );
+
+       return(0);
+}
+
+unsigned
+#ifdef __STDC__
+set_int( set b )
+#else
+set_int( b )
+set b;
+#endif
+{
+       /* Fast pick any element of the set b */
+       register unsigned *p = b.setword;
+       register unsigned *endp = &(b.setword[b.n]);
+
+       CHK(b);
+       if ( b.n == 0 ) return( nil );
+
+       do {
+               if (*p) {
+                       /* Found a non-empty word of the set */
+                       register unsigned i = ((p - b.setword) << LogWordSize);
+                       register unsigned t = *p;
+                       p = &(bitmask[0]);
+                       while (!(*p & t)) {
+                               ++i; ++p;
+                       }
+                       return(i);
+               }
+       } while (++p < endp);
+
+       /* Empty -- only element it contains is nil */
+       return(nil);
+}
+
+int
+#ifdef __STDC__
+set_el( unsigned b, set a )
+#else
+set_el( b, a )
+unsigned b;
+set a;
+#endif
+{
+       CHK(a);
+       /* nil is an element of every set */
+       if (b == nil) return(1);
+       if ( a.n == 0 || NumWords(b) > a.n ) return(0);
+       
+       /* Otherwise, we have to check */
+       return( a.setword[DIVWORD(b)] & bitmask[MODWORD(b)] );
+}
+
+int
+#ifdef __STDC__
+set_nil( set a )
+#else
+set_nil( a )
+set a;
+#endif
+{
+       /* Fast check for nil set */
+       register unsigned *p = a.setword;
+       register unsigned *endp = &(a.setword[a.n]);
+
+       CHK(a);
+       if ( a.n == 0 ) return(1);
+       /* The set is not empty if any word used to store
+          the set is non-zero.  This means one must be a
+          bit careful about doing things like negation.
+       */
+       do {
+               if (*p) return(0);
+       } while (++p < endp);
+       
+       return(1);
+}
+
+char *
+#ifdef __STDC__
+set_str( set a )
+#else
+set_str( a )
+set a;
+#endif
+{
+       /* Fast convert set a into ASCII char string...
+          assumes that all word bits are used in the set
+          and that SETSIZE is a multiple of WORDSIZE.
+          Trailing 0 bits are removed from the string.
+          if no bits are on or set is empty, "" is returned.
+       */
+       register unsigned *p = a.setword;
+       register unsigned *endp = &(a.setword[a.n]);
+       static char str_tmp[StrSize+1];
+       register char *q = &(str_tmp[0]);
+
+       CHK(a);
+       if ( a.n==0 ) {*q=0; return( &(str_tmp[0]) );}
+       do {
+               register unsigned t = *p;
+               register unsigned *b = &(bitmask[0]);
+               do {
+                       *(q++) = (char) ((t & *b) ? '1' : '0');
+               } while (++b < &(bitmask[WORDSIZE]));
+       } while (++p < endp);
+
+       /* Trim trailing 0s & NULL terminate the string */
+       while ((q > &(str_tmp[0])) && (*(q-1) != '1')) --q;
+       *q = 0;
+
+       return(&(str_tmp[0]));
+}
+
+set
+#ifdef __STDC__
+set_val( register char *s )
+#else
+set_val( s )
+register char *s;
+#endif
+{
+       /* Fast convert set ASCII char string into a set.
+          If the string ends early, the remaining set bits
+          are all made zero.
+          The resulting set size is just big enough to hold all elements.
+       */
+       static set a;
+       register unsigned *p, *endp;
+
+       set_new(a, strlen(s));
+       p = a.setword;
+       endp = &(a.setword[a.n]);
+       do {
+               register unsigned *b = &(bitmask[0]);
+               /* Start with a word with no bits on */
+               *p = 0;
+               do {
+                       if (*s) {
+                               if (*s == '1') {
+                                       /* Turn-on this bit */
+                                       *p |= *b;
+                               }
+                               ++s;
+                       }
+               } while (++b < &(bitmask[WORDSIZE]));
+       } while (++p < endp);
+
+       return(a);
+}
+
+/*
+ * Or element e into set a.  a can be empty.
+ */
+void
+#ifdef __STDC__
+set_orel( unsigned e, set *a )
+#else
+set_orel( e, a )
+unsigned e;
+set *a;
+#endif
+{
+       CHK((*a));
+       if ( e == nil ) return;
+       if ( NumWords(e) > a->n ) set_ext(a, NumWords(e));
+       a->setword[DIVWORD(e)] |= bitmask[MODWORD(e)];
+}
+
+/*
+ * Or set b into set a.  a can be empty. does nothing if b empty.
+ */
+void
+#ifdef __STDC__
+set_orin( set *a, set b )
+#else
+set_orin( a, b )
+set *a;
+set b;
+#endif
+{
+       /* Fast set union operation */
+       /* size(a) is max(a, b); */
+       unsigned int m;
+       register unsigned *p,
+                                         *q    = b.setword,
+                                         *endq = &(b.setword[b.n]);
+
+       CHK((*a)); CHK(b);
+       if ( b.n == 0 ) return;
+       m = (a->n > b.n) ? a->n : b.n;
+       set_ext(a, m);
+       p = a->setword;
+       do {
+               *p++ |= *q++;
+       } while ( q < endq );
+}
+
+void
+#ifdef __STDC__
+set_rm( unsigned e, set a )
+#else
+set_rm( e, a )
+unsigned e;
+set a;
+#endif
+{
+       /* Does not effect size of set */
+       CHK(a);
+       if ( (e == nil) || (NumWords(e) > a.n) ) return;
+       a.setword[DIVWORD(e)] ^= (a.setword[DIVWORD(e)]&bitmask[MODWORD(e)]);
+}
+
+void
+#ifdef __STDC__
+set_clr( set a )
+#else
+set_clr( a )
+set a;
+#endif
+{
+       /* Does not effect size of set */
+       register unsigned *p = a.setword;
+       register unsigned *endp = &(a.setword[a.n]);
+       
+       CHK(a);
+       if ( a.n == 0 ) return;
+       do {
+               *p++ = 0;
+       } while ( p < endp );
+}
+
+set
+#ifdef __STDC__
+set_dup( set a )
+#else
+set_dup( a )
+set a;
+#endif
+{
+       set b;
+       register unsigned *p,
+                                         *q    = a.setword,
+                                         *endq = &(a.setword[a.n]);
+       
+       CHK(a);
+       b = empty;
+       if ( a.n == 0 ) return( empty );
+       set_ext(&b, a.n);
+       p = b.setword;
+       do {
+               *p++ = *q++;
+       } while ( q < endq );
+       
+       return(b);
+}
+
+/*
+ * Return a nil terminated list of unsigned ints that represents all
+ * "on" bits in the bit set.
+ *
+ * e.g. {011011} --> {1, 2, 4, 5, nil}
+ *
+ * _set_pdq and set_pdq are useful when an operation is required on each element
+ * of a set.  Normally, the sequence is:
+ *
+ *             while ( set_deg(a) > 0 ) {
+ *                     e = set_int(a);
+ *                     set_rm(e, a);
+ *                     ...process e...
+ *             }
+ * Now,
+ *
+ *             t = e = set_pdq(a);
+ *             while ( *e != nil ) {
+ *                     ...process *e...
+ *                     e++;
+ *             }
+ *             free( t );
+ *
+ * We have saved many set calls and have not destroyed set a.
+ */
+void
+#ifdef __STDC__
+_set_pdq( set a, register unsigned *q )
+#else
+_set_pdq( a, q )
+set a;
+register unsigned *q;
+#endif
+{
+       register unsigned *p = a.setword,
+                                         *endp = &(a.setword[a.n]);
+       register unsigned e=0;
+
+       CHK(a);
+       /* are there any space (possibility of elements)? */
+       if ( a.n == 0 ) return;
+       do {
+               register unsigned t = *p;
+               register unsigned *b = &(bitmask[0]);
+               do {
+                       if ( t & *b ) *q++ = e;
+                       ++e;
+               } while (++b < &(bitmask[WORDSIZE]));
+       } while (++p < endp);
+       *q = nil;
+}
+
+/*
+ * Same as _set_pdq except allocate memory.  set_pdq is the natural function
+ * to use.
+ */
+unsigned *
+#ifdef __STDC__
+set_pdq( set a )
+#else
+set_pdq( a )
+set a;
+#endif
+{
+       unsigned *q;
+       int max_deg;
+       
+       CHK(a);
+       max_deg = WORDSIZE*a.n;
+       /* assume a.n!=0 & no elements is rare, but still ok */
+       if ( a.n == 0 ) return(NULL);
+       q = (unsigned *) malloc((max_deg+1)*BytesPerWord);
+       if ( q == NULL ) return( NULL );
+       _set_pdq(a, q);
+       return( q );
+}
+
+/* a function that produces a hash number for the set
+ */
+unsigned int
+#ifdef __STDC__
+set_hash( set a, register unsigned int mod )
+#else
+set_hash( a, mod )
+set a;
+register unsigned int mod;
+#endif
+{
+       /* Fast hash of set a (assumes all bits used) */
+       register unsigned *p = &(a.setword[0]);
+       register unsigned *endp = &(a.setword[a.n]);
+       register unsigned i = 0;
+
+       CHK(a);
+       while (p<endp){
+               i += (*p);
+               ++p;
+       }
+
+       return(i % mod);
+}