2009-10-22 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mono / utils / monobitset.c
index ce5d4b8422eceb96c44e83e3f60c8ad5261810d5..d25f66ec0b81b2e4d9daf78cbc92b81cb3575c91 100644 (file)
@@ -4,20 +4,8 @@
 #include "monobitset.h"
 #include "config.h"
 
-#ifdef __GNUC__
-#define MONO_ZERO_LEN_ARRAY 0
-#else
-#define MONO_ZERO_LEN_ARRAY 1
-#endif
-
 #define BITS_PER_CHUNK MONO_BITSET_BITS_PER_CHUNK
 
-struct MonoBitSet {
-       gsize size;
-       gsize flags;
-       gsize data [MONO_ZERO_LEN_ARRAY];
-};
-
 /*
  * mono_bitset_alloc_size:
  * @max_size: The numer of bits you want to hold
@@ -216,11 +204,6 @@ mono_bitset_size (const MonoBitSet *set) {
  */
 guint32
 mono_bitset_count (const MonoBitSet *set) {
-#if SIZEOF_VOID_P == 8
-       static const unsigned char table [16] = {
-               0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
-       };
-#endif
        guint32 i, count;
        gsize d;
 
@@ -230,22 +213,12 @@ mono_bitset_count (const MonoBitSet *set) {
                /* there is probably some asm code that can do this much faster */
                if (d) {
 #if SIZEOF_VOID_P == 8
-                       count += table [d & 0xf]; d >>= 4;
-                       count += table [d & 0xf]; d >>= 4;
-                       count += table [d & 0xf]; d >>= 4;
-                       count += table [d & 0xf]; d >>= 4;
-                       count += table [d & 0xf]; d >>= 4;
-                       count += table [d & 0xf]; d >>= 4;
-                       count += table [d & 0xf]; d >>= 4;
-                       count += table [d & 0xf]; d >>= 4;
-                       count += table [d & 0xf]; d >>= 4;
-                       count += table [d & 0xf]; d >>= 4;
-                       count += table [d & 0xf]; d >>= 4;
-                       count += table [d & 0xf]; d >>= 4;
-                       count += table [d & 0xf]; d >>= 4;
-                       count += table [d & 0xf]; d >>= 4;
-                       count += table [d & 0xf]; d >>= 4;
-                       count += table [d & 0xf]; d >>= 4;
+                       /* http://www.jjj.de/bitwizardry/bitwizardrypage.html */
+                       d -=  (d>>1) & 0x5555555555555555;
+                       d  = ((d>>2) & 0x3333333333333333) + (d & 0x3333333333333333);
+                       d  = ((d>>4) + d) & 0x0f0f0f0f0f0f0f0f;
+                       d *= 0x0101010101010101;
+                       count += d >> 56;
 #else
                        /* http://aggregate.org/MAGIC/ */
                        d -= ((d >> 1) & 0x55555555);
@@ -306,21 +279,28 @@ bitstart_mask [] = {
 static inline gint
 my_g_bit_nth_lsf (gsize mask, gint nth_bit)
 {
-#ifdef __i386__
-       int cnt;
-#endif
-
        nth_bit ++;
        mask >>= nth_bit;
 
        if ((mask == 0) || (nth_bit == BITS_PER_CHUNK))
                return -1;
 
-#ifdef __i386__
-       /* This depends on mask != 0 */
-       __asm__("bsfl %1,%0\n\t"
-                       : "=r" (cnt) : "g" (mask)); 
-       return nth_bit + cnt;
+#if defined(__i386__) && defined(__GNUC__)
+ {
+        int r;
+        /* This depends on mask != 0 */
+        __asm__("bsfl %1,%0\n\t"
+                        : "=r" (r) : "g" (mask)); 
+        return nth_bit + r;
+ }
+#elif defined(__x86_64) && defined(__GNUC__)
+ {
+       guint64 r;
+
+       __asm__("bsfq %1,%0\n\t"
+                       : "=r" (r) : "rm" (mask));
+       return nth_bit + r;
+ }
 #else
        while (! (mask & 0x1)) {
                mask >>= 1;
@@ -335,12 +315,18 @@ static inline gint
 my_g_bit_nth_lsf_nomask (gsize mask)
 {
        /* Mask is expected to be != 0 */
-#ifdef __i386__
+#if defined(__i386__) && defined(__GNUC__)
        int r;
 
        __asm__("bsfl %1,%0\n\t"
                        : "=r" (r) : "rm" (mask));
        return r;
+#elif defined(__x86_64) && defined(__GNUC__)
+       guint64 r;
+
+       __asm__("bsfq %1,%0\n\t"
+                       : "=r" (r) : "rm" (mask));
+       return r;
 #else
        int nth_bit = 0;
 
@@ -385,6 +371,22 @@ my_g_bit_nth_msf (gsize mask,
        return -1;
 }
 
+static int
+find_first_unset (gsize mask, gint nth_bit)
+{
+       do {
+               nth_bit++;
+               if (!(mask & ((gsize)1 << nth_bit))) {
+                       if (nth_bit == BITS_PER_CHUNK)
+                               /* On 64 bit platforms, 1 << 64 == 1 */
+                               return -1;
+                       else
+                               return nth_bit;
+               }
+       } while (nth_bit < BITS_PER_CHUNK);
+       return -1;
+}
+
 /*
  * mono_bitset_find_start:
  * @set: bitset ptr
@@ -423,7 +425,7 @@ mono_bitset_find_first (const MonoBitSet *set, gint pos) {
        } else {
                j = pos / BITS_PER_CHUNK;
                bit = pos % BITS_PER_CHUNK;
-               g_return_val_if_fail (pos < set->size, -1);
+               g_assert (pos < set->size);
        }
        /*g_print ("find first from %d (j: %d, bit: %d)\n", pos, j, bit);*/
 
@@ -471,6 +473,43 @@ mono_bitset_find_last (const MonoBitSet *set, gint pos) {
        return -1;
 }
 
+/*
+ * mono_bitset_find_first_unset:
+ * @set: bitset ptr
+ * @pos: pos to search _after_ (not including)
+ *
+ * Returns position of first unset bit after @pos. If pos < 0 begin search from
+ * start. Return -1 if no bit set is found.
+ */
+int
+mono_bitset_find_first_unset (const MonoBitSet *set, gint pos) {
+       int j;
+       int bit;
+       int result, i;
+
+       if (pos < 0) {
+               j = 0;
+               bit = -1;
+       } else {
+               j = pos / BITS_PER_CHUNK;
+               bit = pos % BITS_PER_CHUNK;
+               g_return_val_if_fail (pos < set->size, -1);
+       }
+       /*g_print ("find first from %d (j: %d, bit: %d)\n", pos, j, bit);*/
+
+       if (set->data [j] != -1) {
+               result = find_first_unset (set->data [j], bit);
+               if (result != -1)
+                       return result + j * BITS_PER_CHUNK;
+       }
+       for (i = ++j; i < set->size / BITS_PER_CHUNK; ++i) {
+               if (set->data [i] != -1) {
+                       return find_first_unset (set->data [i], -1) + i * BITS_PER_CHUNK;
+               }
+       }
+       return -1;
+}
+
 /*
  * mono_bitset_clone:
  * @set: bitset ptr to clone
@@ -515,11 +554,12 @@ mono_bitset_copyto (const MonoBitSet *src, MonoBitSet *dest) {
  */
 void
 mono_bitset_union (MonoBitSet *dest, const MonoBitSet *src) {
-       int i;
+       int i, size;
 
        g_assert (src->size <= dest->size);
 
-       for (i = 0; i < dest->size / BITS_PER_CHUNK; ++i)
+       size = dest->size / BITS_PER_CHUNK;
+       for (i = 0; i < size; ++i)
                dest->data [i] |= src->data [i];
 }
 
@@ -532,12 +572,13 @@ mono_bitset_union (MonoBitSet *dest, const MonoBitSet *src) {
  */
 void
 mono_bitset_intersection (MonoBitSet *dest, const MonoBitSet *src) {
-       int i;
+       int i, size;
 
        g_assert (src->size <= dest->size);
 
-       for (i = 0; i < dest->size / BITS_PER_CHUNK; ++i)
-               dest->data [i] = dest->data [i] & src->data [i];
+       size = dest->size / BITS_PER_CHUNK;
+       for (i = 0; i < size; ++i)
+               dest->data [i] &= src->data [i];
 }
 
 /*
@@ -550,12 +591,13 @@ mono_bitset_intersection (MonoBitSet *dest, const MonoBitSet *src) {
  */
 void
 mono_bitset_intersection_2 (MonoBitSet *dest, const MonoBitSet *src1, const MonoBitSet *src2) {
-       int i;
+       int i, size;
 
        g_assert (src1->size <= dest->size);
        g_assert (src2->size <= dest->size);
 
-       for (i = 0; i < dest->size / BITS_PER_CHUNK; ++i)
+       size = dest->size / BITS_PER_CHUNK;
+       for (i = 0; i < size; ++i)
                dest->data [i] = src1->data [i] & src2->data [i];
 }
 
@@ -568,11 +610,12 @@ mono_bitset_intersection_2 (MonoBitSet *dest, const MonoBitSet *src1, const Mono
  */
 void
 mono_bitset_sub (MonoBitSet *dest, const MonoBitSet *src) {
-       int i;
+       int i, size;
 
        g_assert (src->size <= dest->size);
 
-       for (i = 0; i < dest->size / BITS_PER_CHUNK; ++i)
+       size = src->size / BITS_PER_CHUNK;
+       for (i = 0; i < size; ++i)
                dest->data [i] &= ~src->data [i];
 }