the hito embeddable programming language
at main 218 lines 5.3 kB view raw
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}