Release captured reference type stack variables
[mono-project.git] / mono / utils / monobitset.c
blobc71da25ba5c931129e5c7b0ca1e79cdec6c21220
1 #include <glib.h>
2 #include <string.h>
4 #include "monobitset.h"
5 #include "config.h"
7 #define BITS_PER_CHUNK MONO_BITSET_BITS_PER_CHUNK
9 /*
10 * mono_bitset_alloc_size:
11 * @max_size: The number of bits you want to hold
12 * @flags: unused
14 * Return the number of bytes required to hold the bitset.
15 * Useful to allocate it on the stack or with mempool.
16 * Use with mono_bitset_mem_new ().
18 guint32
19 mono_bitset_alloc_size (guint32 max_size, guint32 flags) {
20 guint32 real_size = (max_size + BITS_PER_CHUNK - 1) / BITS_PER_CHUNK;
22 return sizeof (MonoBitSet) + sizeof (gsize) * (real_size - MONO_ZERO_LEN_ARRAY);
26 * mono_bitset_new:
27 * @max_size: The numer of bits you want to hold
28 * @flags: bitfield of flags
30 * Return a bitset of size max_size. It must be freed using
31 * mono_bitset_free.
33 MonoBitSet *
34 mono_bitset_new (guint32 max_size, guint32 flags) {
35 guint32 real_size = (max_size + BITS_PER_CHUNK - 1) / BITS_PER_CHUNK;
36 MonoBitSet *result;
38 result = g_malloc0 (sizeof (MonoBitSet) + sizeof (gsize) * (real_size - MONO_ZERO_LEN_ARRAY));
39 result->size = real_size * BITS_PER_CHUNK;
40 result->flags = flags;
41 return result;
45 * mono_bitset_mem_new:
46 * @mem: The location the bitset is stored
47 * @max_size: The number of bits you want to hold
48 * @flags: bitfield of flags
50 * Return mem, which is now a initialized bitset of size max_size. It is
51 * not freed even if called with mono_bitset_free. mem must be at least
52 * as big as mono_bitset_alloc_size returns for the same max_size.
54 MonoBitSet *
55 mono_bitset_mem_new (gpointer mem, guint32 max_size, guint32 flags) {
56 guint32 real_size = (max_size + BITS_PER_CHUNK - 1) / BITS_PER_CHUNK;
57 MonoBitSet *result = mem;
59 result->size = real_size * BITS_PER_CHUNK;
60 result->flags = flags | MONO_BITSET_DONT_FREE;
61 return result;
65 * mono_bitset_free:
66 * @set: bitset ptr to free
68 * Free bitset unless flags have MONO_BITSET_DONT_FREE set. Does not
69 * free anything if flag MONO_BITSET_DONT_FREE is set or bitset was
70 * made with mono_bitset_mem_new.
72 void
73 mono_bitset_free (MonoBitSet *set) {
74 if (!(set->flags & MONO_BITSET_DONT_FREE))
75 g_free (set);
79 * mono_bitset_set:
80 * @set: bitset ptr
81 * @pos: set bit at this pos
83 * Set bit at pos @pos, counting from 0.
85 void
86 mono_bitset_set (MonoBitSet *set, guint32 pos) {
87 int j = pos / BITS_PER_CHUNK;
88 int bit = pos % BITS_PER_CHUNK;
90 g_assert (pos < set->size);
92 set->data [j] |= (gsize)1 << bit;
96 * mono_bitset_test:
97 * @set: bitset ptr
98 * @pos: test bit at this pos
100 * Test bit at pos @pos, counting from 0.
101 * Returns a value != 0 if set, 0 otherwise.
104 mono_bitset_test (const MonoBitSet *set, guint32 pos) {
105 int j = pos / BITS_PER_CHUNK;
106 int bit = pos % BITS_PER_CHUNK;
108 g_return_val_if_fail (pos < set->size, 0);
110 return (set->data [j] & ((gsize)1 << bit)) > 0;
114 * mono_bitset_test_bulk:
115 * @set: bitset ptr
116 * @pos: test bit at this pos
118 * Return 32/64 bits from the bitset, starting from @pos, which must be
119 * divisible with 32/64.
121 gsize
122 mono_bitset_test_bulk (const MonoBitSet *set, guint32 pos) {
123 int j = pos / BITS_PER_CHUNK;
125 if (pos >= set->size)
126 return 0;
127 else
128 return set->data [j];
132 * mono_bitset_clear:
133 * @set: bitset ptr
134 * @pos: unset bit at this pos
136 * Unset bit at pos 'pos', counting from 0.
138 void
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 * @set: bitset ptr
152 * Unset all bits.
154 void
155 mono_bitset_clear_all (MonoBitSet *set) {
156 memset (set->data, 0, set->size / 8);
160 * mono_bitset_set_all:
161 * @set: bitset ptr
163 * Set all bits.
165 void
166 mono_bitset_set_all (MonoBitSet *set) {
167 memset (set->data, -1, set->size / 8);
171 * mono_bitset_invert:
172 * @set: bitset ptr
174 * Flip all bits.
176 void
177 mono_bitset_invert (MonoBitSet *set) {
178 int i;
179 for (i = 0; i < set->size / BITS_PER_CHUNK; ++i)
180 set->data [i] = ~set->data [i];
184 * mono_bitset_size:
185 * @set: bitset ptr
187 * Returns the number of bits this bitset can hold.
189 guint32
190 mono_bitset_size (const MonoBitSet *set) {
191 return set->size;
195 * should test wich version is faster.
197 #if 1
200 * mono_bitset_count:
201 * @set: bitset ptr
203 * return number of bits that is set.
205 guint32
206 mono_bitset_count (const MonoBitSet *set) {
207 guint32 i, count;
208 gsize d;
210 count = 0;
211 for (i = 0; i < set->size / BITS_PER_CHUNK; ++i) {
212 d = set->data [i];
213 /* there is probably some asm code that can do this much faster */
214 if (d) {
215 #if SIZEOF_VOID_P == 8
216 /* http://www.jjj.de/bitwizardry/bitwizardrypage.html */
217 d -= (d>>1) & 0x5555555555555555;
218 d = ((d>>2) & 0x3333333333333333) + (d & 0x3333333333333333);
219 d = ((d>>4) + d) & 0x0f0f0f0f0f0f0f0f;
220 d *= 0x0101010101010101;
221 count += d >> 56;
222 #else
223 /* http://aggregate.org/MAGIC/ */
224 d -= ((d >> 1) & 0x55555555);
225 d = (((d >> 2) & 0x33333333) + (d & 0x33333333));
226 d = (((d >> 4) + d) & 0x0f0f0f0f);
227 d += (d >> 8);
228 d += (d >> 16);
229 count += (d & 0x0000003f);
230 #endif
233 return count;
235 #else
236 guint32
237 mono_bitset_count (const MonoBitSet *set) {
238 static const guint32 table [] = {
239 0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF
241 guint32 i, count, val;
243 count = 0;
244 for (i = 0; i < set->size / BITS_PER_CHUNK;+i) {
245 if (set->data [i]) {
246 val = set->data [i];
247 val = (val & table [0]) ((val >> 1) & table [0]);
248 val = (val & table [1]) ((val >> 2) & table [1]);
249 val = (val & table [2]) ((val >> 4) & table [2]);
250 val = (val & table [3]) ((val >> 8) & table [3]);
251 val = (val & table [4]) ((val >> 16) & table [4]);
252 count += val;
255 return count;
258 #endif
260 #if 0
261 const static int
262 bitstart_mask [] = {
263 0xffffffff, 0xfffffffe, 0xfffffffc, 0xfffffff8,
264 0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80,
265 0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800,
266 0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000,
267 0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000,
268 0xfff00000, 0xffe00000, 0xffc00000, 0xff800000,
269 0xff000000, 0xfe000000, 0xfc000000, 0xf8000000,
270 0xf0000000, 0xe0000000, 0xc0000000, 0x80000000,
271 0x00000000
274 #define my_g_bit_nth_lsf(m,n) (ffs((m) & bitstart_mask [(n)+1])-1)
275 #define my_g_bit_nth_lsf_nomask(m) (ffs((m))-1)
277 #else
279 static inline gint
280 my_g_bit_nth_lsf (gsize mask, gint nth_bit)
282 nth_bit ++;
283 mask >>= nth_bit;
285 if ((mask == 0) || (nth_bit == BITS_PER_CHUNK))
286 return -1;
288 #if defined(__i386__) && defined(__GNUC__)
290 int r;
291 /* This depends on mask != 0 */
292 __asm__("bsfl %1,%0\n\t"
293 : "=r" (r) : "g" (mask));
294 return nth_bit + r;
296 #elif defined(__x86_64) && defined(__GNUC__)
298 guint64 r;
300 __asm__("bsfq %1,%0\n\t"
301 : "=r" (r) : "rm" (mask));
302 return nth_bit + r;
304 #else
305 while (! (mask & 0x1)) {
306 mask >>= 1;
307 nth_bit ++;
310 return nth_bit;
311 #endif
314 static inline gint
315 my_g_bit_nth_lsf_nomask (gsize mask)
317 /* Mask is expected to be != 0 */
318 #if defined(__i386__) && defined(__GNUC__)
319 int r;
321 __asm__("bsfl %1,%0\n\t"
322 : "=r" (r) : "rm" (mask));
323 return r;
324 #elif defined(__x86_64) && defined(__GNUC__)
325 guint64 r;
327 __asm__("bsfq %1,%0\n\t"
328 : "=r" (r) : "rm" (mask));
329 return r;
330 #else
331 int nth_bit = 0;
333 while (! (mask & 0x1)) {
334 mask >>= 1;
335 nth_bit ++;
338 return nth_bit;
339 #endif
342 #endif
344 static inline int
345 my_g_bit_nth_msf (gsize mask,
346 gint nth_bit)
348 int i;
350 if (nth_bit == 0)
351 return -1;
353 mask <<= BITS_PER_CHUNK - nth_bit;
355 i = BITS_PER_CHUNK;
356 while ((i > 0) && !(mask >> (BITS_PER_CHUNK - 8))) {
357 mask <<= 8;
358 i -= 8;
360 if (mask == 0)
361 return -1;
363 do {
364 i--;
365 if (mask & ((gsize)1 << (BITS_PER_CHUNK - 1)))
366 return i - (BITS_PER_CHUNK - nth_bit);
367 mask <<= 1;
369 while (mask);
371 return -1;
374 static int
375 find_first_unset (gsize mask, gint nth_bit)
377 do {
378 nth_bit++;
379 if (!(mask & ((gsize)1 << nth_bit))) {
380 if (nth_bit == BITS_PER_CHUNK)
381 /* On 64 bit platforms, 1 << 64 == 1 */
382 return -1;
383 else
384 return nth_bit;
386 } while (nth_bit < BITS_PER_CHUNK);
387 return -1;
391 * mono_bitset_find_start:
392 * @set: bitset ptr
394 * Equivalent to mono_bitset_find_first (set, -1) but faster.
397 mono_bitset_find_start (const MonoBitSet *set)
399 int i;
401 for (i = 0; i < set->size / BITS_PER_CHUNK; ++i) {
402 if (set->data [i])
403 return my_g_bit_nth_lsf_nomask (set->data [i]) + i * BITS_PER_CHUNK;
405 return -1;
409 * mono_bitset_find_first:
410 * @set: bitset ptr
411 * @pos: pos to search _after_ (not including)
413 * Returns position of first set bit after @pos. If pos < 0 begin search from
414 * start. Return -1 if no bit set is found.
417 mono_bitset_find_first (const MonoBitSet *set, gint pos) {
418 int j;
419 int bit;
420 int result, i;
422 if (pos < 0) {
423 j = 0;
424 bit = -1;
425 } else {
426 j = pos / BITS_PER_CHUNK;
427 bit = pos % BITS_PER_CHUNK;
428 g_assert (pos < set->size);
430 /*g_print ("find first from %d (j: %d, bit: %d)\n", pos, j, bit);*/
432 if (set->data [j]) {
433 result = my_g_bit_nth_lsf (set->data [j], bit);
434 if (result != -1)
435 return result + j * BITS_PER_CHUNK;
437 for (i = ++j; i < set->size / BITS_PER_CHUNK; ++i) {
438 if (set->data [i])
439 return my_g_bit_nth_lsf (set->data [i], -1) + i * BITS_PER_CHUNK;
441 return -1;
445 * mono_bitset_find_last:
446 * @set: bitset ptr
447 * @pos: pos to search _before_ (not including)
449 * Returns position of last set bit before pos. If pos < 0 search is
450 * started from the end. Returns -1 if no set bit is found.
453 mono_bitset_find_last (const MonoBitSet *set, gint pos) {
454 int j, bit, result, i;
456 if (pos < 0)
457 pos = set->size - 1;
459 j = pos / BITS_PER_CHUNK;
460 bit = pos % BITS_PER_CHUNK;
462 g_return_val_if_fail (pos < set->size, -1);
464 if (set->data [j]) {
465 result = my_g_bit_nth_msf (set->data [j], bit);
466 if (result != -1)
467 return result + j * BITS_PER_CHUNK;
469 for (i = --j; i >= 0; --i) {
470 if (set->data [i])
471 return my_g_bit_nth_msf (set->data [i], BITS_PER_CHUNK) + i * BITS_PER_CHUNK;
473 return -1;
477 * mono_bitset_find_first_unset:
478 * @set: bitset ptr
479 * @pos: pos to search _after_ (not including)
481 * Returns position of first unset bit after @pos. If pos < 0 begin search from
482 * start. Return -1 if no bit set is found.
485 mono_bitset_find_first_unset (const MonoBitSet *set, gint pos) {
486 int j;
487 int bit;
488 int result, i;
490 if (pos < 0) {
491 j = 0;
492 bit = -1;
493 } else {
494 j = pos / BITS_PER_CHUNK;
495 bit = pos % BITS_PER_CHUNK;
496 g_return_val_if_fail (pos < set->size, -1);
498 /*g_print ("find first from %d (j: %d, bit: %d)\n", pos, j, bit);*/
500 if (set->data [j] != -1) {
501 result = find_first_unset (set->data [j], bit);
502 if (result != -1)
503 return result + j * BITS_PER_CHUNK;
505 for (i = ++j; i < set->size / BITS_PER_CHUNK; ++i) {
506 if (set->data [i] != -1) {
507 return find_first_unset (set->data [i], -1) + i * BITS_PER_CHUNK;
510 return -1;
514 * mono_bitset_clone:
515 * @set: bitset ptr to clone
516 * @new_size: number of bits the cloned bitset can hold
518 * Return a cloned bitset of size new_size. MONO_BITSET_DONT_FREE
519 * unset in cloned bitset. If new_size is 0, the cloned object is just
520 * as big.
522 MonoBitSet*
523 mono_bitset_clone (const MonoBitSet *set, guint32 new_size) {
524 MonoBitSet *result;
526 if (!new_size)
527 new_size = set->size;
528 result = mono_bitset_new (new_size, set->flags);
529 result->flags &= ~MONO_BITSET_DONT_FREE;
530 memcpy (result->data, set->data, set->size / 8);
531 return result;
535 * mono_bitset_copyto:
536 * @src: bitset ptr to copy from
537 * @dest: bitset ptr to copy to
539 * Copy one bitset to another.
541 void
542 mono_bitset_copyto (const MonoBitSet *src, MonoBitSet *dest) {
543 g_assert (dest->size <= src->size);
545 memcpy (&dest->data, &src->data, dest->size / 8);
549 * mono_bitset_union:
550 * @dest: bitset ptr to hold union
551 * @src: bitset ptr to copy
553 * Make union of one bitset and another.
555 void
556 mono_bitset_union (MonoBitSet *dest, const MonoBitSet *src) {
557 int i, size;
559 g_assert (src->size <= dest->size);
561 size = dest->size / BITS_PER_CHUNK;
562 for (i = 0; i < size; ++i)
563 dest->data [i] |= src->data [i];
567 * mono_bitset_intersection:
568 * @dest: bitset ptr to hold intersection
569 * @src: bitset ptr to copy
571 * Make intersection of one bitset and another.
573 void
574 mono_bitset_intersection (MonoBitSet *dest, const MonoBitSet *src) {
575 int i, size;
577 g_assert (src->size <= dest->size);
579 size = dest->size / BITS_PER_CHUNK;
580 for (i = 0; i < size; ++i)
581 dest->data [i] &= src->data [i];
585 * mono_bitset_intersection_2:
586 * @dest: bitset ptr to hold intersection
587 * @src1: first bitset
588 * @src2: second bitset
590 * Make intersection of two bitsets
592 void
593 mono_bitset_intersection_2 (MonoBitSet *dest, const MonoBitSet *src1, const MonoBitSet *src2) {
594 int i, size;
596 g_assert (src1->size <= dest->size);
597 g_assert (src2->size <= dest->size);
599 size = dest->size / BITS_PER_CHUNK;
600 for (i = 0; i < size; ++i)
601 dest->data [i] = src1->data [i] & src2->data [i];
605 * mono_bitset_sub:
606 * @dest: bitset ptr to hold bitset - src
607 * @src: bitset ptr to copy
609 * Unset all bits in dest, which are set in src.
611 void
612 mono_bitset_sub (MonoBitSet *dest, const MonoBitSet *src) {
613 int i, size;
615 g_assert (src->size <= dest->size);
617 size = src->size / BITS_PER_CHUNK;
618 for (i = 0; i < size; ++i)
619 dest->data [i] &= ~src->data [i];
623 * mono_bitset_equal:
624 * @src: bitset ptr
625 * @src1: bitset ptr
627 * return TRUE if their size are the same and the same bits are set in
628 * both bitsets.
630 gboolean
631 mono_bitset_equal (const MonoBitSet *src, const MonoBitSet *src1) {
632 int i;
633 if (src->size != src1->size)
634 return FALSE;
636 for (i = 0; i < src->size / BITS_PER_CHUNK; ++i)
637 if (src->data [i] != src1->data [i])
638 return FALSE;
639 return TRUE;
643 * mono_bitset_foreach:
644 * @set: bitset ptr
645 * @func: Function to call for every set bit
646 * @data: pass this as second arg to func
648 * Calls func for every bit set in bitset. Argument 1 is the number of
649 * the bit set, argument 2 is data
651 void
652 mono_bitset_foreach (MonoBitSet *set, MonoBitSetFunc func, gpointer data)
654 int i, j;
655 for (i = 0; i < set->size / BITS_PER_CHUNK; ++i) {
656 if (set->data [i]) {
657 for (j = 0; j < BITS_PER_CHUNK; ++j)
658 if (set->data [i] & ((gsize)1 << j))
659 func (j + i * BITS_PER_CHUNK, data);
664 #ifdef TEST_BITSET
667 * Compile with:
668 * gcc -g -Wall -DTEST_BITSET -o monobitset monobitset.c `pkg-config --cflags --libs glib-2.0`
670 int
671 main() {
672 MonoBitSet *set1, *set2, *set3, *set4;
673 int error = 1;
674 int count, i;
676 set1 = mono_bitset_new (60, 0);
677 set4 = mono_bitset_new (60, 0);
679 if (mono_bitset_count (set1) != 0)
680 return error;
681 error++;
683 mono_bitset_set (set1, 33);
684 if (mono_bitset_count (set1) != 1)
685 return error;
686 error++;
688 /* g_print("should be 33: %d\n", mono_bitset_find_first (set1, 0)); */
690 if (mono_bitset_find_first (set1, 0) != 33)
691 return error;
692 error++;
694 if (mono_bitset_find_first (set1, 33) != -1)
695 return error;
696 error++;
698 /* test 5 */
699 if (mono_bitset_find_first (set1, -100) != 33)
700 return error;
701 error++;
703 if (mono_bitset_find_last (set1, -1) != 33)
704 return error;
705 error++;
707 if (mono_bitset_find_last (set1, 33) != -1)
708 return error;
709 error++;
711 if (mono_bitset_find_last (set1, -100) != 33)
712 return error;
713 error++;
715 if (mono_bitset_find_last (set1, 34) != 33)
716 return error;
717 error++;
719 /* test 10 */
720 if (!mono_bitset_test (set1, 33))
721 return error;
722 error++;
724 if (mono_bitset_test (set1, 32) || mono_bitset_test (set1, 34))
725 return error;
726 error++;
728 set2 = mono_bitset_clone (set1, 0);
729 if (mono_bitset_count (set2) != 1)
730 return error;
731 error++;
733 mono_bitset_invert (set2);
734 if (mono_bitset_count (set2) != (mono_bitset_size (set2) - 1))
735 return error;
736 error++;
738 mono_bitset_clear (set2, 10);
739 if (mono_bitset_count (set2) != (mono_bitset_size (set2) - 2))
740 return error;
741 error++;
743 /* test 15 */
744 set3 = mono_bitset_clone (set2, 0);
745 mono_bitset_union (set3, set1);
746 if (mono_bitset_count (set3) != (mono_bitset_size (set3) - 1))
747 return error;
748 error++;
750 mono_bitset_clear_all (set2);
751 if (mono_bitset_count (set2) != 0)
752 return error;
753 error++;
755 mono_bitset_invert (set2);
756 if (mono_bitset_count (set2) != mono_bitset_size (set2))
757 return error;
758 error++;
760 mono_bitset_set (set4, 0);
761 mono_bitset_set (set4, 1);
762 mono_bitset_set (set4, 10);
763 if (mono_bitset_count (set4) != 3)
764 return error;
765 error++;
767 count = 0;
768 for (i = mono_bitset_find_first (set4, -1); i != -1; i = mono_bitset_find_first (set4, i)) {
769 count ++;
770 switch (count) {
771 case 1:
772 if (i != 0)
773 return error;
774 break;
775 case 2:
776 if (i != 1)
777 return error;
778 break;
779 case 3:
780 if (i != 10)
781 return error;
782 break;
784 /* g_print ("count got: %d at %d\n", count, i); */
786 if (count != 3)
787 return error;
788 error++;
790 if (mono_bitset_find_first (set4, -1) != 0)
791 return error;
792 error++;
794 /* 20 */
795 mono_bitset_set (set4, 31);
796 if (mono_bitset_find_first (set4, 10) != 31)
797 return error;
798 error++;
800 mono_bitset_free (set1);
802 set1 = mono_bitset_new (200, 0);
803 mono_bitset_set (set1, 0);
804 mono_bitset_set (set1, 1);
805 mono_bitset_set (set1, 10);
806 mono_bitset_set (set1, 31);
807 mono_bitset_set (set1, 150);
809 mono_bitset_free (set1);
810 mono_bitset_free (set2);
811 mono_bitset_free (set3);
812 mono_bitset_free (set4);
814 g_print ("total tests passed: %d\n", error - 1);
816 return 0;
819 #endif