]> git.saurik.com Git - bison.git/blame - lib/sbitset.c
and Akim Demaille <akim@epita.fr>
[bison.git] / lib / sbitset.c
CommitLineData
7086e707
AD
1/* Simple bitsets.
2 Copyright (C) 2002 Free Software Foundation, Inc.
3 Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz).
4
ef017502
AD
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
7086e707 9
ef017502
AD
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
7086e707 14
ef017502
AD
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
345cea78
AD
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18*/
7086e707
AD
19
20#ifdef HAVE_CONFIG_H
21#include "config.h"
22#endif
23
ef017502 24#include "sbitset.h"
7086e707 25#include <stdlib.h>
ef017502 26#include <string.h>
7086e707
AD
27
28/* This file implements fixed size bitsets stored as an array
29 of words. Any unused bits in the last word must be zero. */
30
ef017502
AD
31typedef struct sbitset_struct
32{
33 unsigned int n_bits; /* Number of bits. */
34 bitset_word words[1]; /* The array of bits. */
35}
36*sbitset;
37
38
39struct bitset_struct
40{
41 struct bbitset_struct b;
42 struct sbitset_struct s;
43};
44
45static void sbitset_unused_clear PARAMS ((bitset));
46
47static int sbitset_small_list PARAMS ((bitset, bitset_bindex *, bitset_bindex,
48 bitset_bindex *));
49
50static void sbitset_set PARAMS ((bitset, bitset_bindex));
51static void sbitset_reset PARAMS ((bitset, bitset_bindex));
52static int sbitset_test PARAMS ((bitset, bitset_bindex));
53static int sbitset_size PARAMS ((bitset));
54static int sbitset_op1 PARAMS ((bitset, enum bitset_ops));
55static int sbitset_op2 PARAMS ((bitset, bitset, enum bitset_ops));
56static int sbitset_op3 PARAMS ((bitset, bitset, bitset, enum bitset_ops));
57static int sbitset_op4 PARAMS ((bitset, bitset, bitset, bitset,
58 enum bitset_ops));
59static int sbitset_list PARAMS ((bitset, bitset_bindex *, bitset_bindex,
60 bitset_bindex *));
61static int sbitset_reverse_list
62PARAMS ((bitset, bitset_bindex *, bitset_bindex, bitset_bindex *));
7086e707
AD
63
64#define SBITSET_N_WORDS(N) (((N) + BITSET_WORD_BITS - 1) / BITSET_WORD_BITS)
ef017502
AD
65#define SBITSET_WORDS(X) ((X)->s.words)
66#define SBITSET_N_BITS(X) ((X)->s.n_bits)
7086e707
AD
67
68
69/* Return size in bits of bitset SRC. */
70static int
71sbitset_size (src)
72 bitset src;
73{
ef017502 74 return SBITSET_N_BITS (src);
7086e707
AD
75}
76
77
78/* Find list of up to NUM bits set in BSET starting from and including
ef017502
AD
79 *NEXT and store in array LIST. Return with actual number of bits
80 found and with *NEXT indicating where search stopped. */
7086e707
AD
81static int
82sbitset_small_list (src, list, num, next)
83 bitset src;
84 bitset_bindex *list;
85 bitset_bindex num;
86 bitset_bindex *next;
87{
88 bitset_bindex bitno;
89 bitset_bindex count;
90 bitset_windex size;
91 bitset_word word;
92
93 word = SBITSET_WORDS (src)[0];
94
95 /* Short circuit common case. */
96 if (!word)
97 return 0;
98
99 size = SBITSET_N_BITS (src);
100 bitno = *next;
101 if (bitno >= size)
102 return 0;
103
104 word >>= bitno;
105
106 /* If num is 1, we could speed things up with a binary search
107 of the word of interest. */
108
109 if (num >= BITSET_WORD_BITS)
ef017502 110 {
7086e707 111 for (count = 0; word; bitno++)
ef017502 112 {
7086e707 113 if (word & 1)
ef017502 114 list[count++] = bitno;
7086e707 115 word >>= 1;
ef017502
AD
116 }
117 }
7086e707 118 else
ef017502 119 {
7086e707 120 for (count = 0; word; bitno++)
ef017502 121 {
7086e707 122 if (word & 1)
ef017502 123 {
7086e707
AD
124 list[count++] = bitno;
125 if (count >= num)
ef017502 126 {
7086e707
AD
127 bitno++;
128 break;
ef017502
AD
129 }
130 }
7086e707 131 word >>= 1;
ef017502
AD
132 }
133 }
7086e707
AD
134
135 *next = bitno;
136 return count;
137}
138
139
140/* Set bit BITNO in bitset DST. */
141static void
142sbitset_set (dst, bitno)
143 bitset dst ATTRIBUTE_UNUSED;
144 bitset_bindex bitno ATTRIBUTE_UNUSED;
145{
ef017502
AD
146 /* This should never occur for sbitsets. */
147 abort ();
7086e707
AD
148}
149
150
151/* Reset bit BITNO in bitset DST. */
152static void
153sbitset_reset (dst, bitno)
154 bitset dst ATTRIBUTE_UNUSED;
155 bitset_bindex bitno ATTRIBUTE_UNUSED;
156{
ef017502
AD
157 /* This should never occur for sbitsets. */
158 abort ();
7086e707
AD
159}
160
161
162/* Test bit BITNO in bitset SRC. */
163static int
164sbitset_test (src, bitno)
165 bitset src ATTRIBUTE_UNUSED;
166 bitset_bindex bitno ATTRIBUTE_UNUSED;
167{
ef017502
AD
168 /* This should never occur for sbitsets. */
169 abort ();
170 return 0;
7086e707
AD
171}
172
173
174/* Find list of up to NUM bits set in BSET in reverse order, starting
175 from and including NEXT and store in array LIST. Return with
176 actual number of bits found and with *NEXT indicating where search
177 stopped. */
178static int
179sbitset_reverse_list (src, list, num, next)
180 bitset src;
181 bitset_bindex *list;
182 bitset_bindex num;
183 bitset_bindex *next;
184{
185 bitset_bindex bitno;
186 bitset_bindex rbitno;
187 bitset_bindex count;
345cea78 188 bitset_windex windex;
7086e707
AD
189 unsigned int bitcnt;
190 bitset_bindex bitoff;
191 bitset_word word;
192 bitset_word *srcp = SBITSET_WORDS (src);
193 bitset_bindex n_bits = SBITSET_N_BITS (src);
194
195 rbitno = *next;
196
197 /* If num is 1, we could speed things up with a binary search
198 of the word of interest. */
199
200 if (rbitno >= n_bits)
ef017502 201 return 0;
7086e707
AD
202
203 count = 0;
204
205 bitno = n_bits - (rbitno + 1);
206
345cea78 207 windex = bitno / BITSET_WORD_BITS;
7086e707 208 bitcnt = bitno % BITSET_WORD_BITS;
345cea78 209 bitoff = windex * BITSET_WORD_BITS;
7086e707 210
345cea78 211 for (; windex != ~0U; windex--, bitoff -= BITSET_WORD_BITS,
ef017502 212 bitcnt = BITSET_WORD_BITS - 1)
7086e707 213 {
345cea78 214 word = srcp[windex] << (BITSET_WORD_BITS - 1 - bitcnt);
7086e707
AD
215 for (; word; bitcnt--)
216 {
217 if (word & BITSET_MSB)
218 {
219 list[count++] = bitoff + bitcnt;
220 if (count >= num)
221 {
222 *next = n_bits - (bitoff + bitcnt);
223 return count;
224 }
225 }
226 word <<= 1;
227 }
228 }
229
230 *next = n_bits - (bitoff + 1);
231 return count;
232}
233
234
235/* Find list of up to NUM bits set in BSET starting from and including
ef017502
AD
236 *NEXT and store in array LIST. Return with actual number of bits
237 found and with *NEXT indicating where search stopped. */
7086e707
AD
238static int
239sbitset_list (src, list, num, next)
240 bitset src;
241 bitset_bindex *list;
242 bitset_bindex num;
243 bitset_bindex *next;
244{
245 bitset_bindex bitno;
246 bitset_bindex count;
345cea78 247 bitset_windex windex;
7086e707 248 bitset_bindex bitoff;
ef017502 249 bitset_windex size = src->b.csize;
7086e707
AD
250 bitset_word *srcp = SBITSET_WORDS (src);
251 bitset_word word;
252
253 bitno = *next;
254
255 count = 0;
ef017502 256 if (!bitno)
7086e707
AD
257 {
258 /* Many bitsets are zero, so make this common case fast. */
345cea78 259 for (windex = 0; windex < size && !srcp[windex]; windex++)
7086e707 260 continue;
345cea78 261 if (windex >= size)
7086e707
AD
262 return 0;
263
264 /* If num is 1, we could speed things up with a binary search
265 of the current word. */
266
345cea78 267 bitoff = windex * BITSET_WORD_BITS;
7086e707
AD
268 }
269 else
270 {
271 if (bitno >= SBITSET_N_BITS (src))
272 return 0;
273
345cea78 274 windex = bitno / BITSET_WORD_BITS;
7086e707
AD
275 bitno = bitno % BITSET_WORD_BITS;
276
277 if (bitno)
278 {
279 /* Handle the case where we start within a word.
280 Most often, this is executed with large bitsets
281 with many set bits where we filled the array
282 on the previous call to this function. */
283
345cea78
AD
284 bitoff = windex * BITSET_WORD_BITS;
285 word = srcp[windex] >> bitno;
7086e707
AD
286 for (bitno = bitoff + bitno; word; bitno++)
287 {
288 if (word & 1)
289 {
290 list[count++] = bitno;
291 if (count >= num)
292 {
293 *next = bitno + 1;
294 return count;
295 }
296 }
297 word >>= 1;
298 }
345cea78 299 windex++;
7086e707 300 }
345cea78 301 bitoff = windex * BITSET_WORD_BITS;
7086e707
AD
302 }
303
345cea78 304 for (; windex < size; windex++, bitoff += BITSET_WORD_BITS)
7086e707 305 {
345cea78 306 if (!(word = srcp[windex]))
7086e707
AD
307 continue;
308
309 if ((count + BITSET_WORD_BITS) < num)
ef017502
AD
310 {
311 for (bitno = bitoff; word; bitno++)
312 {
313 if (word & 1)
314 list[count++] = bitno;
315 word >>= 1;
316 }
317 }
7086e707
AD
318 else
319 {
320 for (bitno = bitoff; word; bitno++)
321 {
322 if (word & 1)
323 {
324 list[count++] = bitno;
325 if (count >= num)
326 {
327 *next = bitno + 1;
328 return count;
329 }
330 }
331 word >>= 1;
332 }
333 }
334 }
335
336 *next = bitoff;
337 return count;
338}
339
340
341/* Ensure that any unused bits within the last word are clear. */
342static inline void
343sbitset_unused_clear (dst)
344 bitset dst;
345{
346 unsigned int last_bit;
347
348 last_bit = SBITSET_N_BITS (dst) % BITSET_WORD_BITS;
349 if (last_bit)
ef017502
AD
350 SBITSET_WORDS (dst)[dst->b.csize - 1] &=
351 (bitset_word) ((1 << last_bit) - 1);
7086e707
AD
352}
353
354
355static int
356sbitset_op1 (dst, op)
357 bitset dst;
358 enum bitset_ops op;
359{
360 unsigned int i;
361 bitset_word *dstp = SBITSET_WORDS (dst);
362 unsigned int bytes;
363
ef017502 364 bytes = sizeof (bitset_word) * dst->b.csize;
7086e707
AD
365
366 switch (op)
367 {
ef017502 368 case BITSET_OP_ZERO:
7086e707
AD
369 memset (dstp, 0, bytes);
370 break;
371
ef017502 372 case BITSET_OP_ONES:
7086e707
AD
373 memset (dstp, ~0, bytes);
374 sbitset_unused_clear (dst);
375 break;
376
ef017502
AD
377 case BITSET_OP_EMPTY_P:
378 for (i = 0; i < dst->b.csize; i++)
7086e707
AD
379 if (dstp[i])
380 return 0;
381 break;
382
383 default:
384 abort ();
385 }
386
387 return 1;
388}
389
390
391static int
392sbitset_op2 (dst, src, op)
393 bitset dst;
394 bitset src;
395 enum bitset_ops op;
396{
397 unsigned int i;
398 bitset_word *srcp = SBITSET_WORDS (src);
399 bitset_word *dstp = SBITSET_WORDS (dst);
ef017502 400 bitset_windex size = dst->b.csize;
7086e707
AD
401
402#ifdef ENABLE_CHECKING
403 /* Check for compatiblity. */
ef017502 404 if (SBITSET_N_BITS (src) != SBITSET_N_BITS (dst))
7086e707
AD
405 abort ();
406#endif
407
408 switch (op)
409 {
ef017502 410 case BITSET_OP_COPY:
7086e707
AD
411 if (srcp == dstp)
412 break;
413 memcpy (dstp, srcp, sizeof (bitset_word) * size);
414 break;
415
ef017502 416 case BITSET_OP_NOT:
7086e707
AD
417 for (i = 0; i < size; i++)
418 *dstp++ = ~(*srcp++);
419 sbitset_unused_clear (dst);
420 break;
421
ef017502 422 case BITSET_OP_EQUAL_P:
7086e707 423 for (i = 0; i < size; i++)
ef017502 424 if (*srcp++ != *dstp++)
7086e707
AD
425 return 0;
426 break;
ef017502
AD
427
428 case BITSET_OP_SUBSET_P:
7086e707 429 for (i = 0; i < size; i++, dstp++, srcp++)
ef017502
AD
430 if (*dstp != (*srcp | *dstp))
431 return 0;
7086e707 432 break;
ef017502
AD
433
434 case BITSET_OP_DISJOINT_P:
435 for (i = 0; i < size; i++)
436 if (*srcp++ & *dstp++)
437 return 0;
438 break;
439
7086e707
AD
440 default:
441 abort ();
442 }
443
444 return 1;
445}
446
447
448static int
449sbitset_op3 (dst, src1, src2, op)
450 bitset dst;
451 bitset src1;
452 bitset src2;
453 enum bitset_ops op;
454{
455 unsigned int i;
456 int changed = 0;
457 bitset_word *src1p = SBITSET_WORDS (src1);
458 bitset_word *src2p = SBITSET_WORDS (src2);
459 bitset_word *dstp = SBITSET_WORDS (dst);
ef017502 460 bitset_windex size = dst->b.csize;
7086e707
AD
461
462#ifdef ENABLE_CHECKING
463 /* Check for compatiblity. */
ef017502
AD
464 if (SBITSET_N_BITS (src1) != SBITSET_N_BITS (dst)
465 SBITSET_N_BITS (src2) != SBITSET_N_BITS (dst))
7086e707
AD
466 abort ();
467#endif
468
469 switch (op)
470 {
ef017502 471 case BITSET_OP_OR:
7086e707
AD
472 for (i = 0; i < size; i++, dstp++)
473 {
474 bitset_word tmp = *src1p++ | *src2p++;
475
476 if (*dstp != tmp)
477 {
478 changed = 1;
479 *dstp = tmp;
480 }
481 }
482 break;
483
ef017502 484 case BITSET_OP_AND:
7086e707
AD
485 for (i = 0; i < size; i++, dstp++)
486 {
487 bitset_word tmp = *src1p++ & *src2p++;
488
489 if (*dstp != tmp)
490 {
491 changed = 1;
492 *dstp = tmp;
493 }
494 }
495 break;
496
ef017502 497 case BITSET_OP_XOR:
7086e707
AD
498 for (i = 0; i < size; i++, dstp++)
499 {
500 bitset_word tmp = *src1p++ ^ *src2p++;
501
502 if (*dstp != tmp)
503 {
504 changed = 1;
505 *dstp = tmp;
506 }
507 }
508 break;
509
ef017502 510 case BITSET_OP_ANDN:
7086e707
AD
511 for (i = 0; i < size; i++, dstp++)
512 {
513 bitset_word tmp = *src1p++ & ~(*src2p++);
514
515 if (*dstp != tmp)
516 {
517 changed = 1;
518 *dstp = tmp;
519 }
520 }
521 break;
522
7086e707
AD
523 default:
524 abort ();
525 }
526
527 return changed;
528}
529
530
531static int
532sbitset_op4 (dst, src1, src2, src3, op)
533 bitset dst;
534 bitset src1;
535 bitset src2;
536 bitset src3;
537 enum bitset_ops op;
538{
539 unsigned int i;
540 int changed = 0;
541 bitset_word *src1p = SBITSET_WORDS (src1);
542 bitset_word *src2p = SBITSET_WORDS (src2);
543 bitset_word *src3p = SBITSET_WORDS (src3);
544 bitset_word *dstp = SBITSET_WORDS (dst);
ef017502 545 bitset_windex size = dst->b.csize;
7086e707
AD
546
547#ifdef ENABLE_CHECKING
548 /* Check for compatiblity. */
ef017502
AD
549 if (SBITSET_N_BITS (src1) != SBITSET_N_BITS (dst)
550 || SBITSET_N_BITS (src2) != SBITSET_N_BITS (dst)
551 || SBITSET_N_BITS (src3) != SBITSET_N_BITS (dst))
7086e707
AD
552 abort ();
553#endif
554
555 switch (op)
556 {
ef017502 557 case BITSET_OP_OR_AND:
7086e707
AD
558 for (i = 0; i < size; i++, dstp++)
559 {
560 bitset_word tmp = (*src1p++ | *src2p++) & *src3p++;
561
562 if (*dstp != tmp)
563 {
564 changed = 1;
565 *dstp = tmp;
566 }
567 }
568 break;
569
ef017502 570 case BITSET_OP_AND_OR:
7086e707
AD
571 for (i = 0; i < size; i++, dstp++)
572 {
573 bitset_word tmp = (*src1p++ & *src2p++) | *src3p++;
574
575 if (*dstp != tmp)
576 {
577 changed = 1;
578 *dstp = tmp;
579 }
580 }
581 break;
582
ef017502 583 case BITSET_OP_ANDN_OR:
7086e707
AD
584 for (i = 0; i < size; i++, dstp++)
585 {
586 bitset_word tmp = (*src1p++ & ~(*src2p++)) | *src3p++;
587
588 if (*dstp != tmp)
589 {
590 changed = 1;
591 *dstp = tmp;
592 }
593 }
594 break;
595
596 default:
597 abort ();
598 }
599
600 return changed;
601}
602
603
604/* Vector of operations for single word bitsets. */
ef017502
AD
605struct bitset_ops_struct sbitset_small_ops = {
606 sbitset_set,
607 sbitset_reset,
608 sbitset_test,
609 sbitset_size,
610 sbitset_op1,
611 sbitset_op2,
612 sbitset_op3,
613 sbitset_op4,
614 sbitset_small_list,
615 sbitset_reverse_list,
616 NULL,
617 BITSET_ARRAY
618};
7086e707
AD
619
620
621/* Vector of operations for multiple word bitsets. */
ef017502
AD
622struct bitset_ops_struct sbitset_ops = {
623 sbitset_set,
624 sbitset_reset,
625 sbitset_test,
626 sbitset_size,
627 sbitset_op1,
628 sbitset_op2,
629 sbitset_op3,
630 sbitset_op4,
631 sbitset_list,
632 sbitset_reverse_list,
633 NULL,
634 BITSET_ARRAY
7086e707
AD
635};
636
637
638int
639sbitset_bytes (n_bits)
640 bitset_bindex n_bits;
641{
642 unsigned int bytes, size;
643
644 size = SBITSET_N_WORDS (n_bits);
645 bytes = size * sizeof (bitset_word);
646 return sizeof (struct bitset_struct) + bytes - sizeof (bitset_word);
647}
648
649
650bitset
651sbitset_init (bset, n_bits)
652 bitset bset;
653 bitset_bindex n_bits;
654{
655 bitset_windex size;
656
657 size = SBITSET_N_WORDS (n_bits);
658 SBITSET_N_BITS (bset) = n_bits;
659
660 /* Use optimized routines if bitset fits within a single word.
661 There is probably little merit if using caching since
662 the small bitset will always fit in the cache. */
663 if (size == 1)
ef017502 664 bset->b.ops = &sbitset_small_ops;
7086e707 665 else
ef017502 666 bset->b.ops = &sbitset_ops;
7086e707 667
ef017502
AD
668 bset->b.cindex = 0;
669 bset->b.csize = size;
670 bset->b.cdata = SBITSET_WORDS (bset);
7086e707
AD
671 return bset;
672}