the hito embeddable programming language
1#include "bitset.h"
2#include <stdlib.h>
3#include <string.h>
4#include <stdio.h>
5#include "util.h"
6struct bitset {
7 size_t nwords; /* allocated */
8 uint64_t *words; /* array of 64-bit chunks */
9};
10
11#define BITWORD(i) ((i) >> 6) /* divide by 64 */
12#define BITMASK(i) (1ULL << ((i) & 63))
13
14bitset_t *bitset_alloc(void) {
15 bitset_t *bs = calloc(1, sizeof(bitset_t));
16 if (bs == NULL) {
17 die("Out of memory: cannot allocate bitset");
18 }
19 return bs;
20}
21
22void bitset_free(bitset_t *bs) {
23 if (!bs) return;
24 free(bs->words);
25 free(bs);
26}
27
28void bitset_reserve(bitset_t *bs, size_t maxbit) {
29 size_t need_words = BITWORD(maxbit) + 1;
30 if (need_words <= bs->nwords)
31 return;
32
33 size_t new_words = bs->nwords ? bs->nwords : 1;
34 while (new_words < need_words)
35 new_words *= 2;
36
37 uint64_t *new = calloc(new_words, sizeof(uint64_t));
38 if (new == NULL) {
39 die("Out of memory: cannot enlarge bitset");
40 }
41 if (bs->words) {
42 memcpy(new, bs->words, bs->nwords * sizeof(uint64_t));
43 free(bs->words);
44 }
45 bs->words = new;
46 bs->nwords = new_words;
47}
48
49void bitset_set(bitset_t *bs, size_t bit) {
50 bitset_reserve(bs, bit);
51 bs->words[BITWORD(bit)] |= BITMASK(bit);
52}
53
54void bitset_clear(bitset_t *bs, size_t bit) {
55 size_t w = BITWORD(bit);
56 if (w >= bs->nwords)
57 return;
58 bs->words[w] &= ~BITMASK(bit);
59}
60
61bool bitset_get(const bitset_t *bs, size_t bit) {
62 size_t w = BITWORD(bit);
63 if (w >= bs->nwords)
64 return false;
65 return (bs->words[w] & BITMASK(bit)) != 0;
66}
67
68void bitset_reset(bitset_t *bs) {
69 memset(bs->words, 0, bs->nwords * sizeof(uint64_t));
70}
71
72size_t bitset_count(const bitset_t *bs) {
73 size_t count = 0;
74 for (size_t i = 0; i < bs->nwords; i++)
75 count += __builtin_popcountll(bs->words[i]);
76 return count;
77}
78
79
80size_t bitset_max(const bitset_t *bs) {
81 for (size_t w = bs->nwords; w > 0; w--) {
82 uint64_t x = bs->words[w - 1];
83 if (x != 0) {
84 return ((w - 1) << 6)
85 + (63 - __builtin_clzll(x));
86 }
87 }
88 return 0;
89}
90
91void bitset_shift_up(bitset_t *bs, size_t n) {
92 if (n == 0) return;
93
94 size_t word_shift = n / 64;
95 size_t bit_shift = n % 64;
96
97 size_t old_max = bitset_max(bs);
98 bitset_reserve(bs, old_max + n - 1); // ensure enough space
99
100 size_t old_nwords = bs->nwords;
101
102 // shift words from end to start to avoid overwriting
103 for (ssize_t i = old_nwords - 1; i >= 0; i--) {
104 uint64_t w = bs->words[i];
105 uint64_t upper = (bit_shift != 0 && i > 0) ? bs->words[i - 1] >> (64 - bit_shift) : 0;
106 bs->words[i + word_shift] = (w << bit_shift) | upper;
107 }
108
109 // zero out lower words
110 for (size_t i = 0; i < word_shift; i++)
111 bs->words[i] = 0;
112}
113
114void bitset_shift_down(bitset_t *bs, size_t n) {
115 if (n == 0) return;
116
117 size_t word_shift = n / 64;
118 size_t bit_shift = n % 64;
119
120 if (word_shift >= bs->nwords) {
121 // all bits are discarded
122 bitset_reset(bs);
123 return;
124 }
125
126 // shift words from start to end
127 for (size_t i = 0; i + word_shift < bs->nwords; i++) {
128 uint64_t w = bs->words[i + word_shift];
129 uint64_t lower = (bit_shift != 0 && i + word_shift + 1 < bs->nwords)
130 ? bs->words[i + word_shift + 1] << (64 - bit_shift)
131 : 0;
132 bs->words[i] = (w >> bit_shift) | lower;
133 }
134
135 // zero out top words
136 for (size_t i = bs->nwords - word_shift; i < bs->nwords; i++)
137 bs->words[i] = 0;
138}
139
140void bitset_union_with_offset(bitset_t *bs1, const bitset_t *bs2, size_t skip) {
141 size_t total_bits = bs2->nwords * 64;
142 if (skip >= total_bits) return; // nothing to merge
143
144 // ensure bs1 can hold all bits
145 bitset_reserve(bs1, total_bits - skip - 1);
146
147 size_t start_word = skip / 64;
148 size_t start_bit = skip % 64;
149
150 uint64_t carry = 0;
151 for (size_t i = start_word; i < bs2->nwords; i++) {
152 uint64_t w = bs2->words[i];
153 if (i == start_word && start_bit != 0) {
154 // mask out the first 'start_bit' bits in the first word
155 w &= ~((1ULL << start_bit) - 1);
156 }
157
158 uint64_t new_w = (w >> start_bit) | carry;
159 carry = (start_bit != 0) ? (w << (64 - start_bit)) : 0;
160
161 size_t dest_word = i - start_word;
162 bs1->words[dest_word] |= new_w;
163 }
164
165 if (carry) {
166 size_t dest_word = bs2->nwords - start_word;
167 if (dest_word >= bs1->nwords) {
168 bitset_reserve(bs1, dest_word * 64 + 63);
169 }
170 bs1->words[dest_word] |= carry;
171 }
172}
173
174void bitset_union(bitset_t *bs1, const bitset_t *bs2) {
175 if (bs2->nwords > bs1->nwords)
176 bitset_reserve(bs1, (bs2->nwords * 64) - 1);
177
178 for (size_t i = 0; i < bs2->nwords; i++)
179 bs1->words[i] |= bs2->words[i];
180}
181
182void bitset_dump(const bitset_t *bs) {
183 size_t start = 0;
184 size_t bit;
185 printf("{");
186 bool isStart = 1;
187 while ((bit = bitset_next(bs, &start)) != (size_t)-1) {
188 if (!isStart)
189 printf(", ");
190 printf("%zu", bit);
191 isStart = 0;
192 }
193 printf("}");
194}
195
196size_t bitset_next(const bitset_t *bs, size_t *start) {
197 size_t i = *start;
198 while (1) {
199 size_t w = BITWORD(i);
200 if (w >= bs->nwords) {
201 *start = (size_t)-1;
202 return (size_t)-1;
203 }
204 uint64_t word = bs->words[w];
205
206 uint64_t mask = ~0ULL << (i & 63);
207 uint64_t rem = word & mask;
208
209 if (rem) {
210 int bit = __builtin_ctzll(rem);
211 size_t result = (w << 6) + bit;
212 *start = result + 1;
213 return result;
214 }
215
216 i = (w + 1) << 6;
217 }
218}