1 /*
2 * Copyright 2012-2015 Samy Al Bahra.
3 * Copyright 2012-2014 AppNexus, Inc.
4 * Copyright 2014 Paul Khuong.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #ifndef CK_BITMAP_H
30 #define CK_BITMAP_H
31
32 #include <ck_cc.h>
33 #include <ck_limits.h>
34 #include <ck_pr.h>
35 #include <ck_stdint.h>
36 #include <ck_stdbool.h>
37 #include <ck_stddef.h>
38 #include <ck_stdbool.h>
39 #include <ck_stddef.h>
40 #include <ck_string.h>
41
42 #if !defined(CK_F_PR_LOAD_UINT) || !defined(CK_F_PR_STORE_UINT) || \
43 !defined(CK_F_PR_AND_UINT) || !defined(CK_F_PR_OR_UINT) || \
44 !defined(CK_F_CC_CTZ)
45 #error "ck_bitmap is not supported on your platform."
46 #endif
47
48 #define CK_BITMAP_BLOCK (sizeof(unsigned int) * CHAR_BIT)
49 #define CK_BITMAP_OFFSET(i) ((i) % CK_BITMAP_BLOCK)
50 #define CK_BITMAP_BIT(i) (1U << CK_BITMAP_OFFSET(i))
51 #define CK_BITMAP_PTR(x, i) ((x) + ((i) / CK_BITMAP_BLOCK))
52 #define CK_BITMAP_BLOCKS(n) (((n) + CK_BITMAP_BLOCK - 1) / CK_BITMAP_BLOCK)
53
54 #define CK_BITMAP_INSTANCE(n_entries) \
55 union { \
56 struct { \
57 unsigned int n_bits; \
58 unsigned int map[CK_BITMAP_BLOCKS(n_entries)]; \
59 } content; \
60 struct ck_bitmap bitmap; \
61 }
62
63 #define CK_BITMAP_ITERATOR_INIT(a, b) \
64 ck_bitmap_iterator_init((a), &(b)->bitmap)
65
66 #define CK_BITMAP_INIT(a, b, c) \
67 ck_bitmap_init(&(a)->bitmap, (b), (c))
68
69 #define CK_BITMAP_NEXT(a, b, c) \
70 ck_bitmap_next(&(a)->bitmap, (b), (c))
71
72 #define CK_BITMAP_SET(a, b) \
73 ck_bitmap_set(&(a)->bitmap, (b))
74
75 #define CK_BITMAP_BTS(a, b) \
76 ck_bitmap_bts(&(a)->bitmap, (b))
77
78 #define CK_BITMAP_RESET(a, b) \
79 ck_bitmap_reset(&(a)->bitmap, (b))
80
81 #define CK_BITMAP_TEST(a, b) \
82 ck_bitmap_test(&(a)->bitmap, (b))
83
84 #define CK_BITMAP_UNION(a, b) \
85 ck_bitmap_union(&(a)->bitmap, &(b)->bitmap)
86
87 #define CK_BITMAP_INTERSECTION(a, b) \
88 ck_bitmap_intersection(&(a)->bitmap, &(b)->bitmap)
89
90 #define CK_BITMAP_INTERSECTION_NEGATE(a, b) \
91 ck_bitmap_intersection_negate(&(a)->bitmap, &(b)->bitmap)
92
93 #define CK_BITMAP_CLEAR(a) \
94 ck_bitmap_clear(&(a)->bitmap)
95
96 #define CK_BITMAP_EMPTY(a, b) \
97 ck_bitmap_empty(&(a)->bitmap, b)
98
99 #define CK_BITMAP_FULL(a, b) \
100 ck_bitmap_full(&(a)->bitmap, b)
101
102 #define CK_BITMAP_COUNT(a, b) \
103 ck_bitmap_count(&(a)->bitmap, b)
104
105 #define CK_BITMAP_COUNT_INTERSECT(a, b, c) \
106 ck_bitmap_count_intersect(&(a)->bitmap, b, c)
107
108 #define CK_BITMAP_BITS(a) \
109 ck_bitmap_bits(&(a)->bitmap)
110
111 #define CK_BITMAP_BUFFER(a) \
112 ck_bitmap_buffer(&(a)->bitmap)
113
114 #define CK_BITMAP(a) \
115 (&(a)->bitmap)
116
117 struct ck_bitmap {
118 unsigned int n_bits;
119 unsigned int map[];
120 };
121 typedef struct ck_bitmap ck_bitmap_t;
122
123 struct ck_bitmap_iterator {
124 unsigned int cache;
125 unsigned int n_block;
126 unsigned int n_limit;
127 };
128 typedef struct ck_bitmap_iterator ck_bitmap_iterator_t;
129
130 CK_CC_INLINE static unsigned int
ck_bitmap_base(unsigned int n_bits)131 ck_bitmap_base(unsigned int n_bits)
132 {
133
134 return CK_BITMAP_BLOCKS(n_bits) * sizeof(unsigned int);
135 }
136
137 /*
138 * Returns the required number of bytes for a ck_bitmap_t object supporting the
139 * specified number of bits.
140 */
141 CK_CC_INLINE static unsigned int
ck_bitmap_size(unsigned int n_bits)142 ck_bitmap_size(unsigned int n_bits)
143 {
144
145 return ck_bitmap_base(n_bits) + sizeof(struct ck_bitmap);
146 }
147
148 /*
149 * Returns total number of bits in specified bitmap.
150 */
151 CK_CC_INLINE static unsigned int
ck_bitmap_bits(const struct ck_bitmap * bitmap)152 ck_bitmap_bits(const struct ck_bitmap *bitmap)
153 {
154
155 return bitmap->n_bits;
156 }
157
158 /*
159 * Returns a pointer to the bit buffer associated
160 * with the specified bitmap.
161 */
162 CK_CC_INLINE static void *
ck_bitmap_buffer(struct ck_bitmap * bitmap)163 ck_bitmap_buffer(struct ck_bitmap *bitmap)
164 {
165
166 return bitmap->map;
167 }
168
169 /*
170 * Sets the bit at the offset specified in the second argument.
171 */
172 CK_CC_INLINE static void
ck_bitmap_set(struct ck_bitmap * bitmap,unsigned int n)173 ck_bitmap_set(struct ck_bitmap *bitmap, unsigned int n)
174 {
175
176 ck_pr_or_uint(CK_BITMAP_PTR(bitmap->map, n), CK_BITMAP_BIT(n));
177 return;
178 }
179
180 /*
181 * Performs a test-and-set operation at the offset specified in the
182 * second argument.
183 * Returns true if the bit at the specified offset was already set,
184 * false otherwise.
185 */
186 CK_CC_INLINE static bool
ck_bitmap_bts(struct ck_bitmap * bitmap,unsigned int n)187 ck_bitmap_bts(struct ck_bitmap *bitmap, unsigned int n)
188 {
189
190 return ck_pr_bts_uint(CK_BITMAP_PTR(bitmap->map, n),
191 CK_BITMAP_OFFSET(n));
192 }
193
194 /*
195 * Resets the bit at the offset specified in the second argument.
196 */
197 CK_CC_INLINE static void
ck_bitmap_reset(struct ck_bitmap * bitmap,unsigned int n)198 ck_bitmap_reset(struct ck_bitmap *bitmap, unsigned int n)
199 {
200
201 ck_pr_and_uint(CK_BITMAP_PTR(bitmap->map, n), ~CK_BITMAP_BIT(n));
202 return;
203 }
204
205 /*
206 * Determines whether the bit at offset specified in the
207 * second argument is set.
208 */
209 CK_CC_INLINE static bool
ck_bitmap_test(const struct ck_bitmap * bitmap,unsigned int n)210 ck_bitmap_test(const struct ck_bitmap *bitmap, unsigned int n)
211 {
212 unsigned int block;
213
214 block = ck_pr_load_uint(CK_BITMAP_PTR(bitmap->map, n));
215 return block & CK_BITMAP_BIT(n);
216 }
217
218 /*
219 * Combines bits from second bitmap into the first bitmap. This is not a
220 * linearized operation with respect to the complete bitmap.
221 */
222 CK_CC_INLINE static void
ck_bitmap_union(struct ck_bitmap * dst,const struct ck_bitmap * src)223 ck_bitmap_union(struct ck_bitmap *dst, const struct ck_bitmap *src)
224 {
225 unsigned int n;
226 unsigned int n_buckets = dst->n_bits;
227
228 if (src->n_bits < dst->n_bits)
229 n_buckets = src->n_bits;
230
231 n_buckets = CK_BITMAP_BLOCKS(n_buckets);
232 for (n = 0; n < n_buckets; n++) {
233 ck_pr_or_uint(&dst->map[n],
234 ck_pr_load_uint(&src->map[n]));
235 }
236
237 return;
238 }
239
240 /*
241 * Intersects bits from second bitmap into the first bitmap. This is
242 * not a linearized operation with respect to the complete bitmap.
243 * Any trailing bit in dst is cleared.
244 */
245 CK_CC_INLINE static void
ck_bitmap_intersection(struct ck_bitmap * dst,const struct ck_bitmap * src)246 ck_bitmap_intersection(struct ck_bitmap *dst, const struct ck_bitmap *src)
247 {
248 unsigned int n;
249 unsigned int n_buckets = dst->n_bits;
250 unsigned int n_intersect = n_buckets;
251
252 if (src->n_bits < n_intersect)
253 n_intersect = src->n_bits;
254
255 n_buckets = CK_BITMAP_BLOCKS(n_buckets);
256 n_intersect = CK_BITMAP_BLOCKS(n_intersect);
257 for (n = 0; n < n_intersect; n++) {
258 ck_pr_and_uint(&dst->map[n],
259 ck_pr_load_uint(&src->map[n]));
260 }
261
262 for (; n < n_buckets; n++)
263 ck_pr_store_uint(&dst->map[n], 0);
264
265 return;
266 }
267
268 /*
269 * Intersects the complement of bits from second bitmap into the first
270 * bitmap. This is not a linearized operation with respect to the
271 * complete bitmap. Any trailing bit in dst is left as is.
272 */
273 CK_CC_INLINE static void
ck_bitmap_intersection_negate(struct ck_bitmap * dst,const struct ck_bitmap * src)274 ck_bitmap_intersection_negate(struct ck_bitmap *dst,
275 const struct ck_bitmap *src)
276 {
277 unsigned int n;
278 unsigned int n_intersect = dst->n_bits;
279
280 if (src->n_bits < n_intersect)
281 n_intersect = src->n_bits;
282
283 n_intersect = CK_BITMAP_BLOCKS(n_intersect);
284 for (n = 0; n < n_intersect; n++) {
285 ck_pr_and_uint(&dst->map[n],
286 (~ck_pr_load_uint(&src->map[n])));
287 }
288
289 return;
290 }
291
292 /*
293 * Resets all bits in the provided bitmap. This is not a linearized
294 * operation in ck_bitmap.
295 */
296 CK_CC_INLINE static void
ck_bitmap_clear(struct ck_bitmap * bitmap)297 ck_bitmap_clear(struct ck_bitmap *bitmap)
298 {
299 unsigned int i;
300 unsigned int n_buckets = ck_bitmap_base(bitmap->n_bits) /
301 sizeof(unsigned int);
302
303 for (i = 0; i < n_buckets; i++)
304 ck_pr_store_uint(&bitmap->map[i], 0);
305
306 return;
307 }
308
309 /*
310 * Returns true if the first limit bits in bitmap are cleared. If
311 * limit is greater than the bitmap size, limit is truncated to that
312 * size.
313 */
314 CK_CC_INLINE static bool
ck_bitmap_empty(const ck_bitmap_t * bitmap,unsigned int limit)315 ck_bitmap_empty(const ck_bitmap_t *bitmap, unsigned int limit)
316 {
317 unsigned int i, words, slop;
318
319 if (limit > bitmap->n_bits)
320 limit = bitmap->n_bits;
321
322 words = limit / CK_BITMAP_BLOCK;
323 slop = limit % CK_BITMAP_BLOCK;
324 for (i = 0; i < words; i++) {
325 if (ck_pr_load_uint(&bitmap->map[i]) != 0) {
326 return false;
327 }
328 }
329
330 if (slop > 0) {
331 unsigned int word;
332
333 word = ck_pr_load_uint(&bitmap->map[i]);
334 if ((word & ((1U << slop) - 1)) != 0)
335 return false;
336 }
337
338 return true;
339 }
340
341 /*
342 * Returns true if the first limit bits in bitmap are set. If limit
343 * is greater than the bitmap size, limit is truncated to that size.
344 */
345 CK_CC_UNUSED static bool
ck_bitmap_full(const ck_bitmap_t * bitmap,unsigned int limit)346 ck_bitmap_full(const ck_bitmap_t *bitmap, unsigned int limit)
347 {
348 unsigned int i, slop, words;
349
350 if (limit > bitmap->n_bits) {
351 limit = bitmap->n_bits;
352 }
353
354 words = limit / CK_BITMAP_BLOCK;
355 slop = limit % CK_BITMAP_BLOCK;
356 for (i = 0; i < words; i++) {
357 if (ck_pr_load_uint(&bitmap->map[i]) != -1U)
358 return false;
359 }
360
361 if (slop > 0) {
362 unsigned int word;
363
364 word = ~ck_pr_load_uint(&bitmap->map[i]);
365 if ((word & ((1U << slop) - 1)) != 0)
366 return false;
367 }
368 return true;
369 }
370
371 /*
372 * Returns the number of set bit in bitmap, upto (and excluding)
373 * limit. If limit is greater than the bitmap size, it is truncated
374 * to that size.
375 */
376 CK_CC_INLINE static unsigned int
ck_bitmap_count(const ck_bitmap_t * bitmap,unsigned int limit)377 ck_bitmap_count(const ck_bitmap_t *bitmap, unsigned int limit)
378 {
379 unsigned int count, i, slop, words;
380
381 if (limit > bitmap->n_bits)
382 limit = bitmap->n_bits;
383
384 words = limit / CK_BITMAP_BLOCK;
385 slop = limit % CK_BITMAP_BLOCK;
386 for (i = 0, count = 0; i < words; i++)
387 count += ck_cc_popcount(ck_pr_load_uint(&bitmap->map[i]));
388
389 if (slop > 0) {
390 unsigned int word;
391
392 word = ck_pr_load_uint(&bitmap->map[i]);
393 count += ck_cc_popcount(word & ((1U << slop) - 1));
394 }
395 return count;
396 }
397
398 /*
399 * Returns the number of set bit in the intersection of two bitmaps,
400 * upto (and excluding) limit. If limit is greater than either bitmap
401 * size, it is truncated to the smallest.
402 */
403 CK_CC_INLINE static unsigned int
ck_bitmap_count_intersect(const ck_bitmap_t * x,const ck_bitmap_t * y,unsigned int limit)404 ck_bitmap_count_intersect(const ck_bitmap_t *x, const ck_bitmap_t *y,
405 unsigned int limit)
406 {
407 unsigned int count, i, slop, words;
408
409 if (limit > x->n_bits)
410 limit = x->n_bits;
411
412 if (limit > y->n_bits)
413 limit = y->n_bits;
414
415 words = limit / CK_BITMAP_BLOCK;
416 slop = limit % CK_BITMAP_BLOCK;
417 for (i = 0, count = 0; i < words; i++) {
418 unsigned int xi, yi;
419
420 xi = ck_pr_load_uint(&x->map[i]);
421 yi = ck_pr_load_uint(&y->map[i]);
422 count += ck_cc_popcount(xi & yi);
423 }
424
425 if (slop > 0) {
426 unsigned int word, xi, yi;
427
428 xi = ck_pr_load_uint(&x->map[i]);
429 yi = ck_pr_load_uint(&y->map[i]);
430 word = xi & yi;
431 count += ck_cc_popcount(word & ((1U << slop) - 1));
432 }
433 return count;
434 }
435
436 /*
437 * Initializes a ck_bitmap pointing to a region of memory with
438 * ck_bitmap_size(n_bits) bytes. Third argument determines whether
439 * default bit value is 1 (true) or 0 (false).
440 */
441 CK_CC_INLINE static void
ck_bitmap_init(struct ck_bitmap * bitmap,unsigned int n_bits,bool set)442 ck_bitmap_init(struct ck_bitmap *bitmap,
443 unsigned int n_bits,
444 bool set)
445 {
446 unsigned int base = ck_bitmap_base(n_bits);
447
448 bitmap->n_bits = n_bits;
449 memset(bitmap->map, -(int)set, base);
450
451 if (set == true) {
452 unsigned int b = n_bits % CK_BITMAP_BLOCK;
453
454 if (b == 0)
455 return;
456
457 *CK_BITMAP_PTR(bitmap->map, n_bits - 1) &= (1U << b) - 1U;
458 }
459
460 return;
461 }
462
463 /*
464 * Initialize iterator for use with provided bitmap.
465 */
466 CK_CC_INLINE static void
ck_bitmap_iterator_init(struct ck_bitmap_iterator * i,const struct ck_bitmap * bitmap)467 ck_bitmap_iterator_init(struct ck_bitmap_iterator *i,
468 const struct ck_bitmap *bitmap)
469 {
470
471 i->n_block = 0;
472 i->n_limit = CK_BITMAP_BLOCKS(bitmap->n_bits);
473 if (i->n_limit > 0) {
474 i->cache = ck_pr_load_uint(&bitmap->map[0]);
475 } else {
476 i->cache = 0;
477 }
478 return;
479 }
480
481 /*
482 * Iterate to next bit.
483 */
484 CK_CC_INLINE static bool
ck_bitmap_next(const struct ck_bitmap * bitmap,struct ck_bitmap_iterator * i,unsigned int * bit)485 ck_bitmap_next(const struct ck_bitmap *bitmap,
486 struct ck_bitmap_iterator *i,
487 unsigned int *bit)
488 {
489 unsigned int cache = i->cache;
490 unsigned int n_block = i->n_block;
491 unsigned int n_limit = i->n_limit;
492
493 if (cache == 0) {
494 if (n_block >= n_limit)
495 return false;
496
497 for (n_block++; n_block < n_limit; n_block++) {
498 cache = ck_pr_load_uint(&bitmap->map[n_block]);
499 if (cache != 0)
500 goto non_zero;
501 }
502
503 i->cache = 0;
504 i->n_block = n_block;
505 return false;
506 }
507
508 non_zero:
509 *bit = CK_BITMAP_BLOCK * n_block + ck_cc_ctz(cache);
510 i->cache = cache & (cache - 1);
511 i->n_block = n_block;
512 return true;
513 }
514
515 #endif /* CK_BITMAP_H */
516