home *** CD-ROM | disk | FTP | other *** search
- /* sets.c
-
- Author: QCAD Systems, Inc., 1990.
-
- Provides set operations.
- A "set" is an array of char made large enough to carry all the
- elements of a power set as bits in the array. The organization of
- the bits can be inferred from the function "set_member" given below.
- We recommend using the define SETSIZE in sets.h when allocating
- a set array.
- A set array can be expanded in size as needed without impacting
- any of these functions -- but note that certain functions need the
- dimension of the array as a parameter. "size" will refer to the
- number of chars in the array, not the number of elements.
-
- */
-
- #include <stdio.h>
- #include "sets.h"
-
- static char mask[]= {0x80, 0x40, 0x20, 0x10, 8, 4, 2, 1};
- static char nmask[]= {0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE};
-
- /* clip_mask n has leftmost n+1 bits set; n= 0..7 */
- static char clip_mask[]= {0, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE};
-
- /* set_count is the number of bits in the number 0..15 */
- static char set_count[]= {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
-
- /* .................... */
- void clearset(set, size)
- char *set;
- int size; /* chars in set */
- { /* 'set' is emptied of elements */
- memset(set, '\0', size);
- }
-
- /* .................... */
- void fillset(set, size)
- char *set;
- int size; /* chars in set */
- { /* 'set' is filled with elements.
- NOTE: should be followed by a 'trimset' call */
- memset(set, (char) 0xFF, size);
- }
-
- /* ................... */
- int set_member(element, set)
- const int element;
- char *set;
- { /* is the 'element' (0..elements-1) in the 'set'? */
- return (set[element >> 3] & mask[element & 7]);
- }
-
- /* ................... */
- int set_size(set, size)
- char *set;
- int size;
- /* how many elements are in the set?
- NOTE: is valid only if the set has been trimmed */
- { int count= 0;
-
- while (size--) {
- count += set_count[(*set >> 4) & 0xF];
- count += set_count[*set & 0xF];
- set++;
- }
- return count;
- }
-
- /* ................... */
- int empty_set(set, size)
- char *set;
- int size;
- { /* is the 'set' empty?
- NOTE: is valid only if the set has been trimmed */
- while (size--)
- if (*(set++)) return 0; /* not empty */
- return 1; /* is empty */
- }
-
- /* ................... */
- void set_union(set1, set2, set3, size)
- char *set1, *set2, *set3;
- int size;
- { /* set1 = set_union(set2, set3) */
- while (size--) *(set1++) = *(set2++) | *(set3++);
- }
-
- /* ................... */
- void set_merge(set1, set2, size)
- char *set1, *set2;
- int size;
- { /* set1 = set_union(set1, set2) */
- while (size--) *(set1++) |= *(set2++);
- }
-
- /* ................... */
- void intersection(set1, set2, set3, size)
- char *set1, *set2, *set3;
- int size;
- { /* set1 = set_intersection(set2, set3) */
- while (size--) *(set1++) = *(set2++) & *(set3++);
- }
-
- /* ................... */
- int is_intersection(set1, set2, size)
- char *set1, *set2;
- int size;
- { /* are there any elements in set_intersection(set1, set2)? */
- while (size--)
- if (*(set1++) & *(set2++)) return 1;
- return 0;
- }
-
- /* ................... */
- int set_equal(set1, set2, size)
- char *set1, *set2;
- int size;
- { /* are the two sets equivalent?
- NOTE: both sets should be trimmed BEFORE calling this */
- while (size--)
- if (*(set1++) != *(set2++)) return 0;
- return 1;
- }
-
- /* ................... */
- void set_include(element, set)
- /* add element to set */
- int element;
- char *set;
- {
- set[element >> 3] |= mask[element & 7];
- }
-
- /* ................... */
- void set_exclude(element, set)
- /* remove element from set */
- int element;
- char *set;
- {
- set[element >> 3] &= nmask[element & 7];
- }
-
- /* ..................... */
- int set_greater(set1, set2, size)
- char *set1, *set2;
- int size;
- { /* is there an element in set1 that isn't in set2? */
- while (size--)
- if (*(set1++) & ~*(set2++)) return 1;
- return 0;
- }
-
- /* .................... */
- void set_difference(set1, set2, set3, size)
- char *set1, *set2, *set3;
- int size;
- { /* set1 will contain all elements in set2 that are NOT in set3 */
- while (size--)
- *(set1++) = *(set2++) & ~*(set3++);
- }
-
- /* .................... */
- void set_inverse(set, size)
- char *set;
- int size;
- { /* 'set' is replaced by its inverse. This call should
- be followed by a TRIMSET call */
- while (size--) {
- *set= ~*set;
- set++;
- }
- }
-
- /* .................... */
- void trimset(set, setbits)
- /* this removes any spurious 'members' in the last byte of the
- set array, in case they happen to get in by some accident.
- For example, 'fillset' will mark the last byte 0xFF, whether
- or not all the bits correspond to set members */
- char *set;
- int setbits; /* number of set members, not number of bytes */
- {
- if (setbits & 7)
- set[setbits >> 3] &= clip_mask[setbits & 7];
- }
-
- /* ................ */
- void set_incl(char *set, ...)
- /* This is designed to accept a set, a count, and a list of any
- number of element numbers to be included in the set.
- see definition in sets.h */
- { int element, count;
- va_list args;
-
- va_start(args, set);
- count= va_arg(args, int);
- while (count--) {
- element= va_arg(args, int);
- set[element >> 3] |= mask[element & 7];
- }
- }
-
- /* ................ */
- void set_excl(char *set, ...)
- /* This is designed to accept a set, a count, and a list of any
- number of element numbers to be excluded from the set.
- see definition in sets.h */
- { int count, element;
- va_list args;
-
- va_start(args, set);
- count= va_arg(args, int);
- while (count--) {
- element= va_arg(args, int);
- set[element >> 3] &= nmask[element & 7];
- }
- }
-
-
- #ifdef TEST
- static int errors= 0;
-
- /* ....... */
- static void complain(testno)
- int testno;
- {
- printf("Test %d failure\n", testno);
- errors++;
- }
-
- /* ....... */
- void main()
- { /* standalone test program for the set utilities */
- char set1[SETSIZE(32)], set2[SETSIZE(32)], set3[SETSIZE(32)];
- int index;
-
- set1[0]= set1[1]= set1[2]= set1[3]= 0x18;
- clearset(set1, 4);
- if (set1[0] != 0 ||
- set1[1] != 0 ||
- set1[2] != 0 ||
- set1[3] != 0) complain(1);
- fillset(set1, 4);
- if (set1[0] != (char)0xFF ||
- set1[1] != (char)0xFF ||
- set1[2] != (char)0xFF ||
- set1[3] != (char)0xFF) complain(2);
- trimset(set1, 32);
- if (set1[3] != (char)255) complain(502);
- trimset(set1, 31);
- if (set1[3] != (char)0xFE) complain(3);
- trimset(set1, 30);
- if (set1[3] != (char)0xFC) complain(4);
- trimset(set1, 29);
- if (set1[3] != (char)0xF8) complain(5);
- trimset(set1, 28);
- if (set1[3] != (char)0xF0) complain(6);
- trimset(set1, 27);
- if (set1[3] != (char)0xE0) complain(7);
- trimset(set1, 26);
- if (set1[3] != (char)0xC0) complain(8);
- trimset(set1, 25);
- if (set1[3] != (char)0x80) complain(9);
-
- set1[0]= (char) 0x14;
- if (set_member(0, set1) ||
- set_member(1, set1) ||
- set_member(2, set1) ||
- !set_member(3, set1) ||
- set_member(4, set1) ||
- !set_member(5, set1) ||
- set_member(6, set1) ||
- set_member(7, set1)) complain(10);
-
- set1[1]= (char) 0x81;
- if (!set_member(8, set1) ||
- set_member(9, set1) ||
- set_member(10, set1) ||
- set_member(11, set1) ||
- set_member(12, set1) ||
- set_member(13, set1) ||
- set_member(14, set1) ||
- !set_member(15, set1)) complain(11);
-
- if (set_size(set1, 2) != 4) complain(12);
-
- for (index= 0; index< 32; index++) {
- clearset(set1, 4);
- set_include(index, set1);
- if (set_size(set1, 4) != 1) complain(100+index);
- fillset(set1, 4);
- set_exclude(index, set1);
- if (set_size(set1, 4) != 31) complain(132+index);
- }
-
- set1[0]= (char) 0x14;
- set1[1]= (char) 0x81;
-
- set1[0]= ~set1[0];
- set1[1]= ~set1[1];
- if (set_size(set1, 2) != 12) complain(13);
-
- if (!set_member(0, set1) ||
- !set_member(1, set1) ||
- !set_member(2, set1) ||
- set_member(3, set1) ||
- !set_member(4, set1) ||
- set_member(5, set1) ||
- !set_member(6, set1) ||
- !set_member(7, set1)) complain(14);
-
- set1[1]= (char) 0x81;
- if (!set_member(8, set1) ||
- set_member(9, set1) ||
- set_member(10, set1) ||
- set_member(11, set1) ||
- set_member(12, set1) ||
- set_member(13, set1) ||
- set_member(14, set1) ||
- !set_member(15, set1)) complain(15);
-
-
- if (empty_set(set1, 2)) complain(16);
-
- clearset(set1, 4);
- if (!empty_set(set1, 4)) complain(17);
-
- set1[0]= (char) 0x77;
- set1[1]= (char) 0x88;
- set2[0]= (char) 0x88;
- set2[1]= (char) 0x77;
- set_union(set3, set1, set2, 2);
- if (set3[0] != (char) 0xFF ||
- set3[1] != (char) 0xFF) complain(18);
-
- intersection(set3, set1, set2, 2);
- if (set3[0] != 0 ||
- set3[1] != 0) complain(19);
-
- if (set_equal(set1, set2, 2)) complain(20);
- set_merge(set1, set2, 2);
- if (set1[0] != (char) 0xFF ||
- set1[1] != (char) 0xFF) complain(21);
-
- set1[0]= (char) 0x77;
- set1[1]= (char) 0x88;
- set2[0]= (char) 0x88;
- set2[1]= (char) 0x77;
- set_merge(set2, set1, 2);
- if (set2[0] != (char) 0xFF ||
- set2[1] != (char) 0xFF) complain(22);
-
- set_merge(set1, set2, 2);
- if (!set_equal(set1, set2, 2)) complain(23);
-
- clearset(set1, 2);
- set_include(2, set1);
- set_include(3, set1);
- set_include(4, set1);
- if (set1[0] != (char) 0x38) complain(24);
-
- set_exclude(2, set1);
- set_exclude(4, set1);
- if (set1[0] != (char) 0x10) complain(25);
-
- clearset(set1, 2);
- set_incl(set1, 3, 2, 3, 4);
- if (set1[0] != (char) 0x38) complain(24);
-
- set_excl(set1, 2, 2, 4);
- if (set1[0] != (char) 0x10) complain(25);
-
- clearset(set1, 2);
- clearset(set2, 2);
- set_incl(set1, 3, 2, 3, 4);
- set_incl(set2, 2, 3, 4);
- if (!set_greater(set1, set2, 2)) complain(26);
- if (set_greater(set2, set1, 2)) complain(27);
-
- set_difference(set3, set1, set2, 2);
- if (set3[0] != (char) 0x20 ||
- set3[1] != 0) complain(28);
-
- set_inverse(set1, 2);
- if (set1[0] != (char) 0xC7 ||
- set1[1] != (char) 0xFF) complain(29);
-
- set_inverse(set1, 2);
- if (set1[0] != (char) 0x38 ||
- set1[1] != 0) complain(30);
-
- clearset(set1, 2);
- clearset(set2, 2);
- set_incl(set1, 3, 2, 3, 4);
- set_incl(set2, 2, 3, 4);
- if (!is_intersection(set1, set2, 2)) complain(31);
- clearset(set2, 2);
- set_incl(set2, 3, 5, 6, 7);
- if (is_intersection(set1, set2, 2)) complain(32);
- set2[0]= !set1[0];
- set2[1]= !set1[1];
- if (is_intersection(set1, set2, 2)) complain(33);
-
- if (errors > 0) printf("%d errors!\n", errors);
- else printf("NO errors\n");
- exit(errors);
- }
-
- #endif
-