4 #include "monobitset.h"
7 #define MONO_ZERO_LEN_ARRAY 0
9 #define MONO_ZERO_LEN_ARRAY 1
12 #define BITS_PER_CHUNK (8 * sizeof (guint32))
17 guint32 data [MONO_ZERO_LEN_ARRAY];
21 * mono_bitset_alloc_size:
22 * @max_size: The numer of bits you want to hold
25 * Return the number of bytes required to hold the bitset.
26 * Useful to allocate it on the stack or with mempool.
27 * Use with mono_bitset_mem_new ().
30 mono_bitset_alloc_size (guint32 max_size, guint32 flags) {
31 guint32 real_size = (max_size + BITS_PER_CHUNK - 1) / BITS_PER_CHUNK;
33 return sizeof (MonoBitSet) + sizeof (guint32) * (real_size - MONO_ZERO_LEN_ARRAY);
38 * @max_size: The numer of bits you want to hold
39 * @flags: bitfield of flags
41 * Return a bitset of size max_size. It must be freed using
45 mono_bitset_new (guint32 max_size, guint32 flags) {
46 guint32 real_size = (max_size + BITS_PER_CHUNK - 1) / BITS_PER_CHUNK;
49 result = g_malloc0 (sizeof (MonoBitSet) + sizeof (guint32) * (real_size - MONO_ZERO_LEN_ARRAY));
50 result->size = real_size * BITS_PER_CHUNK;
51 result->flags = flags;
56 * mono_bitset_mem_new:
57 * @mem: The location the bitset is stored
58 * @max_size: The number of bits you want to hold
59 * @flags: bitfield of flags
61 * Return mem, which is now a initialized bitset of size max_size. It is
62 * not freed even if called with mono_bitset_free. mem must be at least
63 * as big as mono_bitset_alloc_size returns for the same max_size.
66 mono_bitset_mem_new (gpointer mem, guint32 max_size, guint32 flags) {
67 guint32 real_size = (max_size + BITS_PER_CHUNK - 1) / BITS_PER_CHUNK;
68 MonoBitSet *result = mem;
70 result->size = real_size * BITS_PER_CHUNK;
71 result->flags = flags | MONO_BITSET_DONT_FREE;
77 * @set: bitset ptr to free
79 * Free bitset unless flags have MONO_BITSET_DONT_FREE set. Does not
80 * free anything if flag MONO_BITSET_DONT_FREE is set or bitset was
81 * made with mono_bitset_mem_new.
84 mono_bitset_free (MonoBitSet *set) {
85 if (!(set->flags & MONO_BITSET_DONT_FREE))
92 * @pos: set bit at this pos
94 * Set bit at pos @pos, counting from 0.
97 mono_bitset_set (MonoBitSet *set, guint32 pos) {
98 int j = pos / BITS_PER_CHUNK;
99 int bit = pos % BITS_PER_CHUNK;
101 g_return_if_fail (pos < set->size);
103 set->data [j] |= 1 << bit;
109 * @pos: test bit at this pos
111 * Test bit at pos @pos, counting from 0.
112 * Returns a value != 0 if set, 0 otherwise.
115 mono_bitset_test (const MonoBitSet *set, guint32 pos) {
116 int j = pos / BITS_PER_CHUNK;
117 int bit = pos % BITS_PER_CHUNK;
119 g_return_val_if_fail (pos < set->size, 0);
121 return set->data [j] & (1 << bit);
125 * mono_bitset_test_bulk:
127 * @pos: test bit at this pos
129 * Return 32 bits from the bitset, starting from @pos, which must be divisible
133 mono_bitset_test_bulk (const MonoBitSet *set, guint32 pos) {
134 int j = pos / BITS_PER_CHUNK;
136 if (pos >= set->size)
139 return set->data [j];
145 * @pos: unset bit at this pos
147 * Unset bit at pos 'pos', counting from 0.
150 mono_bitset_clear (MonoBitSet *set, guint32 pos) {
151 int j = pos / BITS_PER_CHUNK;
152 int bit = pos % BITS_PER_CHUNK;
154 g_return_if_fail (pos < set->size);
156 set->data [j] &= ~(1 << bit);
160 * mono_bitset_clear_all:
166 mono_bitset_clear_all (MonoBitSet *set) {
168 for (i = 0; i < set->size / BITS_PER_CHUNK; ++i)
173 * mono_bitset_set_all:
179 mono_bitset_set_all (MonoBitSet *set) {
181 for (i = 0; i < set->size / BITS_PER_CHUNK; ++i)
182 set->data [i] = 0xffffffff;
186 * mono_bitset_invert:
192 mono_bitset_invert (MonoBitSet *set) {
194 for (i = 0; i < set->size / BITS_PER_CHUNK; ++i)
195 set->data [i] = ~set->data [i];
202 * Returns the number of bits this bitset can hold.
205 mono_bitset_size (const MonoBitSet *set) {
210 * should test wich version is faster.
218 * return number of bits that is set.
221 mono_bitset_count (const MonoBitSet *set) {
222 static const unsigned char table [16] = {
223 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
226 const unsigned char *b;
229 for (i = 0; i < set->size / BITS_PER_CHUNK; ++i) {
230 /* there is probably some asm code that can do this much faster */
232 b = (unsigned char*) (set->data + i);
233 count += table [b [0] & 0xf];
234 count += table [b [0] >> 4];
235 count += table [b [1] & 0xf];
236 count += table [b [1] >> 4];
237 count += table [b [2] & 0xf];
238 count += table [b [2] >> 4];
239 count += table [b [3] & 0xf];
240 count += table [b [3] >> 4];
247 mono_bitset_count (const MonoBitSet *set) {
248 static const guint32 table [] = {
249 0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF
251 guint32 i, count, val;
254 for (i = 0; i < set->size / BITS_PER_CHUNK;+i) {
257 val = (val & table [0]) ((val >> 1) & table [0]);
258 val = (val & table [1]) ((val >> 2) & table [1]);
259 val = (val & table [2]) ((val >> 4) & table [2]);
260 val = (val & table [3]) ((val >> 8) & table [3]);
261 val = (val & table [4]) ((val >> 16) & table [4]);
273 0xffffffff, 0xfffffffe, 0xfffffffc, 0xfffffff8,
274 0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80,
275 0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800,
276 0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000,
277 0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000,
278 0xfff00000, 0xffe00000, 0xffc00000, 0xff800000,
279 0xff000000, 0xfe000000, 0xfc000000, 0xf8000000,
280 0xf0000000, 0xe0000000, 0xc0000000, 0x80000000,
284 #define my_g_bit_nth_lsf(m,n) (ffs((m) & bitstart_mask [(n)+1])-1)
285 #define my_g_bit_nth_lsf_nomask(m) (ffs((m))-1)
289 my_g_bit_nth_lsf (guint32 mask, gint nth_bit)
293 if (mask & (1 << (gulong) nth_bit))
295 } while (nth_bit < 31);
298 #define my_g_bit_nth_lsf_nomask(m) (my_g_bit_nth_lsf((m),-1))
302 * mono_bitset_find_start:
305 * Equivalent to mono_bitset_find_first (set, -1) but faster.
308 mono_bitset_find_start (const MonoBitSet *set)
312 for (i = 0; i < set->size / BITS_PER_CHUNK; ++i) {
314 return my_g_bit_nth_lsf_nomask (set->data [i]) + i * BITS_PER_CHUNK;
320 * mono_bitset_find_first:
322 * @pos: pos to search _after_ (not including)
324 * Returns position of first set bit after @pos. If pos < 0 begin search from
325 * start. Return -1 if no bit set is found.
328 mono_bitset_find_first (const MonoBitSet *set, gint pos) {
337 j = pos / BITS_PER_CHUNK;
338 bit = pos % BITS_PER_CHUNK;
339 g_return_val_if_fail (pos < set->size, -1);
341 /*g_print ("find first from %d (j: %d, bit: %d)\n", pos, j, bit);*/
344 result = my_g_bit_nth_lsf (set->data [j], bit);
346 return result + j * BITS_PER_CHUNK;
348 for (i = ++j; i < set->size / BITS_PER_CHUNK; ++i) {
350 return my_g_bit_nth_lsf (set->data [i], -1) + i * BITS_PER_CHUNK;
356 * mono_bitset_find_last:
358 * @pos: pos to search _before_ (not including)
360 * Returns position of last set bit before pos. If pos < 0 search is
361 * started from the end. Returns -1 if no set bit is found.
364 mono_bitset_find_last (const MonoBitSet *set, gint pos) {
365 int j, bit, result, i;
370 j = pos / BITS_PER_CHUNK;
371 bit = pos % BITS_PER_CHUNK;
373 g_return_val_if_fail (pos < set->size, -1);
376 result = g_bit_nth_msf (set->data [j], bit);
378 return result + j * BITS_PER_CHUNK;
380 for (i = --j; i >= 0; --i) {
382 return g_bit_nth_msf (set->data [i], -1) + i * BITS_PER_CHUNK;
389 * @set: bitset ptr to clone
390 * @new_size: number of bits the cloned bitset can hold
392 * Return a cloned bitset of size new_size. MONO_BITSET_DONT_FREE
393 * unset in cloned bitset. If new_size is 0, the cloned object is just
397 mono_bitset_clone (const MonoBitSet *set, guint32 new_size) {
401 new_size = set->size;
402 result = mono_bitset_new (new_size, set->flags);
403 result->flags &= ~MONO_BITSET_DONT_FREE;
404 memcpy (result->data, set->data, set->size / 8);
409 * mono_bitset_copyto:
410 * @src: bitset ptr to copy from
411 * @dest: bitset ptr to copy to
413 * Copy one bitset to another.
416 mono_bitset_copyto (const MonoBitSet *src, MonoBitSet *dest) {
419 g_return_if_fail (dest->size <= src->size);
421 for (i = 0; i < dest->size / BITS_PER_CHUNK; ++i)
422 dest->data [i] = src->data [i];
427 * @dest: bitset ptr to hold union
428 * @src: bitset ptr to copy
430 * Make union of one bitset and another.
433 mono_bitset_union (MonoBitSet *dest, const MonoBitSet *src) {
436 g_return_if_fail (src->size <= dest->size);
438 for (i = 0; i < dest->size / BITS_PER_CHUNK; ++i)
439 dest->data [i] |= src->data [i];
443 * mono_bitset_intersection:
444 * @dest: bitset ptr to hold intersection
445 * @src: bitset ptr to copy
447 * Make intersection of one bitset and another.
450 mono_bitset_intersection (MonoBitSet *dest, const MonoBitSet *src) {
453 g_return_if_fail (src->size <= dest->size);
455 for (i = 0; i < dest->size / BITS_PER_CHUNK; ++i)
456 dest->data [i] = dest->data [i] & src->data [i];
461 * @dest: bitset ptr to hold bitset - src
462 * @src: bitset ptr to copy
464 * Unset all bits in dest, which are set in src.
467 mono_bitset_sub (MonoBitSet *dest, const MonoBitSet *src) {
470 g_return_if_fail (src->size <= dest->size);
472 for (i = 0; i < dest->size / BITS_PER_CHUNK; ++i)
473 dest->data [i] &= ~src->data [i];
481 * return TRUE if their size are the same and the same bits are set in
485 mono_bitset_equal (const MonoBitSet *src, const MonoBitSet *src1) {
487 if (src->size != src1->size)
490 for (i = 0; i < src->size / BITS_PER_CHUNK; ++i)
491 if (src->data [i] != src1->data [i])
497 * mono_bitset_foreach:
499 * @func: Function to call for every set bit
500 * @data: pass this as second arg to func
502 * Calls func for every bit set in bitset. Argument 1 is the number of
503 * the bit set, argument 2 is data
506 mono_bitset_foreach (MonoBitSet *set, MonoBitSetFunc func, gpointer data)
509 for (i = 0; i < set->size / BITS_PER_CHUNK; ++i) {
511 for (j = 0; j < BITS_PER_CHUNK; ++j)
512 if (set->data [i] & (1 << j))
513 func (j + i * BITS_PER_CHUNK, data);
522 * gcc -g -Wall -DTEST_BITSET -o monobitset monobitset.c `pkg-config --cflags --libs glib-2.0`
526 MonoBitSet *set1, *set2, *set3, *set4;
530 set1 = mono_bitset_new (60, 0);
531 set4 = mono_bitset_new (60, 0);
533 if (mono_bitset_count (set1) != 0)
537 mono_bitset_set (set1, 33);
538 if (mono_bitset_count (set1) != 1)
542 //g_print("should be 33: %d\n", mono_bitset_find_first (set1, 0));
544 if (mono_bitset_find_first (set1, 0) != 33)
548 if (mono_bitset_find_first (set1, 33) != -1)
553 if (mono_bitset_find_first (set1, -100) != 33)
557 if (mono_bitset_find_last (set1, -1) != 33)
561 if (mono_bitset_find_last (set1, 33) != -1)
565 if (mono_bitset_find_last (set1, -100) != 33)
569 if (mono_bitset_find_last (set1, 34) != 33)
574 if (!mono_bitset_test (set1, 33))
578 if (mono_bitset_test (set1, 32) || mono_bitset_test (set1, 34))
582 set2 = mono_bitset_clone (set1, 0);
583 if (mono_bitset_count (set2) != 1)
587 mono_bitset_invert (set2);
588 if (mono_bitset_count (set2) != (mono_bitset_size (set2) - 1))
592 mono_bitset_clear (set2, 10);
593 if (mono_bitset_count (set2) != (mono_bitset_size (set2) - 2))
598 set3 = mono_bitset_clone (set2, 0);
599 mono_bitset_union (set3, set1);
600 if (mono_bitset_count (set3) != (mono_bitset_size (set3) - 1))
604 mono_bitset_clear_all (set2);
605 if (mono_bitset_count (set2) != 0)
609 mono_bitset_invert (set2);
610 if (mono_bitset_count (set2) != mono_bitset_size (set2))
614 mono_bitset_set (set4, 0);
615 mono_bitset_set (set4, 1);
616 mono_bitset_set (set4, 10);
617 if (mono_bitset_count (set4) != 3)
622 for (i = mono_bitset_find_first (set4, -1); i != -1; i = mono_bitset_find_first (set4, i)) {
638 //g_print ("count got: %d at %d\n", count, i);
644 if (mono_bitset_find_first (set4, -1) != 0)
649 mono_bitset_set (set4, 31);
650 if (mono_bitset_find_first (set4, 10) != 31)
654 mono_bitset_free (set1);
656 set1 = mono_bitset_new (200, 0);
657 mono_bitset_set (set1, 0);
658 mono_bitset_set (set1, 1);
659 mono_bitset_set (set1, 10);
660 mono_bitset_set (set1, 31);
661 mono_bitset_set (set1, 150);
663 mono_bitset_free (set1);
664 mono_bitset_free (set2);
665 mono_bitset_free (set3);
666 mono_bitset_free (set4);
668 g_print ("total tests passed: %d\n", error - 1);