2007-01-04 Miguel de Icaza <miguel@novell.com>
[mono-project.git] / mono / utils / monobitset.c
blob48ceb714bd44e42bef208082fcc8a633e69c43b9
1 #include <glib.h>
2 #include <string.h>
4 #include "monobitset.h"
5 #include "config.h"
7 #ifdef __GNUC__
8 #define MONO_ZERO_LEN_ARRAY 0
9 #else
10 #define MONO_ZERO_LEN_ARRAY 1
11 #endif
13 #define BITS_PER_CHUNK MONO_BITSET_BITS_PER_CHUNK
15 struct MonoBitSet {
16 gsize size;
17 gsize flags;
18 gsize data [MONO_ZERO_LEN_ARRAY];
22 * mono_bitset_alloc_size:
23 * @max_size: The numer of bits you want to hold
24 * @flags: unused
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 ().
30 guint32
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);
38 * mono_bitset_new:
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
43 * mono_bitset_free.
45 MonoBitSet *
46 mono_bitset_new (guint32 max_size, guint32 flags) {
47 guint32 real_size = (max_size + BITS_PER_CHUNK - 1) / BITS_PER_CHUNK;
48 MonoBitSet *result;
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;
53 return result;
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.
66 MonoBitSet *
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;
73 return result;
77 * mono_bitset_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.
84 void
85 mono_bitset_free (MonoBitSet *set) {
86 if (!(set->flags & MONO_BITSET_DONT_FREE))
87 g_free (set);
91 * mono_bitset_set:
92 * @set: bitset ptr
93 * @pos: set bit at this pos
95 * Set bit at pos @pos, counting from 0.
97 void
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;
108 * mono_bitset_test:
109 * @set: bitset ptr
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:
127 * @set: bitset ptr
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.
133 gsize
134 mono_bitset_test_bulk (const MonoBitSet *set, guint32 pos) {
135 int j = pos / BITS_PER_CHUNK;
137 if (pos >= set->size)
138 return 0;
139 else
140 return set->data [j];
144 * mono_bitset_clear:
145 * @set: bitset ptr
146 * @pos: unset bit at this pos
148 * Unset bit at pos 'pos', counting from 0.
150 void
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:
162 * @set: bitset ptr
164 * Unset all bits.
166 void
167 mono_bitset_clear_all (MonoBitSet *set) {
168 memset (set->data, 0, set->size / 8);
172 * mono_bitset_set_all:
173 * @set: bitset ptr
175 * Set all bits.
177 void
178 mono_bitset_set_all (MonoBitSet *set) {
179 memset (set->data, -1, set->size / 8);
183 * mono_bitset_invert:
184 * @set: bitset ptr
186 * Flip all bits.
188 void
189 mono_bitset_invert (MonoBitSet *set) {
190 int i;
191 for (i = 0; i < set->size / BITS_PER_CHUNK; ++i)
192 set->data [i] = ~set->data [i];
196 * mono_bitset_size:
197 * @set: bitset ptr
199 * Returns the number of bits this bitset can hold.
201 guint32
202 mono_bitset_size (const MonoBitSet *set) {
203 return set->size;
207 * should test wich version is faster.
209 #if 1
212 * mono_bitset_count:
213 * @set: bitset ptr
215 * return number of bits that is set.
217 guint32
218 mono_bitset_count (const MonoBitSet *set) {
219 guint32 i, count;
220 gsize d;
222 count = 0;
223 for (i = 0; i < set->size / BITS_PER_CHUNK; ++i) {
224 d = set->data [i];
225 /* there is probably some asm code that can do this much faster */
226 if (d) {
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;
233 count += d >> 56;
234 #else
235 /* http://aggregate.org/MAGIC/ */
236 d -= ((d >> 1) & 0x55555555);
237 d = (((d >> 2) & 0x33333333) + (d & 0x33333333));
238 d = (((d >> 4) + d) & 0x0f0f0f0f);
239 d += (d >> 8);
240 d += (d >> 16);
241 count += (d & 0x0000003f);
242 #endif
245 return count;
247 #else
248 guint32
249 mono_bitset_count (const MonoBitSet *set) {
250 static const guint32 table [] = {
251 0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF
253 guint32 i, count, val;
255 count = 0;
256 for (i = 0; i < set->size / BITS_PER_CHUNK;+i) {
257 if (set->data [i]) {
258 val = set->data [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]);
264 count += val;
267 return count;
270 #endif
272 #if 0
273 const static int
274 bitstart_mask [] = {
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,
283 0x00000000
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)
289 #else
291 static inline gint
292 my_g_bit_nth_lsf (gsize mask, gint nth_bit)
294 nth_bit ++;
295 mask >>= nth_bit;
297 if ((mask == 0) || (nth_bit == BITS_PER_CHUNK))
298 return -1;
300 #if defined(__i386__) && defined(__GNUC__)
302 int r;
303 /* This depends on mask != 0 */
304 __asm__("bsfl %1,%0\n\t"
305 : "=r" (r) : "g" (mask));
306 return nth_bit + r;
308 #elif defined(__x86_64) && defined(__GNUC__)
310 guint64 r;
312 __asm__("bsfq %1,%0\n\t"
313 : "=r" (r) : "rm" (mask));
314 return nth_bit + r;
316 #else
317 while (! (mask & 0x1)) {
318 mask >>= 1;
319 nth_bit ++;
322 return nth_bit;
323 #endif
326 static inline gint
327 my_g_bit_nth_lsf_nomask (gsize mask)
329 /* Mask is expected to be != 0 */
330 #if defined(__i386__) && defined(__GNUC__)
331 int r;
333 __asm__("bsfl %1,%0\n\t"
334 : "=r" (r) : "rm" (mask));
335 return r;
336 #elif defined(__x86_64) && defined(__GNUC__)
337 guint64 r;
339 __asm__("bsfq %1,%0\n\t"
340 : "=r" (r) : "rm" (mask));
341 return r;
342 #else
343 int nth_bit = 0;
345 while (! (mask & 0x1)) {
346 mask >>= 1;
347 nth_bit ++;
350 return nth_bit;
351 #endif
354 #endif
356 static inline int
357 my_g_bit_nth_msf (gsize mask,
358 gint nth_bit)
360 int i;
362 if (nth_bit == 0)
363 return -1;
365 mask <<= BITS_PER_CHUNK - nth_bit;
367 i = BITS_PER_CHUNK;
368 while ((i > 0) && !(mask >> (BITS_PER_CHUNK - 8))) {
369 mask <<= 8;
370 i -= 8;
372 if (mask == 0)
373 return -1;
375 do {
376 i--;
377 if (mask & ((gsize)1 << (BITS_PER_CHUNK - 1)))
378 return i - (BITS_PER_CHUNK - nth_bit);
379 mask <<= 1;
381 while (mask);
383 return -1;
386 static int
387 find_first_unset (gulong mask, gint nth_bit)
389 do {
390 nth_bit++;
391 if (!(mask & ((gsize)1 << nth_bit))) {
392 if (nth_bit == BITS_PER_CHUNK)
393 /* On 64 bit platforms, 1 << 64 == 1 */
394 return -1;
395 else
396 return nth_bit;
398 } while (nth_bit < BITS_PER_CHUNK);
399 return -1;
403 * mono_bitset_find_start:
404 * @set: bitset ptr
406 * Equivalent to mono_bitset_find_first (set, -1) but faster.
409 mono_bitset_find_start (const MonoBitSet *set)
411 int i;
413 for (i = 0; i < set->size / BITS_PER_CHUNK; ++i) {
414 if (set->data [i])
415 return my_g_bit_nth_lsf_nomask (set->data [i]) + i * BITS_PER_CHUNK;
417 return -1;
421 * mono_bitset_find_first:
422 * @set: bitset ptr
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) {
430 int j;
431 int bit;
432 int result, i;
434 if (pos < 0) {
435 j = 0;
436 bit = -1;
437 } else {
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);*/
444 if (set->data [j]) {
445 result = my_g_bit_nth_lsf (set->data [j], bit);
446 if (result != -1)
447 return result + j * BITS_PER_CHUNK;
449 for (i = ++j; i < set->size / BITS_PER_CHUNK; ++i) {
450 if (set->data [i])
451 return my_g_bit_nth_lsf (set->data [i], -1) + i * BITS_PER_CHUNK;
453 return -1;
457 * mono_bitset_find_last:
458 * @set: bitset ptr
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;
468 if (pos < 0)
469 pos = set->size - 1;
471 j = pos / BITS_PER_CHUNK;
472 bit = pos % BITS_PER_CHUNK;
474 g_return_val_if_fail (pos < set->size, -1);
476 if (set->data [j]) {
477 result = my_g_bit_nth_msf (set->data [j], bit);
478 if (result != -1)
479 return result + j * BITS_PER_CHUNK;
481 for (i = --j; i >= 0; --i) {
482 if (set->data [i])
483 return my_g_bit_nth_msf (set->data [i], BITS_PER_CHUNK) + i * BITS_PER_CHUNK;
485 return -1;
489 * mono_bitset_find_first_unset:
490 * @set: bitset ptr
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) {
498 int j;
499 int bit;
500 int result, i;
502 if (pos < 0) {
503 j = 0;
504 bit = -1;
505 } else {
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);
514 if (result != -1)
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;
522 return -1;
526 * mono_bitset_clone:
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
532 * as big.
534 MonoBitSet*
535 mono_bitset_clone (const MonoBitSet *set, guint32 new_size) {
536 MonoBitSet *result;
538 if (!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);
543 return result;
547 * mono_bitset_copyto:
548 * @src: bitset ptr to copy from
549 * @dest: bitset ptr to copy to
551 * Copy one bitset to another.
553 void
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);
561 * mono_bitset_union:
562 * @dest: bitset ptr to hold union
563 * @src: bitset ptr to copy
565 * Make union of one bitset and another.
567 void
568 mono_bitset_union (MonoBitSet *dest, const MonoBitSet *src) {
569 int i;
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.
584 void
585 mono_bitset_intersection (MonoBitSet *dest, const MonoBitSet *src) {
586 int i;
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
602 void
603 mono_bitset_intersection_2 (MonoBitSet *dest, const MonoBitSet *src1, const MonoBitSet *src2) {
604 int i;
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];
614 * mono_bitset_sub:
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.
620 void
621 mono_bitset_sub (MonoBitSet *dest, const MonoBitSet *src) {
622 int i;
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];
631 * mono_bitset_equal:
632 * @src: bitset ptr
633 * @src1: bitset ptr
635 * return TRUE if their size are the same and the same bits are set in
636 * both bitsets.
638 gboolean
639 mono_bitset_equal (const MonoBitSet *src, const MonoBitSet *src1) {
640 int i;
641 if (src->size != src1->size)
642 return FALSE;
644 for (i = 0; i < src->size / BITS_PER_CHUNK; ++i)
645 if (src->data [i] != src1->data [i])
646 return FALSE;
647 return TRUE;
651 * mono_bitset_foreach:
652 * @set: bitset ptr
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
659 void
660 mono_bitset_foreach (MonoBitSet *set, MonoBitSetFunc func, gpointer data)
662 int i, j;
663 for (i = 0; i < set->size / BITS_PER_CHUNK; ++i) {
664 if (set->data [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);
672 #ifdef TEST_BITSET
675 * Compile with:
676 * gcc -g -Wall -DTEST_BITSET -o monobitset monobitset.c `pkg-config --cflags --libs glib-2.0`
678 int
679 main() {
680 MonoBitSet *set1, *set2, *set3, *set4;
681 int error = 1;
682 int count, i;
684 set1 = mono_bitset_new (60, 0);
685 set4 = mono_bitset_new (60, 0);
687 if (mono_bitset_count (set1) != 0)
688 return error;
689 error++;
691 mono_bitset_set (set1, 33);
692 if (mono_bitset_count (set1) != 1)
693 return error;
694 error++;
696 /* g_print("should be 33: %d\n", mono_bitset_find_first (set1, 0)); */
698 if (mono_bitset_find_first (set1, 0) != 33)
699 return error;
700 error++;
702 if (mono_bitset_find_first (set1, 33) != -1)
703 return error;
704 error++;
706 /* test 5 */
707 if (mono_bitset_find_first (set1, -100) != 33)
708 return error;
709 error++;
711 if (mono_bitset_find_last (set1, -1) != 33)
712 return error;
713 error++;
715 if (mono_bitset_find_last (set1, 33) != -1)
716 return error;
717 error++;
719 if (mono_bitset_find_last (set1, -100) != 33)
720 return error;
721 error++;
723 if (mono_bitset_find_last (set1, 34) != 33)
724 return error;
725 error++;
727 /* test 10 */
728 if (!mono_bitset_test (set1, 33))
729 return error;
730 error++;
732 if (mono_bitset_test (set1, 32) || mono_bitset_test (set1, 34))
733 return error;
734 error++;
736 set2 = mono_bitset_clone (set1, 0);
737 if (mono_bitset_count (set2) != 1)
738 return error;
739 error++;
741 mono_bitset_invert (set2);
742 if (mono_bitset_count (set2) != (mono_bitset_size (set2) - 1))
743 return error;
744 error++;
746 mono_bitset_clear (set2, 10);
747 if (mono_bitset_count (set2) != (mono_bitset_size (set2) - 2))
748 return error;
749 error++;
751 /* test 15 */
752 set3 = mono_bitset_clone (set2, 0);
753 mono_bitset_union (set3, set1);
754 if (mono_bitset_count (set3) != (mono_bitset_size (set3) - 1))
755 return error;
756 error++;
758 mono_bitset_clear_all (set2);
759 if (mono_bitset_count (set2) != 0)
760 return error;
761 error++;
763 mono_bitset_invert (set2);
764 if (mono_bitset_count (set2) != mono_bitset_size (set2))
765 return error;
766 error++;
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)
772 return error;
773 error++;
775 count = 0;
776 for (i = mono_bitset_find_first (set4, -1); i != -1; i = mono_bitset_find_first (set4, i)) {
777 count ++;
778 switch (count) {
779 case 1:
780 if (i != 0)
781 return error;
782 break;
783 case 2:
784 if (i != 1)
785 return error;
786 break;
787 case 3:
788 if (i != 10)
789 return error;
790 break;
792 /* g_print ("count got: %d at %d\n", count, i); */
794 if (count != 3)
795 return error;
796 error++;
798 if (mono_bitset_find_first (set4, -1) != 0)
799 return error;
800 error++;
802 /* 20 */
803 mono_bitset_set (set4, 31);
804 if (mono_bitset_find_first (set4, 10) != 31)
805 return error;
806 error++;
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);
824 return 0;
827 #endif