2 * Handle bit vector as a run length encoded array of
5 * Copyright (C) 2007 Olaf Kirch <olaf.kirch@oracle.com>
13 struct isns_bitvector
{
14 unsigned int ib_count
;
19 isns_bitvector_init(isns_bitvector_t
*bv
)
21 memset(bv
, 0, sizeof(*bv
));
25 isns_bitvector_destroy(isns_bitvector_t
*bv
)
27 isns_free(bv
->ib_words
);
28 memset(bv
, 0, sizeof(*bv
));
32 isns_bitvector_alloc(void)
34 return isns_calloc(1, sizeof(isns_bitvector_t
));
38 isns_bitvector_free(isns_bitvector_t
*bv
)
41 isns_free(bv
->ib_words
);
42 memset(bv
, 0xa5, sizeof(*bv
));
48 * Helper function to locate bit
51 __isns_bitvector_find_word(const isns_bitvector_t
*bv
, unsigned int bit
)
55 if (bv
->ib_words
== NULL
)
59 end
= wp
+ bv
->ib_count
;
61 unsigned int base
, rlen
;
66 isns_assert(!(base
% 32));
67 if (base
<= bit
&& bit
< base
+ rlen
* 32)
68 return wp
+ 2 + ((bit
- base
) / 32);
71 isns_assert(wp
<= end
);
78 * Insert words in the middle of the array
81 __isns_bitvector_insert_words(isns_bitvector_t
*bv
,
82 unsigned int offset
, unsigned int count
)
84 bv
->ib_words
= isns_realloc(bv
->ib_words
,
85 (bv
->ib_count
+ count
) * sizeof(uint32_t));
87 /* If we insert in the middle, shift out the tail
88 * to make room for the new range. */
89 isns_assert(offset
<= bv
->ib_count
);
90 if (offset
< bv
->ib_count
) {
91 memmove(bv
->ib_words
+ offset
+ count
,
92 bv
->ib_words
+ offset
,
93 (bv
->ib_count
- offset
) * sizeof(uint32_t));
96 memset(bv
->ib_words
+ offset
, 0, count
* sizeof(uint32_t));
97 bv
->ib_count
+= count
;
103 static inline uint32_t *
104 __isns_bitvector_insert_range(isns_bitvector_t
*bv
,
105 unsigned int offset
, unsigned int base
)
109 __isns_bitvector_insert_words(bv
, offset
, 3);
111 pos
= bv
->ib_words
+ offset
;
120 * Extend an existing range
121 * @offset marks the beginning of the existing range.
123 static inline uint32_t *
124 __isns_bitvector_extend_range(isns_bitvector_t
*bv
,
125 unsigned int offset
, unsigned int count
)
129 /* Find the end of the range */
130 pos
= bv
->ib_words
+ offset
;
133 __isns_bitvector_insert_words(bv
, offset
+ 2 + rlen
, count
);
135 pos
= bv
->ib_words
+ offset
;
138 /* Return pointer to the last word of the new range. */
139 return pos
+ 2 + rlen
+ count
- 1;
143 * Find a suitable range for insertion
146 __isns_bitvector_find_insert_word(isns_bitvector_t
*bv
, unsigned int bit
)
150 if (bv
->ib_words
== NULL
)
151 return __isns_bitvector_insert_range(bv
, 0, bit
);
154 end
= wp
+ bv
->ib_count
;
156 unsigned int base
, rlen
, distance
;
161 isns_assert(!(base
% 32));
164 return __isns_bitvector_insert_range(bv
,
165 wp
- bv
->ib_words
, bit
);
168 distance
= (bit
- base
) / 32;
169 if (distance
< rlen
) {
170 /* This bit is within range */
171 return wp
+ 2 + distance
;
174 /* Is it efficient to extend this range?
175 * The break even point is if we have to add
176 * 3 words to extend the range, because a new
177 * range would be at least that much.
179 if (distance
+ 1 <= rlen
+ 3) {
180 return __isns_bitvector_extend_range(bv
,
182 distance
+ 1 - rlen
);
186 isns_assert(wp
<= end
);
189 /* No suitable range found. Append one at the end */
190 return __isns_bitvector_insert_range(bv
,
195 * After clearing a bit, check if the bitvector can be
199 __isns_bitvector_compact(isns_bitvector_t
*bv
)
201 uint32_t *src
, *dst
, *end
;
202 unsigned int dst_base
= 0, dst_len
= 0;
204 if (bv
->ib_words
== NULL
)
207 src
= dst
= bv
->ib_words
;
208 end
= src
+ bv
->ib_count
;
210 unsigned int base
, rlen
;
215 /* Consume leading NUL words */
216 while (rlen
&& *src
== 0) {
222 /* Consume trailing NUL words */
223 while (rlen
&& src
[rlen
-1] == 0)
227 if (dst_len
&& dst_base
+ 32 * dst_len
== base
) {
228 /* We can extend the previous run */
230 /* New run. Close off the previous one,
243 dst
[2 + dst_len
++] = *src
++;
246 isns_assert(src
<= end
);
256 bv
->ib_count
= dst
- bv
->ib_words
;
257 if (bv
->ib_count
== 0)
258 isns_bitvector_destroy(bv
);
262 * Test the value of a single bit
265 isns_bitvector_test_bit(const isns_bitvector_t
*bv
, unsigned int bit
)
270 pos
= __isns_bitvector_find_word(bv
, bit
);
274 mask
= 1 << (bit
% 32);
275 return !!(*pos
& mask
);
279 isns_bitvector_clear_bit(isns_bitvector_t
*bv
, unsigned int bit
)
281 uint32_t *pos
, oldval
, mask
;
283 pos
= __isns_bitvector_find_word(bv
, bit
);
287 mask
= 1 << (bit
% 32);
291 __isns_bitvector_compact(bv
);
292 return !!(oldval
& mask
);
296 isns_bitvector_set_bit(isns_bitvector_t
*bv
, unsigned int bit
)
298 uint32_t *pos
, oldval
= 0, mask
;
300 mask
= 1 << (bit
% 32);
302 pos
= __isns_bitvector_find_insert_word(bv
, bit
);
307 return !!(oldval
& mask
);
314 isns_bitvector_is_empty(const isns_bitvector_t
*bv
)
318 if (bv
== NULL
|| bv
->ib_count
== 0)
321 /* In theory, we should never have a non-compacted
322 * empty bitvector, as the only way to get one
323 * is through clear_bit.
324 * Better safe than sorry...
328 end
= wp
+ bv
->ib_count
;
330 unsigned int base
, rlen
;
339 isns_assert(wp
<= end
);
346 isns_bitvector_intersect(const isns_bitvector_t
*a
,
347 const isns_bitvector_t
*b
,
348 isns_bitvector_t
*result
)
350 const uint32_t *runa
, *runb
, *enda
, *endb
;
351 const uint32_t *wpa
= NULL
, *wpb
= NULL
;
352 uint32_t bita
= 0, lena
= 0, bitb
= 0, lenb
= 0;
355 if (a
== NULL
|| b
== NULL
)
358 /* Returning the intersect is not implemented yet. */
359 isns_assert(result
== NULL
);
362 enda
= runa
+ a
->ib_count
;
364 endb
= runb
+ b
->ib_count
;
394 /* range A ends before range B starts.
395 * Proceed to next run in vector A. */
406 /* range B ends before range A starts.
407 * Proceed to next run in vector B. */
416 isns_assert(bita
== bitb
);
418 while (lena
&& lenb
) {
421 intersect
= *wpa
& *wpb
;
428 uint32_t mask
= intersect
;
431 while (!(mask
& 1)) {
440 /* Append to result vector */
444 bita
+= 32; lena
-= 32; wpa
++;
445 bitb
+= 32; lenb
-= 32; wpb
++;
453 * Iterate over the bit vector
456 isns_bitvector_foreach(const isns_bitvector_t
*bv
,
457 int (*cb
)(uint32_t, void *),
463 end
= wp
+ bv
->ib_count
;
465 unsigned int base
, rlen
, bits
;
476 for (mask
= 1; mask
; mask
<<= 1, ++base
) {
481 isns_assert(wp
<= end
);
486 isns_bitvector_dump(const isns_bitvector_t
*bv
, isns_print_fn_t
*fn
)
490 fn("Bit Vector %p (%u words):", bv
, bv
->ib_count
);
493 end
= wp
+ bv
->ib_count
;
495 unsigned int base
, rlen
, bits
;
507 isns_assert(wp
<= end
);
510 if (bv
->ib_count
== 0)
516 __isns_bitvector_print_next(uint32_t first
, uint32_t last
,
519 switch (last
- first
) {
532 isns_bitvector_print(const isns_bitvector_t
*bv
,
535 uint32_t *wp
, *end
, first
= 0, next
= 0;
536 const char *sepa
= "";
539 end
= wp
+ bv
->ib_count
;
541 unsigned int base
, rlen
, bits
;
552 for (mask
= 1; mask
; mask
<<= 1, ++base
) {
556 fn("%s%u", sepa
, base
);
562 __isns_bitvector_print_next(first
, next
- 1, fn
);
567 isns_assert(wp
<= end
);
571 __isns_bitvector_print_next(first
, next
- 1, fn
);
582 isns_bitvector_t a
, b
;
585 isns_bitvector_init(&a
);
586 isns_bitvector_set_bit(&a
, 0);
587 isns_bitvector_dump(&a
, isns_print_stdout
);
588 isns_bitvector_set_bit(&a
, 1);
589 isns_bitvector_set_bit(&a
, 16);
590 isns_bitvector_set_bit(&a
, 32);
591 isns_bitvector_set_bit(&a
, 64);
592 isns_bitvector_dump(&a
, isns_print_stdout
);
593 isns_bitvector_set_bit(&a
, 8192);
594 isns_bitvector_set_bit(&a
, 8196);
595 isns_bitvector_set_bit(&a
, 8194);
596 isns_bitvector_dump(&a
, isns_print_stdout
);
597 isns_bitvector_set_bit(&a
, 2052);
598 isns_bitvector_set_bit(&a
, 2049);
599 isns_bitvector_set_bit(&a
, 2051);
600 isns_bitvector_set_bit(&a
, 2050);
601 isns_bitvector_dump(&a
, isns_print_stdout
);
602 isns_bitvector_print(&a
, isns_print_stdout
);
603 isns_bitvector_destroy(&a
);
605 isns_bitvector_init(&a
);
606 for (i
= 127; i
>= 0; --i
)
607 isns_bitvector_set_bit(&a
, i
);
608 isns_bitvector_dump(&a
, isns_print_stdout
);
609 printf("[Compacting]\n");
610 __isns_bitvector_compact(&a
);
611 isns_bitvector_dump(&a
, isns_print_stdout
);
612 isns_bitvector_print(&a
, isns_print_stdout
);
613 isns_bitvector_destroy(&a
);
615 isns_bitvector_init(&a
);
616 for (i
= 0; i
< 128; ++i
)
617 isns_bitvector_set_bit(&a
, i
);
618 isns_bitvector_dump(&a
, isns_print_stdout
);
619 isns_bitvector_print(&a
, isns_print_stdout
);
620 isns_bitvector_destroy(&a
);
622 isns_bitvector_init(&a
);
623 isns_bitvector_init(&b
);
624 isns_bitvector_set_bit(&a
, 0);
625 isns_bitvector_set_bit(&a
, 77);
626 isns_bitvector_set_bit(&a
, 249);
627 isns_bitvector_set_bit(&a
, 102);
629 isns_bitvector_set_bit(&b
, 1);
630 isns_bitvector_set_bit(&b
, 76);
631 isns_bitvector_set_bit(&b
, 250);
632 isns_bitvector_set_bit(&b
, 102);
633 i
= isns_bitvector_intersect(&a
, &b
, NULL
);
635 fprintf(stderr
, "*** BAD: Intersect should return 102 (got %d)! ***\n", i
);
637 printf("Intersect okay: %d\n", i
);
638 isns_bitvector_destroy(&a
);
639 isns_bitvector_destroy(&b
);
641 isns_bitvector_init(&a
);
642 isns_bitvector_set_bit(&a
, 0);
643 isns_bitvector_set_bit(&a
, 1);
644 isns_bitvector_clear_bit(&a
, 1);
645 isns_bitvector_clear_bit(&a
, 0);
646 isns_bitvector_dump(&a
, isns_print_stdout
);
647 isns_bitvector_print(&a
, isns_print_stdout
);
648 isns_bitvector_destroy(&a
);