Click here to Skip to main content
15,893,722 members
Articles / Desktop Programming / MFC

Another Enum Viewer

Rate me:
Please Sign up or sign in to vote.
4.50/5 (2 votes)
22 Oct 20015 min read 83K   1.3K   19  
An article on the usage and design of another Enum Viewer
/*	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);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions