File Coverage

ds_bitmask126.h
Criterion Covered Total %
statement 105 134 78.3
branch 46 76 60.5
condition n/a
subroutine n/a
pod n/a
total 151 210 71.9


line stmt bran cond sub pod time code
1             #ifndef MPU_DS_BITMASK126_H
2             #define MPU_DS_BITMASK126_H
3              
4             #include "ptypes.h"
5              
6             /******************************************************************************/
7             /* BITMASK126 DATA STRUCTURE */
8             /******************************************************************************/
9              
10             /*
11             * This is a bitmask for lucky numbers, using a 32-bit word for 126 integers.
12             * Crucially, we use a tree of counts so we can skip to a given index in a
13             * reasonable amount of time.
14             *
15             * The amount of memory used is about n/25. This is about 20x smaller than
16             * the 64-bit pagelist or cgen method, and 10x smaller than Wilson's list,
17             * in addition to being orders of magnitude faster than cgen or Wilson.
18             */
19              
20             #ifndef BMTYPE
21             #define BMTYPE UV
22             #endif
23              
24             #define BMDEBUG 0
25             /* Not clear if SSHIFT/TSHIFT should be 3/3, 3/4, 4/3, or 4/4 */
26             #define SSHIFT 4
27             #define TSHIFT 3
28              
29             static unsigned char _bm_offset[32] = {
30             1, 3, 7, 9,13,15,21,25,31,33,37, 43, 45, 49, 51, 55,
31             63,67,69,73,75,79,85,87,93,97,99,105,109,111,115,117};
32             static unsigned char _bm_bit[63] = {
33             0, 1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 6, 7, 7, 7, 8,
34             9, 9,10,10,10,11,12,12,13,14,14,15,15,15,15,16,
35             16,17,18,18,19,20,20,21,21,21,22,23,23,23,24,24,
36             25,26,26,26,27,27,28,29,29,30,31,31,31,31,31 };
37              
38             #define BM_WORD(n) ((n) / 2 / 63)
39             #define BM_BITN(n) _bm_bit[(n) / 2 % 63]
40             #define BM_BITM(n) (1U << BM_BITN(n))
41              
42             /* Modified from Stanford Bit Twiddling Hacks, via "Nominal Animal" */
43 132797           static uint32_t _nth_bit_set(uint32_t n, uint32_t word) {
44 132797           const uint32_t pop2 = word - (word >> 1 & 0x55555555u);
45 132797           const uint32_t pop4 = (pop2 & 0x33333333u) + (pop2 >> 2 & 0x33333333u);
46 132797           const uint32_t pop8 = (pop4 + (pop4 >> 4)) & 0x0f0f0f0fu;
47 132797           const uint32_t pop16 = (pop8 + (pop8 >> 8)) & 0x00ff00ffu;
48 132797           const uint32_t pop32 = (pop16 + (pop16 >> 16)) & 0x000000ffu;
49 132797           uint32_t temp, rank = 0;
50              
51 132797 50         if (n++ >= pop32) return 32;
52              
53 132797           temp = pop16 & 0xffu;
54 132797 100         if (n > temp) { n -= temp; rank += 16; }
55 132797           temp = (pop8 >> rank) & 0xffu;
56 132797 100         if (n > temp) { n -= temp; rank += 8; }
57 132797           temp = (pop4 >> rank) & 0x0fu;
58 132797 100         if (n > temp) { n -= temp; rank += 4; }
59 132797           temp = (pop2 >> rank) & 0x03u;
60 132797 100         if (n > temp) { n -= temp; rank += 2; }
61 132797           temp = (word >> rank) & 0x01u;
62 132797 100         if (n > temp) rank += 1;
63              
64 132797           return rank;
65             }
66              
67             /* We are trying to balance space and performance. */
68             /* Also note that we do not support a bitmask with 256 consecutive bits set,
69             * as that would overflow bsize.
70             * A "block" could be changed to 16 or 32 words * with a uint16_t bsize. */
71             typedef struct bitmask126_t {
72             BMTYPE n; /* The upper limit on the sieve */
73             BMTYPE nelems; /* The total number of bits set */
74             BMTYPE nwords; /* The number of words in data[] */
75             int nilevels; /* The number of tbsize[] arrays actually used */
76             uint32_t* data; /* The bitmap itself */
77             uint8_t* size; /* The number of bits set in each data[] word */
78             uint8_t* bsize; /* Sums over 8-word blocks */
79             uint16_t* sbsize; /* Sums over 1<
80             BMTYPE* tbsize[12]; /* Further index levels */
81             } bitmask126_t;
82              
83 3           static bitmask126_t* bitmask126_create(BMTYPE n) {
84             BMTYPE nblocks, nlevels;
85             bitmask126_t *bm;
86 3           New(0, bm, 1, bitmask126_t);
87              
88 3           bm->n = n;
89 3           bm->nelems = 0;
90 3           bm->nwords = (n+125)/126;
91 3           nblocks = (bm->nwords + 7) / 8;
92 3 50         Newz(0, bm->data, bm->nwords, uint32_t);
93 3           Newz(0, bm->size, bm->nwords, uint8_t);
94 3           Newz(0, bm->bsize, nblocks, uint8_t);
95 3           nblocks = (nblocks + (1U << SSHIFT) - 1) >> SSHIFT;
96 3 50         Newz(0, bm->sbsize, nblocks, uint16_t);
97              
98 5 50         for (nlevels=0; nlevels < 12; nlevels++) {
99 5           nblocks = (nblocks + (1U << TSHIFT) - 1) >> TSHIFT;
100 5 100         if (nblocks < 3) break;
101             #if BMDEBUG
102             printf(" level %lu blocks = %lu\n", nlevels, nblocks);
103             #endif
104 2 50         Newz(0, bm->tbsize[nlevels], nblocks, BMTYPE);
105             }
106 3           bm->nilevels = nlevels;
107              
108 3           return bm;
109             }
110              
111 3           static void bitmask126_destroy(bitmask126_t *bm) {
112             int i;
113              
114 3           Safefree(bm->data);
115 3           Safefree(bm->size);
116 3           Safefree(bm->bsize);
117 3           Safefree(bm->sbsize);
118 5 100         for (i = 0; i < bm->nilevels; i++)
119 2           Safefree(bm->tbsize[i]);
120 3           bm->nelems = 0;
121 3           bm->n = 0;
122 3           Safefree(bm);
123 3           }
124              
125             /* Update all index levels for adding (subtracting) n bits to word wi. */
126             #define ADDSIZE(bm, wi, n) \
127             do { int _i; \
128             BMTYPE _j = wi; \
129             bm->size[_j] += n; \
130             bm->bsize[_j >>= 3] += n; \
131             bm->sbsize[_j >>= SSHIFT] += n; \
132             for (_i = 0; _i < bm->nilevels; _i++) \
133             bm->tbsize[_i][_j >>= TSHIFT] += n; \
134             bm->nelems += n; \
135             } while (0)
136              
137 210597           static void bitmask126_append(bitmask126_t *bm, BMTYPE n) {
138 210597           BMTYPE w = BM_WORD(n);
139             #if BMDEBUG
140             if (n >= bm->n) croak("bitmask126: bad n in append");
141             #endif
142 210597           bm->data[w] |= BM_BITM(n);
143 410504 100         ADDSIZE(bm, w, 1);
144 210597           }
145              
146 0           static BMTYPE* bitmask126_to_array(UV *size, bitmask126_t *bm) {
147             BMTYPE nelem, wi, nwords, *arr;
148              
149 0 0         New(0, arr, bm->nelems, BMTYPE);
150 0           nwords = bm->nwords;
151 0           nelem = 0;
152              
153 0 0         for (wi = 0; wi < nwords; wi++) {
154 0           uint32_t bit, w = bm->data[wi];
155 0 0         for (bit = 0; bit < 32; bit++, w >>= 1)
156 0 0         if (w & 1)
157 0           arr[nelem++] = wi*126 + _bm_offset[bit];
158             }
159 0 0         if (nelem != bm->nelems) croak("bitmask126: bad number of elements in array");
160 0           *size = nelem;
161 0           return arr;
162             }
163 2           static uint32_t* bitmask126_to_array32(UV *size, const bitmask126_t *bm) {
164             uint32_t nelem, wi, nwords, *arr;
165              
166 2 50         New(0, arr, bm->nelems, uint32_t);
167 2           nwords = bm->nwords;
168 2           nelem = 0;
169              
170 7616 100         for (wi = 0; wi < nwords; wi++) {
171 7614           uint32_t bit, w = bm->data[wi];
172 251262 100         for (bit = 0; bit < 32; bit++, w >>= 1)
173 243648 100         if (w & 1)
174 73001           arr[nelem++] = wi*126 + _bm_offset[bit];
175             }
176 2 50         if (nelem != bm->nelems) croak("bitmask126: bad number of elements in array");
177 2           *size = nelem;
178 2           return arr;
179             }
180              
181              
182             /* We want to find the e.g. 101'st set value, returns the array word index,
183             * and set *idx to the number of bits to skip within that word. */
184 132797           static BMTYPE _bitmask126_find_index(const bitmask126_t *bm, BMTYPE *idx) {
185             int lev;
186 132797           BMTYPE i = *idx, j = 0;
187              
188 132797 50         if (i > bm->nelems) croak("index higher than number of elements");
189              
190             /* Skip though superblock tree (128,2048,32768,524288,... words) */
191 259705 100         for (lev = bm->nilevels-1; lev >= 0; lev--) {
192 126908           const BMTYPE *tbsizei = bm->tbsize[lev];
193 326766 100         for (j <<= TSHIFT; i >= tbsizei[j]; j++)
194 199858           i -= tbsizei[j];
195             }
196 561076 100         for (j <<= TSHIFT; i >= bm->sbsize[j]; j++) /* Skip superblocks */
197 428279           i -= bm->sbsize[j];
198 1122327 100         for (j <<= SSHIFT; i >= bm->bsize[j]; j++) /* Skip 8w blocks */
199 989530           i -= bm->bsize[j];
200 597879 100         for (j <<= 3; i >= bm->size[j]; j++) /* Skip words */
201 465082           i -= bm->size[j];
202              
203 132797           *idx = i;
204 132797           return j;
205             }
206              
207             static INLINE BMTYPE bitmask126_val(const bitmask126_t *bm, BMTYPE idx) {
208             BMTYPE wi;
209             uint32_t bit;
210              
211             wi = _bitmask126_find_index(bm, &idx);
212             bit = _nth_bit_set(idx, bm->data[wi]);
213             return wi * 126 + _bm_offset[bit];
214             }
215              
216 132793           static void bitmask126_delete(bitmask126_t *bm, BMTYPE idx) { /* idx 0,1,... */
217             BMTYPE wi;
218              
219             #if BMDEBUG
220             if (idx >= bm->nelems) croak("bitmask126: bad index in delete");
221             #endif
222              
223 132793           wi = _bitmask126_find_index(bm, &idx);
224              
225 132793 50         if (bm->size[wi] == 1) { /* Only 1 value, zero the word. */
226 0           bm->data[wi] = 0;
227             } else { /* Find the index bit and zero it */
228 132793           uint32_t bit = _nth_bit_set(idx, bm->data[wi]);
229 132793           bm->data[wi] &= ~(1U << bit);
230             }
231              
232 259699 100         ADDSIZE(bm, wi, -1);
233 132793           }
234              
235              
236              
237             typedef struct bitmask126_iter_t {
238             const bitmask126_t *bm;
239             const uint32_t *data;
240             BMTYPE wi;
241             uint32_t bit;
242             } bitmask126_iter_t;
243              
244 4           static bitmask126_iter_t bitmask126_iterator_create(const bitmask126_t *bm, BMTYPE idx) {
245             bitmask126_iter_t iter;
246 4 50         if (idx >= bm->nelems) croak("bitmask126: invalid iterator initial position\n");
247 4           iter.bm = bm;
248 4           iter.data = bm->data;
249 4           iter.wi = _bitmask126_find_index(bm, &idx);
250 4           iter.bit = _nth_bit_set(idx, bm->data[iter.wi]);
251 4           return iter;
252             }
253              
254 7656           static BMTYPE bitmask126_iterator_next(bitmask126_iter_t *iter) {
255 7656           BMTYPE v, wi = iter->wi;
256 7656           uint32_t bit = iter->bit;
257 7656           uint32_t w = iter->data[wi] >> bit;
258              
259 8057 100         while (w == 0) { /* skip any empty words */
260 401           w = iter->data[++wi];
261 401           bit = 0;
262             }
263              
264             #if defined(__GNUC__) && 100*__GNUC__ + __GNUC_MINOR >= 304
265 7656           bit += __builtin_ctzl(w);
266             #else
267             for ( ; bit < 32; bit++, w >>= 1) /* Find next set bit */
268             if (w & 1)
269             break;
270             #endif
271              
272 7656           v = wi * 126 + _bm_offset[bit];
273              
274 7656           iter->bit = ++bit & 31;
275 7656           iter->wi = wi + (bit>>5);
276 7656           return v;
277             }
278              
279 0           static BMTYPE bitmask126_iterator_prev(bitmask126_iter_t *iter) {
280 0           BMTYPE v, wi = iter->wi;
281 0           int bit = iter->bit;
282 0           uint32_t w = iter->data[wi];
283              
284             do {
285 0 0         if (bit < 0) {
286 0 0         if (wi == 0) croak("bitmask126: iterator underflow");
287 0           w = iter->data[--wi];
288 0           bit = 31;
289             }
290 0 0         for ( ; bit >= 0; bit--) { /* Find prev set bit */
291 0 0         if (w & 1U << bit)
292 0           break;
293             }
294 0 0         } while (bit < 0);
295              
296 0           v = wi * 126 + _bm_offset[bit];
297              
298 0           iter->bit = --bit & 31;
299 0           iter->wi = wi - (bit >> 5 & 1);
300 0           return v;
301             }
302              
303             #undef BMTYPE
304             #undef BMDEBUG
305             #undef SSHIFT
306             #undef TSHIFT
307             #undef ADDSIZE
308             #undef BM_WORD
309             #undef BM_BITN
310             #undef BM_BITM
311              
312             #endif