xref: /freebsd/sys/contrib/ck/include/ck_bitmap.h (revision 8aac90f18aef7c9eea906c3ff9a001ca7b94f375)
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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