home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1986
/
11
/
holub.nov
next >
Wrap
Text File
|
1986-12-01
|
14KB
|
394 lines
Listing 1 -- set.h
------------------------------------------------------------------------------
1 /* SET.H: Header to use the set manipulation routiness in set.c
2 *
3 * Copyright (c) 1986, Allen I. Holub. All rights reserved
4 */
5
6 #define DEFBYTES 2 /* bytes in def set (>= 1) */
7 #define DEFBITS (DEFBYTES * 8) /* bits in default set */
8
9 typedef struct
10 {
11 unsigned nbytes : 13; /* Number of bytes in map */
12 unsigned compl : 1; /* This is a negative true set */
13 int nbits; /* Number of bits in map */
14 unsigned char *map; /* Pointer to the map */
15 unsigned char defmap[DEFBYTES]; /* The map itself */
16 }
17 SET;
18
19 extern void set_op ( int, SET*, SET*, SET*); /* Routines in set.c */
20 extern int set_cmp ( SET*, SET* );
21 extern int subset ( SET*, SET* );
22 extern int num_ele ( SET* );
23 extern void delset ( SET* );
24 extern SET *newset ( );
25
26 #define UNION 0 /* x is in s1 or s2 */
27 #define INTERSECT 1 /* x is in s1 and s2 */
28 #define DIFFERENCE 2 /* x is in s1 but !s2 or in s2 but !s1 */
29 #define INVERT 3 /* ones complement */
30 #define ASSIGN 4 /* s1 = s2 */
31 #define CLEAR 5 /* d = all bits cleared */
32 #define FILL 6 /* d = all bits set */
33
34 #define union(d,s1,s2) set_op( UNION, d, s1, s2 )
35 #define intersection(d,s1,s2) set_op( INTERSECT, d, s1, s2 )
36 #define difference(d,s1,s2) set_op( DIFFERENCE, d, s1, s2 )
37 #define assign(d,s1) set_op( ASSIGN, d, s1, NULL )
38 #define invert(d,s1) set_op( INVERT, d, s1, NULL )
39 #define clear(d) set_op( CLEAR, d, NULL, NULL )
40 #define fill(d) set_op( FILL, d, NULL, NULL )
41 #define complement(d) ( (d)->compl = ~(d)->compl)
42
43 #define equivalent(s1,s2) ( set_cmp(s1,s2) == 0 )
44 #define disjoint(s1,s2) ( set_cmp(s1,s2) == 1 )
45
46 #define GBIT(x,s,op) ( ((s)->map)[(x) >> 3] op (1 << ((x) & 0x07)) )
47
48 #define remove(x,s) ( ((x) >= (s)->nbits) ? 0 : GBIT(x,s,&= ~) )
49 #define add(x,s) ( ((x) >= (s)->nbits) ? addset(x,s) : GBIT(x,s,|= ) )
50 #define ismember(x,s) ( ((x) >= (s)->nbits) ? 0 : GBIT(x,s,& ) )
51
52 #define test(x,s) ( ( ismember(x,s) ) ? !( (s)->compl ) : (s)->compl )
Listing 2 -- set.c
------------------------------------------------------------------------------
1 #include <stdio.h>
2 #include <ctype.h>
3 #include <set.h>
4
5 extern char *calloc ( int, int );
6
7 /*----------------------------------------------------------------------*/
8
9 #ifdef DIAG
10 # define D(x) x
11 #else
12 # define D(x)
13 #endif
14
15 #define max(a,b) ((a) > (b) ? (a) : (b))
16
17 /*----------------------------------------------------------------------*/
18
19 SET *newset()
20 {
21 SET *p;
22
23 if( !(p=(SET *) calloc(sizeof(SET),1)) )
24 {
25 fprintf(stderr,"Can't get memory for set\n");
26 return NULL;
27 }
28 else
29 {
30 p->map = p->defmap;
31 p->nbytes = DEFBYTES;
32 p->nbits = DEFBITS;
33 }
34 return p;
35 }
36
37 /*----------------------------------------------------------------------*/
38
39 void delset( set )
40 SET *set;
41 {
42 /* Delete a set created with a previous newset
43 */
44
45 if( set->map != set->defmap )
46 free( set->map );
47
48 free( set );
49 }
50
51 /*----------------------------------------------------------------------*/
52
53 static void enlarge( need, set )
54 SET *set;
55 {
56 /* Enlarge the set to "need" bytes, filling in the extra
57 * bytes with zeros.
58 */
59
60 register char *new;
61
62 if( !set || need <= set->nbytes )
63 return;
64
65 D( printf("enlarging %d byte map to %d bytes\n", set->nbytes,need);)
66
67 if( !(new = calloc(need, 1)) )
68 fprintf(stderr,"Can't get memory to expand set\n");
69 else
70 {
71 memcpy( new, set->map, set->nbytes );
72
73 if( set->map != set->defmap )
74 free( set->map );
75
76 set->map = new;
77 set->nbytes = need;
78 set->nbits = need * 8;
79 }
80 }
81
82 /* ------------------------------------------------------------------- */
83
84 int addset( bit, set )
85 SET *set;
86 {
87 /* Addset is called by the add() macro when the set isn't
88 * big enough. It expands the set to the necessary size
89 * and sets the indicated bit.
90 */
91
92 enlarge( (bit >> 3) + 1, set );
93 GBIT ( bit, set, |= );
94 }
95
96 /* ------------------------------------------------------------------- */
97
98 int num_ele( set )
99 SET *set;
100 {
101 /* Return the number of elements (set bits) in the set.
102 * This routine depends on zero fill when an
103 * unsigned quantity is shifted to the right.
104 */
105
106 register unsigned j;
107 register unsigned count = 0;
108 unsigned char *p;
109 int i;
110
111 p = set->map;
112 for( i = set->nbytes; --i >= 0 ; p++)
113 for( j = *p; j ; j >>= 1 )
114 count += j & 0x1;
115
116 return count;
117 }
118
119 /* ------------------------------------------------------------------- */
120
121 set_cmp( set1, set2 )
122 SET *set1, *set2;
123 {
124 /* Compares two sets. Returns zero if they're equivalent, one if
125 * they're disjoint, 2 if they intersect but aren't equivalent,
126 * -1 is returned if the two sets are different sizes.
127 */
128
129 register char *p1, *p2;
130 register int i, disj = 0 ;
131
132 i = max( set1->nbytes, set2->nbytes);
133
134 enlarge( i, set1 ); /* Make the sets the same size */
135 enlarge( i, set2 );
136
137 p1 = set1->map;
138 p2 = set2->map;
139
140 for(; --i >= 0; p1++, p2++ )
141 {
142 if( *p1 != *p2 )
143 {
144 if( *p1 ^ ~*p2 )
145 return 2;
146 else
147 disj = 1;
148 }
149 }
150
151 return disj; /* They're equivalent */
152 }
153
154 /* ------------------------------------------------------------------- */
155
156 int subset( a, b )
157 SET *a, *b;
158 {
159 /* Return 1 if A is a subset of B. Set A must be either smaller
160 * than or the same size as B. 0 is returned if A is not a
161 * subset or if A is larger than B.
162 */
163
164 register int i;
165 register char *ap, *bp;
166
167 if( (i = a->nbytes) > b->nbytes )
168 return 0;
169
170 ap = a->map;
171 bp = b->map;
172
173 for(; --i >= 0; ap++, bp++ )
174 if( (*ap & *bp) != *ap )
175 return 0;
176 return 1;
177 }
178
179 /* ------------------------------------------------------------------- */
180
181 void set_op( op, dest, set1, set2 )
182 int op;
183 SET *set1, *set2, *dest;
184 {
185 /* Performs either the union or intersection of two sets
186 * (depending on the value of "union"). Dest is the result.
187 * The two source sets (set1 and set2) must be different,
188 * however either of the sources may be used as a destination
189 * if you like. If the sets are different sizes, the smaller
190 * set is made larger. Unused arguments should be set to NULL.
191 */
192
193 register char *d; /* Pointer to destiniation map */
194 register char *m1; /* Pointer to map in set1 */
195 register char *m2; /* Pointer to map in set2 */
196 register int i; /* Number of bytes in map */
197
198
199 i = dest->nbytes;
200 if( set1 )
201 i = max( i, set1->nbytes );
202 if( set2 )
203 i = max( i, set2->nbytes );
204
205 enlarge( i, set1 ); /* Make all three sets the same size */
206 enlarge( i, set2 ); /* if necessary. Enlarge() does nothing */
207 enlarge( i, dest ); /* if they're already the correct size. */
208
209 d = dest->map;
210 m1 = set1->map;
211 m2 = set2->map;
212
213 while( --i >= 0 )
214 {
215 D( printf("set_op: working on bit %d\n", i ); )
216
217 switch( op )
218 {
219 case UNION: *d++ = *m1++ | *m2++ ; break;
220 case INTERSECT: *d++ = *m1++ & *m2++ ; break;
221 case DIFFERENCE: *d++ = *m1++ ^ *m2++ ; break;
222 case ASSIGN: *d++ = *m1++ ; break;
223 case INVERT: *d++ = ~*m1++ ; break;
224 case CLEAR: *d++ = 0 ; break;
225 case FILL: *d++ = ~0 ; break;
226 }
227 }
228 }
229
230 /* ------------------------------------------------------------------- */
231 #ifdef DEBUG
232
233 pset( str, set )
234 char *str;
235 SET *set;
236 {
237 int i;
238
239 printf("+------------------------------------------------------\n");
240 printf("| %s\n", str );
241 printf("| Set at 0x%04x: %d bits, %d bytes, map (0x%04x) ",
242 set, set->nbits, set->nbytes, set->map);
243
244 printf("%s TRUE\n", set->compl ? "NEGATIVE" : "POSITIVE" );
245 printf("| map = ");
246
247 for( i = 0; i < set->nbytes; i++ )
248 printf("0x%02x,", (set->map)[i] );
249
250 printf("\n| bits= ");
251
252 for( i = 0; i < set->nbits; i++ )
253 printf( test(i, set) ? "%d," : "" , i );
254
255 printf("\n| %d elements\n", num_ele(set) );
256
257 printf("+------------------------------------------------------\n");
258 }
259
260 /* ------------------------------------------------------------------- */
261
262 test_stuff( a, b, d )
263 SET *a, *b, *d;
264 {
265 pset("set a", a );
266 pset("set b", b );
267
268 union (d,a,b); pset("a union b", d );
269 intersection (d,a,b); pset("a intersect b", d );
270 difference (d,a,b); pset("a difference b", d );
271 assign (d,a); pset("d assign a", d );
272 complement (d); pset("complement a", d );
273 complement (d);
274 invert (d,a); pset("invert a", d );
275
276 printf("a %s equivalent to b\n", equivalent(a,b) ? "IS" : "ISN'T" );
277 printf("a %s disjoint from b\n", disjoint(a,b) ? "IS" : "ISN'T" );
278 printf("b %s a subset of a\n", subset(b, a) ? "IS" : "ISN'T" );
279 printf("a %s a subset of b\n", subset(a, b) ? "IS" : "ISN'T" );
280
281 printf("-------------------------------------------------------\n");
282 }
283
284 /* ------------------------------------------------------------------- */
285
286 main()
287 {
288 SET *a, *b, *d;
289 char buf[80], *p;
290 int num;
291
292 a = newset(); pset( "initial a", a );
293 b = newset(); pset( "initial b", b );
294 d = newset(); pset( "initial d", d );
295
296 add(0,a);
297 add(1,a);
298 add(3,a);
299 add(0,b);
300 add(3,b);
301
302 test_stuff( a, b, d );
303
304 remove(0,a); remove(1,a); remove(3,a); remove(0,b); remove(3,b);
305 add(0, a); add(2, a); add(2, b); add(3, b);
306
307 test_stuff( a, b, d );
308
309 clear( a ); clear( b ); test_stuff( a, b, d );
310 clear( a ); fill ( b ); test_stuff( a, b, d );
311
312 delset( b );
313 delset( d );
314 delset( a );
315 a = newset();
316
317 printf("enter <bitnum><s|c>:");
318
319 while( gets(buf) )
320 {
321 num = atoi(buf);
322 for( p = buf; isdigit(*p) ; p++ )
323 ;
324
325 if( *p == 's' )
326 add(num ,a);
327 else
328 remove(num, a);
329
330 pset( "", a );
331 printf("enter <bitnum><s|c>:");
332 }
333 }
334
335 #endif
[EOF]