forked from bliksemlabs/rrrr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bitset.c
181 lines (155 loc) · 4.79 KB
/
bitset.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/* Copyright 2013 Bliksem Labs.
* See the LICENSE file at the top-level directory of this distribution and at
* https://github.com/bliksemlabs/rrrr/
*/
/* bitset.c : compact enumerable bit array */
#include "bitset.h"
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
/* Initialize a pre-allocated bitset struct,
* allocating memory for bits_t holding the bits.
*/
static void bitset_init(bitset_t *self, uint32_t capacity) {
self->capacity = capacity;
/* round upwards */
self->n_chunks = (capacity + (BS_BITS - 1)) >> BS_SHIFT;
self->chunks = (bits_t *) calloc(self->n_chunks, sizeof(bits_t));
}
/* Allocate a new bitset of the specified capacity,
* and return a pointer to the bitset_t struct.
*/
bitset_t *bitset_new(uint32_t capacity) {
bitset_t *bs = (bitset_t *) malloc(sizeof(bitset_t));
if (bs == NULL) return NULL;
bitset_init(bs, capacity);
if (bs->chunks == NULL) {
fprintf(stderr, "bitset chunk allocation failure.");
free (bs);
return NULL;
}
return bs;
}
/* De-allocate a bitset_t struct as well as the memory it references
* internally for the bit fields.
*/
void bitset_destroy(bitset_t *self) {
if (!self) return;
free(self->chunks);
free(self);
}
void bitset_clear(bitset_t *self) {
uint32_t i_chunk = self->n_chunks;
do {
i_chunk--;
self->chunks[i_chunk] = (bits_t) 0;
} while (i_chunk);
}
void bitset_black(bitset_t *self) {
uint32_t i_chunk = self->n_chunks;
do {
i_chunk--;
self->chunks[i_chunk] = ~((bits_t) 0);
} while (i_chunk);
}
void bitset_mask_and(bitset_t *self, bitset_t *mask) {
uint32_t i_chunk = self->n_chunks;
assert (self->capacity == mask->capacity);
do {
i_chunk--;
self->chunks[i_chunk] &= mask->chunks[i_chunk];
} while (i_chunk);
}
/* Our bitset code is storing a long number of bits by packing an array of
* uint128_t's. To find at what location a bit should be read or written, we
* must firstly figure out at what index the bit is stored.
* An uint128_t is 128bit long, thus to figure out the index in our array for
* bit 137 would divide by 128 and the remainder will be the nth place in the
* at the selected index.
* Dividing by 128 can be done using a bitshift right 7.
* Calculating the remainder of 128 can be done using modulo 128 or using
* 137 & ((1 << 7) - 1), the latter equals 127.
*
* To resume:
* 137 / 128 = 137 >> 7
* 137 % 128 = 137 & 127
*
* Or bitwise:
* 10001001 = 137
* 10001001 >> 7 =
* 1 = 1
*
* 10001001 =
* 01111111 = 127
* & =
* 00001001 = 9
*/
void bitset_set(bitset_t *self, uint32_t index) {
assert (index < self->capacity);
self->chunks[index >> BS_SHIFT] |= ((bits_t) 1) << (index & (BS_BITS - 1));
}
void bitset_unset(bitset_t *self, uint32_t index) {
assert (index < self->capacity);
self->chunks[index >> BS_SHIFT] &= ~(((bits_t) 1) << (index & (BS_BITS - 1)));
}
bool bitset_get(bitset_t *self, uint32_t index) {
assert (index < self->capacity);
return self->chunks[index >> BS_SHIFT] & ((bits_t) 1) << (index & (BS_BITS - 1));
}
/* Return the next set index in this bitset_t greater than or equal to
* the specified index. Returns BITSET_NONE if there are no more set bits.
*/
uint32_t bitset_next_set_bit(bitset_t *bs, uint32_t index) {
bits_t *chunk = bs->chunks + (index >> BS_SHIFT);
bits_t mask = ((bits_t) 1) << (index & (BS_BITS - 1));
while (index < bs->capacity) {
/* check current bit in current chunk */
if (mask & *chunk)
return index;
/* move to next bit in current chunk */
mask <<= 1;
index += 1;
/* begin a new chunk */
if (mask == 0) {
/* 1ull */
mask = ((bits_t) 1);
++chunk;
/* spin forward to next chunk containing a set bit,
* if no set bit was found
*/
while ( ! *chunk ) {
++chunk;
index += BS_BITS;
if (index >= bs->capacity) {
return BITSET_NONE;
}
}
}
}
return BITSET_NONE;
}
#ifdef RRRR_DEBUG
void bitset_dump(bitset_t *self) {
uint32_t i;
for (i = 0; i < self->capacity; ++i)
if (bitset_get(self, i))
fprintf(stderr, "%d ", i);
fprintf(stderr, "\n\n");
}
uint32_t bitset_enumerate(bitset_t *self) {
uint32_t total = 0;
uint32_t elem;
for (elem = bitset_next_set_bit(self, 0);
elem != BITSET_NONE;
elem = bitset_next_set_bit(self, elem + 1)) {
#if 0
fprintf (stderr, "%d ", elem);
#endif
total += elem;
}
return total;
}
#endif /* RRRR_DEBUG */