4 #include "monobitset.h"
8 #define MONO_ZERO_LEN_ARRAY 0
10 #define MONO_ZERO_LEN_ARRAY 1
13 #define BITS_PER_CHUNK MONO_BITSET_BITS_PER_CHUNK
18 gsize data
[MONO_ZERO_LEN_ARRAY
];
22 * mono_bitset_alloc_size:
23 * @max_size: The numer of bits you want to hold
26 * Return the number of bytes required to hold the bitset.
27 * Useful to allocate it on the stack or with mempool.
28 * Use with mono_bitset_mem_new ().
31 mono_bitset_alloc_size (guint32 max_size
, guint32 flags
) {
32 guint32 real_size
= (max_size
+ BITS_PER_CHUNK
- 1) / BITS_PER_CHUNK
;
34 return sizeof (MonoBitSet
) + sizeof (gsize
) * (real_size
- MONO_ZERO_LEN_ARRAY
);
39 * @max_size: The numer of bits you want to hold
40 * @flags: bitfield of flags
42 * Return a bitset of size max_size. It must be freed using
46 mono_bitset_new (guint32 max_size
, guint32 flags
) {
47 guint32 real_size
= (max_size
+ BITS_PER_CHUNK
- 1) / BITS_PER_CHUNK
;
50 result
= g_malloc0 (sizeof (MonoBitSet
) + sizeof (gsize
) * (real_size
- MONO_ZERO_LEN_ARRAY
));
51 result
->size
= real_size
* BITS_PER_CHUNK
;
52 result
->flags
= flags
;
57 * mono_bitset_mem_new:
58 * @mem: The location the bitset is stored
59 * @max_size: The number of bits you want to hold
60 * @flags: bitfield of flags
62 * Return mem, which is now a initialized bitset of size max_size. It is
63 * not freed even if called with mono_bitset_free. mem must be at least
64 * as big as mono_bitset_alloc_size returns for the same max_size.
67 mono_bitset_mem_new (gpointer mem
, guint32 max_size
, guint32 flags
) {
68 guint32 real_size
= (max_size
+ BITS_PER_CHUNK
- 1) / BITS_PER_CHUNK
;
69 MonoBitSet
*result
= mem
;
71 result
->size
= real_size
* BITS_PER_CHUNK
;
72 result
->flags
= flags
| MONO_BITSET_DONT_FREE
;
78 * @set: bitset ptr to free
80 * Free bitset unless flags have MONO_BITSET_DONT_FREE set. Does not
81 * free anything if flag MONO_BITSET_DONT_FREE is set or bitset was
82 * made with mono_bitset_mem_new.
85 mono_bitset_free (MonoBitSet
*set
) {
86 if (!(set
->flags
& MONO_BITSET_DONT_FREE
))
93 * @pos: set bit at this pos
95 * Set bit at pos @pos, counting from 0.
98 mono_bitset_set (MonoBitSet
*set
, guint32 pos
) {
99 int j
= pos
/ BITS_PER_CHUNK
;
100 int bit
= pos
% BITS_PER_CHUNK
;
102 g_assert (pos
< set
->size
);
104 set
->data
[j
] |= (gsize
)1 << bit
;
110 * @pos: test bit at this pos
112 * Test bit at pos @pos, counting from 0.
113 * Returns a value != 0 if set, 0 otherwise.
116 mono_bitset_test (const MonoBitSet
*set
, guint32 pos
) {
117 int j
= pos
/ BITS_PER_CHUNK
;
118 int bit
= pos
% BITS_PER_CHUNK
;
120 g_return_val_if_fail (pos
< set
->size
, 0);
122 return (set
->data
[j
] & ((gsize
)1 << bit
)) > 0;
126 * mono_bitset_test_bulk:
128 * @pos: test bit at this pos
130 * Return 32/64 bits from the bitset, starting from @pos, which must be
131 * divisible with 32/64.
134 mono_bitset_test_bulk (const MonoBitSet
*set
, guint32 pos
) {
135 int j
= pos
/ BITS_PER_CHUNK
;
137 if (pos
>= set
->size
)
140 return set
->data
[j
];
146 * @pos: unset bit at this pos
148 * Unset bit at pos 'pos', counting from 0.
151 mono_bitset_clear (MonoBitSet
*set
, guint32 pos
) {
152 int j
= pos
/ BITS_PER_CHUNK
;
153 int bit
= pos
% BITS_PER_CHUNK
;
155 g_assert (pos
< set
->size
);
157 set
->data
[j
] &= ~((gsize
)1 << bit
);
161 * mono_bitset_clear_all:
167 mono_bitset_clear_all (MonoBitSet
*set
) {
168 memset (set
->data
, 0, set
->size
/ 8);
172 * mono_bitset_set_all:
178 mono_bitset_set_all (MonoBitSet
*set
) {
179 memset (set
->data
, -1, set
->size
/ 8);
183 * mono_bitset_invert:
189 mono_bitset_invert (MonoBitSet
*set
) {
191 for (i
= 0; i
< set
->size
/ BITS_PER_CHUNK
; ++i
)
192 set
->data
[i
] = ~set
->data
[i
];
199 * Returns the number of bits this bitset can hold.
202 mono_bitset_size (const MonoBitSet
*set
) {
207 * should test wich version is faster.
215 * return number of bits that is set.
218 mono_bitset_count (const MonoBitSet
*set
) {
223 for (i
= 0; i
< set
->size
/ BITS_PER_CHUNK
; ++i
) {
225 /* there is probably some asm code that can do this much faster */
227 #if SIZEOF_VOID_P == 8
228 /* http://www.jjj.de/bitwizardry/bitwizardrypage.html */
229 d
-= (d
>>1) & 0x5555555555555555;
230 d
= ((d
>>2) & 0x3333333333333333) + (d
& 0x3333333333333333);
231 d
= ((d
>>4) + d
) & 0x0f0f0f0f0f0f0f0f;
232 d
*= 0x0101010101010101;
235 /* http://aggregate.org/MAGIC/ */
236 d
-= ((d
>> 1) & 0x55555555);
237 d
= (((d
>> 2) & 0x33333333) + (d
& 0x33333333));
238 d
= (((d
>> 4) + d
) & 0x0f0f0f0f);
241 count
+= (d
& 0x0000003f);
249 mono_bitset_count (const MonoBitSet
*set
) {
250 static const guint32 table
[] = {
251 0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF
253 guint32 i
, count
, val
;
256 for (i
= 0; i
< set
->size
/ BITS_PER_CHUNK
;+i
) {
259 val
= (val
& table
[0]) ((val
>> 1) & table
[0]);
260 val
= (val
& table
[1]) ((val
>> 2) & table
[1]);
261 val
= (val
& table
[2]) ((val
>> 4) & table
[2]);
262 val
= (val
& table
[3]) ((val
>> 8) & table
[3]);
263 val
= (val
& table
[4]) ((val
>> 16) & table
[4]);
275 0xffffffff, 0xfffffffe, 0xfffffffc, 0xfffffff8,
276 0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80,
277 0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800,
278 0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000,
279 0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000,
280 0xfff00000, 0xffe00000, 0xffc00000, 0xff800000,
281 0xff000000, 0xfe000000, 0xfc000000, 0xf8000000,
282 0xf0000000, 0xe0000000, 0xc0000000, 0x80000000,
286 #define my_g_bit_nth_lsf(m,n) (ffs((m) & bitstart_mask [(n)+1])-1)
287 #define my_g_bit_nth_lsf_nomask(m) (ffs((m))-1)
292 my_g_bit_nth_lsf (gsize mask
, gint nth_bit
)
297 if ((mask
== 0) || (nth_bit
== BITS_PER_CHUNK
))
300 #if defined(__i386__) && defined(__GNUC__)
303 /* This depends on mask != 0 */
304 __asm__("bsfl %1,%0\n\t"
305 : "=r" (r
) : "g" (mask
));
308 #elif defined(__x86_64) && defined(__GNUC__)
312 __asm__("bsfq %1,%0\n\t"
313 : "=r" (r
) : "rm" (mask
));
317 while (! (mask
& 0x1)) {
327 my_g_bit_nth_lsf_nomask (gsize mask
)
329 /* Mask is expected to be != 0 */
330 #if defined(__i386__) && defined(__GNUC__)
333 __asm__("bsfl %1,%0\n\t"
334 : "=r" (r
) : "rm" (mask
));
336 #elif defined(__x86_64) && defined(__GNUC__)
339 __asm__("bsfq %1,%0\n\t"
340 : "=r" (r
) : "rm" (mask
));
345 while (! (mask
& 0x1)) {
357 my_g_bit_nth_msf (gsize mask
,
365 mask
<<= BITS_PER_CHUNK
- nth_bit
;
368 while ((i
> 0) && !(mask
>> (BITS_PER_CHUNK
- 8))) {
377 if (mask
& ((gsize
)1 << (BITS_PER_CHUNK
- 1)))
378 return i
- (BITS_PER_CHUNK
- nth_bit
);
387 find_first_unset (gulong mask
, gint nth_bit
)
391 if (!(mask
& ((gsize
)1 << nth_bit
))) {
392 if (nth_bit
== BITS_PER_CHUNK
)
393 /* On 64 bit platforms, 1 << 64 == 1 */
398 } while (nth_bit
< BITS_PER_CHUNK
);
403 * mono_bitset_find_start:
406 * Equivalent to mono_bitset_find_first (set, -1) but faster.
409 mono_bitset_find_start (const MonoBitSet
*set
)
413 for (i
= 0; i
< set
->size
/ BITS_PER_CHUNK
; ++i
) {
415 return my_g_bit_nth_lsf_nomask (set
->data
[i
]) + i
* BITS_PER_CHUNK
;
421 * mono_bitset_find_first:
423 * @pos: pos to search _after_ (not including)
425 * Returns position of first set bit after @pos. If pos < 0 begin search from
426 * start. Return -1 if no bit set is found.
429 mono_bitset_find_first (const MonoBitSet
*set
, gint pos
) {
438 j
= pos
/ BITS_PER_CHUNK
;
439 bit
= pos
% BITS_PER_CHUNK
;
440 g_assert (pos
< set
->size
);
442 /*g_print ("find first from %d (j: %d, bit: %d)\n", pos, j, bit);*/
445 result
= my_g_bit_nth_lsf (set
->data
[j
], bit
);
447 return result
+ j
* BITS_PER_CHUNK
;
449 for (i
= ++j
; i
< set
->size
/ BITS_PER_CHUNK
; ++i
) {
451 return my_g_bit_nth_lsf (set
->data
[i
], -1) + i
* BITS_PER_CHUNK
;
457 * mono_bitset_find_last:
459 * @pos: pos to search _before_ (not including)
461 * Returns position of last set bit before pos. If pos < 0 search is
462 * started from the end. Returns -1 if no set bit is found.
465 mono_bitset_find_last (const MonoBitSet
*set
, gint pos
) {
466 int j
, bit
, result
, i
;
471 j
= pos
/ BITS_PER_CHUNK
;
472 bit
= pos
% BITS_PER_CHUNK
;
474 g_return_val_if_fail (pos
< set
->size
, -1);
477 result
= my_g_bit_nth_msf (set
->data
[j
], bit
);
479 return result
+ j
* BITS_PER_CHUNK
;
481 for (i
= --j
; i
>= 0; --i
) {
483 return my_g_bit_nth_msf (set
->data
[i
], BITS_PER_CHUNK
) + i
* BITS_PER_CHUNK
;
489 * mono_bitset_find_first_unset:
491 * @pos: pos to search _after_ (not including)
493 * Returns position of first unset bit after @pos. If pos < 0 begin search from
494 * start. Return -1 if no bit set is found.
497 mono_bitset_find_first_unset (const MonoBitSet
*set
, gint pos
) {
506 j
= pos
/ BITS_PER_CHUNK
;
507 bit
= pos
% BITS_PER_CHUNK
;
508 g_return_val_if_fail (pos
< set
->size
, -1);
510 /*g_print ("find first from %d (j: %d, bit: %d)\n", pos, j, bit);*/
512 if (set
->data
[j
] != -1) {
513 result
= find_first_unset (set
->data
[j
], bit
);
515 return result
+ j
* BITS_PER_CHUNK
;
517 for (i
= ++j
; i
< set
->size
/ BITS_PER_CHUNK
; ++i
) {
518 if (set
->data
[i
] != -1) {
519 return find_first_unset (set
->data
[i
], -1) + i
* BITS_PER_CHUNK
;
527 * @set: bitset ptr to clone
528 * @new_size: number of bits the cloned bitset can hold
530 * Return a cloned bitset of size new_size. MONO_BITSET_DONT_FREE
531 * unset in cloned bitset. If new_size is 0, the cloned object is just
535 mono_bitset_clone (const MonoBitSet
*set
, guint32 new_size
) {
539 new_size
= set
->size
;
540 result
= mono_bitset_new (new_size
, set
->flags
);
541 result
->flags
&= ~MONO_BITSET_DONT_FREE
;
542 memcpy (result
->data
, set
->data
, set
->size
/ 8);
547 * mono_bitset_copyto:
548 * @src: bitset ptr to copy from
549 * @dest: bitset ptr to copy to
551 * Copy one bitset to another.
554 mono_bitset_copyto (const MonoBitSet
*src
, MonoBitSet
*dest
) {
555 g_assert (dest
->size
<= src
->size
);
557 memcpy (&dest
->data
, &src
->data
, dest
->size
/ 8);
562 * @dest: bitset ptr to hold union
563 * @src: bitset ptr to copy
565 * Make union of one bitset and another.
568 mono_bitset_union (MonoBitSet
*dest
, const MonoBitSet
*src
) {
571 g_assert (src
->size
<= dest
->size
);
573 for (i
= 0; i
< dest
->size
/ BITS_PER_CHUNK
; ++i
)
574 dest
->data
[i
] |= src
->data
[i
];
578 * mono_bitset_intersection:
579 * @dest: bitset ptr to hold intersection
580 * @src: bitset ptr to copy
582 * Make intersection of one bitset and another.
585 mono_bitset_intersection (MonoBitSet
*dest
, const MonoBitSet
*src
) {
588 g_assert (src
->size
<= dest
->size
);
590 for (i
= 0; i
< dest
->size
/ BITS_PER_CHUNK
; ++i
)
591 dest
->data
[i
] = dest
->data
[i
] & src
->data
[i
];
595 * mono_bitset_intersection_2:
596 * @dest: bitset ptr to hold intersection
597 * @src1: first bitset
598 * @src2: second bitset
600 * Make intersection of two bitsets
603 mono_bitset_intersection_2 (MonoBitSet
*dest
, const MonoBitSet
*src1
, const MonoBitSet
*src2
) {
606 g_assert (src1
->size
<= dest
->size
);
607 g_assert (src2
->size
<= dest
->size
);
609 for (i
= 0; i
< dest
->size
/ BITS_PER_CHUNK
; ++i
)
610 dest
->data
[i
] = src1
->data
[i
] & src2
->data
[i
];
615 * @dest: bitset ptr to hold bitset - src
616 * @src: bitset ptr to copy
618 * Unset all bits in dest, which are set in src.
621 mono_bitset_sub (MonoBitSet
*dest
, const MonoBitSet
*src
) {
624 g_assert (src
->size
<= dest
->size
);
626 for (i
= 0; i
< src
->size
/ BITS_PER_CHUNK
; ++i
)
627 dest
->data
[i
] &= ~src
->data
[i
];
635 * return TRUE if their size are the same and the same bits are set in
639 mono_bitset_equal (const MonoBitSet
*src
, const MonoBitSet
*src1
) {
641 if (src
->size
!= src1
->size
)
644 for (i
= 0; i
< src
->size
/ BITS_PER_CHUNK
; ++i
)
645 if (src
->data
[i
] != src1
->data
[i
])
651 * mono_bitset_foreach:
653 * @func: Function to call for every set bit
654 * @data: pass this as second arg to func
656 * Calls func for every bit set in bitset. Argument 1 is the number of
657 * the bit set, argument 2 is data
660 mono_bitset_foreach (MonoBitSet
*set
, MonoBitSetFunc func
, gpointer data
)
663 for (i
= 0; i
< set
->size
/ BITS_PER_CHUNK
; ++i
) {
665 for (j
= 0; j
< BITS_PER_CHUNK
; ++j
)
666 if (set
->data
[i
] & ((gsize
)1 << j
))
667 func (j
+ i
* BITS_PER_CHUNK
, data
);
676 * gcc -g -Wall -DTEST_BITSET -o monobitset monobitset.c `pkg-config --cflags --libs glib-2.0`
680 MonoBitSet
*set1
, *set2
, *set3
, *set4
;
684 set1
= mono_bitset_new (60, 0);
685 set4
= mono_bitset_new (60, 0);
687 if (mono_bitset_count (set1
) != 0)
691 mono_bitset_set (set1
, 33);
692 if (mono_bitset_count (set1
) != 1)
696 /* g_print("should be 33: %d\n", mono_bitset_find_first (set1, 0)); */
698 if (mono_bitset_find_first (set1
, 0) != 33)
702 if (mono_bitset_find_first (set1
, 33) != -1)
707 if (mono_bitset_find_first (set1
, -100) != 33)
711 if (mono_bitset_find_last (set1
, -1) != 33)
715 if (mono_bitset_find_last (set1
, 33) != -1)
719 if (mono_bitset_find_last (set1
, -100) != 33)
723 if (mono_bitset_find_last (set1
, 34) != 33)
728 if (!mono_bitset_test (set1
, 33))
732 if (mono_bitset_test (set1
, 32) || mono_bitset_test (set1
, 34))
736 set2
= mono_bitset_clone (set1
, 0);
737 if (mono_bitset_count (set2
) != 1)
741 mono_bitset_invert (set2
);
742 if (mono_bitset_count (set2
) != (mono_bitset_size (set2
) - 1))
746 mono_bitset_clear (set2
, 10);
747 if (mono_bitset_count (set2
) != (mono_bitset_size (set2
) - 2))
752 set3
= mono_bitset_clone (set2
, 0);
753 mono_bitset_union (set3
, set1
);
754 if (mono_bitset_count (set3
) != (mono_bitset_size (set3
) - 1))
758 mono_bitset_clear_all (set2
);
759 if (mono_bitset_count (set2
) != 0)
763 mono_bitset_invert (set2
);
764 if (mono_bitset_count (set2
) != mono_bitset_size (set2
))
768 mono_bitset_set (set4
, 0);
769 mono_bitset_set (set4
, 1);
770 mono_bitset_set (set4
, 10);
771 if (mono_bitset_count (set4
) != 3)
776 for (i
= mono_bitset_find_first (set4
, -1); i
!= -1; i
= mono_bitset_find_first (set4
, i
)) {
792 /* g_print ("count got: %d at %d\n", count, i); */
798 if (mono_bitset_find_first (set4
, -1) != 0)
803 mono_bitset_set (set4
, 31);
804 if (mono_bitset_find_first (set4
, 10) != 31)
808 mono_bitset_free (set1
);
810 set1
= mono_bitset_new (200, 0);
811 mono_bitset_set (set1
, 0);
812 mono_bitset_set (set1
, 1);
813 mono_bitset_set (set1
, 10);
814 mono_bitset_set (set1
, 31);
815 mono_bitset_set (set1
, 150);
817 mono_bitset_free (set1
);
818 mono_bitset_free (set2
);
819 mono_bitset_free (set3
);
820 mono_bitset_free (set4
);
822 g_print ("total tests passed: %d\n", error
- 1);