8 #include "monobitset.h"
11 #define BITS_PER_CHUNK MONO_BITSET_BITS_PER_CHUNK
14 * mono_bitset_alloc_size:
15 * \param max_size The number of bits you want to hold
17 * \returns the number of bytes required to hold the bitset.
18 * Useful to allocate it on the stack or with mempool.
19 * Use with \c mono_bitset_mem_new.
22 mono_bitset_alloc_size (guint32 max_size, guint32 flags) {
23 guint32 real_size = (max_size + BITS_PER_CHUNK - 1) / BITS_PER_CHUNK;
25 return sizeof (MonoBitSet) + sizeof (gsize) * (real_size - MONO_ZERO_LEN_ARRAY);
30 * \param max_size The numer of bits you want to hold
31 * \param flags bitfield of flags
32 * \returns a bitset of size \p max_size. It must be freed using
33 * \c mono_bitset_free.
36 mono_bitset_new (guint32 max_size, guint32 flags) {
37 guint32 real_size = (max_size + BITS_PER_CHUNK - 1) / BITS_PER_CHUNK;
40 result = (MonoBitSet *) g_malloc0 (sizeof (MonoBitSet) + sizeof (gsize) * (real_size - MONO_ZERO_LEN_ARRAY));
41 result->size = real_size * BITS_PER_CHUNK;
42 result->flags = flags;
47 * mono_bitset_mem_new:
48 * \param mem The location the bitset is stored
49 * \param max_size The number of bits you want to hold
50 * \param flags bitfield of flags
52 * Return \p mem, which is now a initialized bitset of size \p max_size. It is
53 * not freed even if called with \c mono_bitset_free. \p mem must be at least
54 * as big as \c mono_bitset_alloc_size returns for the same \p max_size.
57 mono_bitset_mem_new (gpointer mem, guint32 max_size, guint32 flags) {
58 guint32 real_size = (max_size + BITS_PER_CHUNK - 1) / BITS_PER_CHUNK;
59 MonoBitSet *result = (MonoBitSet *) mem;
61 result->size = real_size * BITS_PER_CHUNK;
62 result->flags = flags | MONO_BITSET_DONT_FREE;
68 * \param set bitset ptr to free
70 * Free bitset unless flags have \c MONO_BITSET_DONT_FREE set. Does not
71 * free anything if flag \c MONO_BITSET_DONT_FREE is set or bitset was
72 * made with \c mono_bitset_mem_new.
75 mono_bitset_free (MonoBitSet *set) {
76 if (!(set->flags & MONO_BITSET_DONT_FREE))
82 * \param set bitset ptr
83 * \param pos set bit at this pos
85 * Set bit at \p pos, counting from 0.
88 mono_bitset_set (MonoBitSet *set, guint32 pos) {
89 int j = pos / BITS_PER_CHUNK;
90 int bit = pos % BITS_PER_CHUNK;
92 g_assert (pos < set->size);
94 set->data [j] |= (gsize)1 << bit;
99 * \param set bitset ptr
100 * \param pos test bit at this pos
101 * Test bit at \p pos, counting from 0.
102 * \returns a nonzero value if set, 0 otherwise.
105 mono_bitset_test (const MonoBitSet *set, guint32 pos) {
106 int j = pos / BITS_PER_CHUNK;
107 int bit = pos % BITS_PER_CHUNK;
109 g_return_val_if_fail (pos < set->size, 0);
111 return (set->data [j] & ((gsize)1 << bit)) > 0;
115 * mono_bitset_test_bulk:
116 * \param set bitset ptr
117 * \param pos test bit at this pos
118 * \returns 32/64 bits from the bitset, starting from \p pos, which must be
119 * divisible with 32/64.
122 mono_bitset_test_bulk (const MonoBitSet *set, guint32 pos) {
123 int j = pos / BITS_PER_CHUNK;
125 if (pos >= set->size)
128 return set->data [j];
133 * \param set bitset ptr
134 * \param pos unset bit at this pos
136 * Unset bit at \p pos, counting from 0.
139 mono_bitset_clear (MonoBitSet *set, guint32 pos) {
140 int j = pos / BITS_PER_CHUNK;
141 int bit = pos % BITS_PER_CHUNK;
143 g_assert (pos < set->size);
145 set->data [j] &= ~((gsize)1 << bit);
149 * mono_bitset_clear_all:
150 * \param set bitset ptr
155 mono_bitset_clear_all (MonoBitSet *set) {
156 memset (set->data, 0, set->size / 8);
160 * mono_bitset_set_all:
161 * \param set bitset ptr
166 mono_bitset_set_all (MonoBitSet *set) {
167 memset (set->data, -1, set->size / 8);
171 * mono_bitset_invert:
172 * \param set bitset ptr
177 mono_bitset_invert (MonoBitSet *set) {
179 for (i = 0; i < set->size / BITS_PER_CHUNK; ++i)
180 set->data [i] = ~set->data [i];
185 * \param set bitset ptr
186 * \returns the number of bits this bitset can hold.
189 mono_bitset_size (const MonoBitSet *set) {
194 * should test wich version is faster.
200 * \param set bitset ptr
201 * \returns number of bits that are set.
204 mono_bitset_count (const MonoBitSet *set) {
209 for (i = 0; i < set->size / BITS_PER_CHUNK; ++i) {
212 if (sizeof (gsize) == sizeof (unsigned int))
213 count += __builtin_popcount (d);
215 count += __builtin_popcountll (d);
227 mono_bitset_count (const MonoBitSet *set) {
228 static const guint32 table [] = {
229 0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF
231 guint32 i, count, val;
234 for (i = 0; i < set->size / BITS_PER_CHUNK;+i) {
237 val = (val & table [0]) ((val >> 1) & table [0]);
238 val = (val & table [1]) ((val >> 2) & table [1]);
239 val = (val & table [2]) ((val >> 4) & table [2]);
240 val = (val & table [3]) ((val >> 8) & table [3]);
241 val = (val & table [4]) ((val >> 16) & table [4]);
253 0xffffffff, 0xfffffffe, 0xfffffffc, 0xfffffff8,
254 0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80,
255 0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800,
256 0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000,
257 0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000,
258 0xfff00000, 0xffe00000, 0xffc00000, 0xff800000,
259 0xff000000, 0xfe000000, 0xfc000000, 0xf8000000,
260 0xf0000000, 0xe0000000, 0xc0000000, 0x80000000,
264 #define my_g_bit_nth_lsf(m,n) (ffs((m) & bitstart_mask [(n)+1])-1)
265 #define my_g_bit_nth_lsf_nomask(m) (ffs((m))-1)
270 my_g_bit_nth_lsf (gsize mask, gint nth_bit)
275 if ((mask == 0) || (nth_bit == BITS_PER_CHUNK))
278 #if (defined(__i386__) && defined(__GNUC__))
281 /* This depends on mask != 0 */
282 __asm__("bsfl %1,%0\n\t"
283 : "=r" (r) : "g" (mask));
286 #elif defined(__x86_64) && defined(__GNUC__)
290 __asm__("bsfq %1,%0\n\t"
291 : "=r" (r) : "rm" (mask));
295 while (! (mask & 0x1)) {
305 my_g_bit_nth_lsf_nomask (gsize mask)
307 /* Mask is expected to be != 0 */
308 #if (defined(__i386__) && defined(__GNUC__))
311 __asm__("bsfl %1,%0\n\t"
312 : "=r" (r) : "rm" (mask));
314 #elif defined(__x86_64) && defined(__GNUC__)
317 __asm__("bsfq %1,%0\n\t"
318 : "=r" (r) : "rm" (mask));
323 while (! (mask & 0x1)) {
335 my_g_bit_nth_msf (gsize mask,
343 mask <<= BITS_PER_CHUNK - nth_bit;
346 while ((i > 0) && !(mask >> (BITS_PER_CHUNK - 8))) {
355 if (mask & ((gsize)1 << (BITS_PER_CHUNK - 1)))
356 return i - (BITS_PER_CHUNK - nth_bit);
365 find_first_unset (gsize mask, gint nth_bit)
369 if (!(mask & ((gsize)1 << nth_bit))) {
370 if (nth_bit == BITS_PER_CHUNK)
371 /* On 64 bit platforms, 1 << 64 == 1 */
376 } while (nth_bit < BITS_PER_CHUNK);
381 * mono_bitset_find_start:
382 * \param set bitset ptr
383 * Equivalent to <code>mono_bitset_find_first (set, -1)</code> but faster.
386 mono_bitset_find_start (const MonoBitSet *set)
390 for (i = 0; i < set->size / BITS_PER_CHUNK; ++i) {
392 return my_g_bit_nth_lsf_nomask (set->data [i]) + i * BITS_PER_CHUNK;
398 * mono_bitset_find_first:
399 * \param set bitset ptr
400 * \param pos pos to search after (not including)
401 * \returns position of first set bit after \p pos. If \p pos < 0, begin search from
402 * start. Return \c -1 if no bit set is found.
405 mono_bitset_find_first (const MonoBitSet *set, gint pos) {
414 j = pos / BITS_PER_CHUNK;
415 bit = pos % BITS_PER_CHUNK;
416 g_assert (pos < set->size);
418 /*g_print ("find first from %d (j: %d, bit: %d)\n", pos, j, bit);*/
421 result = my_g_bit_nth_lsf (set->data [j], bit);
423 return result + j * BITS_PER_CHUNK;
425 for (i = ++j; i < set->size / BITS_PER_CHUNK; ++i) {
427 return my_g_bit_nth_lsf (set->data [i], -1) + i * BITS_PER_CHUNK;
433 * mono_bitset_find_last:
434 * \param set bitset ptr
435 * \param pos pos to search before (not including)
436 * \returns position of last set bit before \p pos. If \p pos < 0 search is
437 * started from the end. Returns \c -1 if no set bit is found.
440 mono_bitset_find_last (const MonoBitSet *set, gint pos) {
441 int j, bit, result, i;
446 j = pos / BITS_PER_CHUNK;
447 bit = pos % BITS_PER_CHUNK;
449 g_return_val_if_fail (pos < set->size, -1);
452 result = my_g_bit_nth_msf (set->data [j], bit);
454 return result + j * BITS_PER_CHUNK;
456 for (i = --j; i >= 0; --i) {
458 return my_g_bit_nth_msf (set->data [i], BITS_PER_CHUNK) + i * BITS_PER_CHUNK;
464 * mono_bitset_find_first_unset:
465 * \param set bitset ptr
466 * \param pos pos to search after (not including)
467 * \returns position of first unset bit after \p pos. If \p pos < 0 begin search from
468 * start. Return \c -1 if no bit set is found.
471 mono_bitset_find_first_unset (const MonoBitSet *set, gint pos) {
480 j = pos / BITS_PER_CHUNK;
481 bit = pos % BITS_PER_CHUNK;
482 g_return_val_if_fail (pos < set->size, -1);
484 /*g_print ("find first from %d (j: %d, bit: %d)\n", pos, j, bit);*/
486 if (set->data [j] != -1) {
487 result = find_first_unset (set->data [j], bit);
489 return result + j * BITS_PER_CHUNK;
491 for (i = ++j; i < set->size / BITS_PER_CHUNK; ++i) {
492 if (set->data [i] != -1) {
493 return find_first_unset (set->data [i], -1) + i * BITS_PER_CHUNK;
501 * \param set bitset ptr to clone
502 * \param new_size number of bits the cloned bitset can hold
503 * \returns a cloned bitset of size \p new_size. \c MONO_BITSET_DONT_FREE
504 * unset in cloned bitset. If \p new_size is 0, the cloned object is just
508 mono_bitset_clone (const MonoBitSet *set, guint32 new_size) {
512 new_size = set->size;
513 result = mono_bitset_new (new_size, set->flags);
514 result->flags &= ~MONO_BITSET_DONT_FREE;
515 memcpy (result->data, set->data, set->size / 8);
520 * mono_bitset_copyto:
521 * \param src bitset ptr to copy from
522 * \param dest bitset ptr to copy to
524 * Copy one bitset to another.
527 mono_bitset_copyto (const MonoBitSet *src, MonoBitSet *dest) {
528 g_assert (dest->size <= src->size);
530 memcpy (&dest->data, &src->data, dest->size / 8);
535 * \param dest bitset ptr to hold union
536 * \param src bitset ptr to copy
538 * Make union of one bitset and another.
541 mono_bitset_union (MonoBitSet *dest, const MonoBitSet *src) {
544 g_assert (src->size <= dest->size);
546 size = dest->size / BITS_PER_CHUNK;
547 for (i = 0; i < size; ++i)
548 dest->data [i] |= src->data [i];
552 * mono_bitset_intersection:
553 * \param dest bitset ptr to hold intersection
554 * \param src bitset ptr to copy
556 * Make intersection of one bitset and another.
559 mono_bitset_intersection (MonoBitSet *dest, const MonoBitSet *src) {
562 g_assert (src->size <= dest->size);
564 size = dest->size / BITS_PER_CHUNK;
565 for (i = 0; i < size; ++i)
566 dest->data [i] &= src->data [i];
570 * mono_bitset_intersection_2:
571 * \param dest bitset ptr to hold intersection
572 * \param src1 first bitset
573 * \param src2 second bitset
575 * Make intersection of two bitsets
578 mono_bitset_intersection_2 (MonoBitSet *dest, const MonoBitSet *src1, const MonoBitSet *src2) {
581 g_assert (src1->size <= dest->size);
582 g_assert (src2->size <= dest->size);
584 size = dest->size / BITS_PER_CHUNK;
585 for (i = 0; i < size; ++i)
586 dest->data [i] = src1->data [i] & src2->data [i];
591 * \param dest bitset ptr to hold bitset - src
592 * \param src bitset ptr to copy
594 * Unset all bits in \p dest that are set in \p src.
597 mono_bitset_sub (MonoBitSet *dest, const MonoBitSet *src) {
600 g_assert (src->size <= dest->size);
602 size = src->size / BITS_PER_CHUNK;
603 for (i = 0; i < size; ++i)
604 dest->data [i] &= ~src->data [i];
609 * \param src bitset ptr
610 * \param src1 bitset ptr
611 * \returns TRUE if their size are the same and the same bits are set in
615 mono_bitset_equal (const MonoBitSet *src, const MonoBitSet *src1) {
617 if (src->size != src1->size)
620 for (i = 0; i < src->size / BITS_PER_CHUNK; ++i)
621 if (src->data [i] != src1->data [i])
627 * mono_bitset_foreach:
628 * \param set bitset ptr
629 * \param func Function to call for every set bit
630 * \param data pass this as second arg to func
631 * Calls \p func for every bit set in bitset. Argument 1 is the number of
632 * the bit set, argument 2 is data
635 mono_bitset_foreach (MonoBitSet *set, MonoBitSetFunc func, gpointer data)
638 for (i = 0; i < set->size / BITS_PER_CHUNK; ++i) {
640 for (j = 0; j < BITS_PER_CHUNK; ++j)
641 if (set->data [i] & ((gsize)1 << j))
642 func (j + i * BITS_PER_CHUNK, data);
651 * gcc -g -Wall -DTEST_BITSET -o monobitset monobitset.c `pkg-config --cflags --libs glib-2.0`
655 MonoBitSet *set1, *set2, *set3, *set4;
659 set1 = mono_bitset_new (60, 0);
660 set4 = mono_bitset_new (60, 0);
662 if (mono_bitset_count (set1) != 0)
666 mono_bitset_set (set1, 33);
667 if (mono_bitset_count (set1) != 1)
671 /* g_print("should be 33: %d\n", mono_bitset_find_first (set1, 0)); */
673 if (mono_bitset_find_first (set1, 0) != 33)
677 if (mono_bitset_find_first (set1, 33) != -1)
682 if (mono_bitset_find_first (set1, -100) != 33)
686 if (mono_bitset_find_last (set1, -1) != 33)
690 if (mono_bitset_find_last (set1, 33) != -1)
694 if (mono_bitset_find_last (set1, -100) != 33)
698 if (mono_bitset_find_last (set1, 34) != 33)
703 if (!mono_bitset_test (set1, 33))
707 if (mono_bitset_test (set1, 32) || mono_bitset_test (set1, 34))
711 set2 = mono_bitset_clone (set1, 0);
712 if (mono_bitset_count (set2) != 1)
716 mono_bitset_invert (set2);
717 if (mono_bitset_count (set2) != (mono_bitset_size (set2) - 1))
721 mono_bitset_clear (set2, 10);
722 if (mono_bitset_count (set2) != (mono_bitset_size (set2) - 2))
727 set3 = mono_bitset_clone (set2, 0);
728 mono_bitset_union (set3, set1);
729 if (mono_bitset_count (set3) != (mono_bitset_size (set3) - 1))
733 mono_bitset_clear_all (set2);
734 if (mono_bitset_count (set2) != 0)
738 mono_bitset_invert (set2);
739 if (mono_bitset_count (set2) != mono_bitset_size (set2))
743 mono_bitset_set (set4, 0);
744 mono_bitset_set (set4, 1);
745 mono_bitset_set (set4, 10);
746 if (mono_bitset_count (set4) != 3)
751 for (i = mono_bitset_find_first (set4, -1); i != -1; i = mono_bitset_find_first (set4, i)) {
767 /* g_print ("count got: %d at %d\n", count, i); */
773 if (mono_bitset_find_first (set4, -1) != 0)
778 mono_bitset_set (set4, 31);
779 if (mono_bitset_find_first (set4, 10) != 31)
783 mono_bitset_free (set1);
785 set1 = mono_bitset_new (200, 0);
786 mono_bitset_set (set1, 0);
787 mono_bitset_set (set1, 1);
788 mono_bitset_set (set1, 10);
789 mono_bitset_set (set1, 31);
790 mono_bitset_set (set1, 150);
792 mono_bitset_free (set1);
793 mono_bitset_free (set2);
794 mono_bitset_free (set3);
795 mono_bitset_free (set4);
797 g_print ("total tests passed: %d\n", error - 1);