2009-02-23 Mark Probst <mark.probst@gmail.com>
[mono.git] / mono / utils / monobitset.c
index 0211fa2ebcbba8133e1875efefcbc45e52b07666..d25f66ec0b81b2e4d9daf78cbc92b81cb3575c91 100644 (file)
@@ -2,16 +2,15 @@
 #include <string.h>
 
 #include "monobitset.h"
+#include "config.h"
 
-#define BITS_PER_CHUNK (8 * sizeof (guint32))
-
-struct MonoBitSet {
-       guint32 size;
-       guint32 flags;
-       guint32 data [0];
-};
+#define BITS_PER_CHUNK MONO_BITSET_BITS_PER_CHUNK
 
 /*
+ * mono_bitset_alloc_size:
+ * @max_size: The numer of bits you want to hold
+ * @flags: unused
+ *
  * Return the number of bytes required to hold the bitset.
  * Useful to allocate it on the stack or with mempool.
  * Use with mono_bitset_mem_new ().
@@ -20,23 +19,37 @@ guint32
 mono_bitset_alloc_size (guint32 max_size, guint32 flags) {
        guint32 real_size = (max_size + BITS_PER_CHUNK - 1) / BITS_PER_CHUNK;
 
-       return sizeof (MonoBitSet) + sizeof (guint32) * real_size;
+       return sizeof (MonoBitSet) + sizeof (gsize) * (real_size - MONO_ZERO_LEN_ARRAY);
 }
 
+/*
+ * mono_bitset_new:
+ * @max_size: The numer of bits you want to hold
+ * @flags: bitfield of flags
+ *
+ * Return a bitset of size max_size. It must be freed using
+ * mono_bitset_free.
+ */
 MonoBitSet *
 mono_bitset_new (guint32 max_size, guint32 flags) {
        guint32 real_size = (max_size + BITS_PER_CHUNK - 1) / BITS_PER_CHUNK;
        MonoBitSet *result;
 
-       result = g_malloc0 (sizeof (MonoBitSet) + sizeof (guint32) * real_size);
+       result = g_malloc0 (sizeof (MonoBitSet) + sizeof (gsize) * (real_size - MONO_ZERO_LEN_ARRAY));
        result->size = real_size * BITS_PER_CHUNK;
        result->flags = flags;
        return result;
 }
 
 /*
- * We could require mem_size here, instead of max_size, so we could do
- * some out of range checking...
+ * mono_bitset_mem_new:
+ * @mem: The location the bitset is stored
+ * @max_size: The number of bits you want to hold
+ * @flags: bitfield of flags
+ *
+ * Return mem, which is now a initialized bitset of size max_size. It is
+ * not freed even if called with mono_bitset_free. mem must be at least
+ * as big as mono_bitset_alloc_size returns for the same max_size.
  */
 MonoBitSet *
 mono_bitset_mem_new (gpointer mem, guint32 max_size, guint32 flags) {
@@ -48,49 +61,118 @@ mono_bitset_mem_new (gpointer mem, guint32 max_size, guint32 flags) {
        return result;
 }
 
+/*
+ * mono_bitset_free:
+ * @set: bitset ptr to free
+ *
+ * Free bitset unless flags have MONO_BITSET_DONT_FREE set. Does not
+ * free anything if flag MONO_BITSET_DONT_FREE is set or bitset was
+ * made with mono_bitset_mem_new.
+ */
 void
 mono_bitset_free (MonoBitSet *set) {
        if (!(set->flags & MONO_BITSET_DONT_FREE))
                g_free (set);
 }
 
+/*
+ * mono_bitset_set:
+ * @set: bitset ptr
+ * @pos: set bit at this pos
+ *
+ * Set bit at pos @pos, counting from 0.
+ */
 void
 mono_bitset_set (MonoBitSet *set, guint32 pos) {
        int j = pos / BITS_PER_CHUNK;
        int bit = pos % BITS_PER_CHUNK;
 
-       g_return_if_fail (pos < set->size);
+       g_assert (pos < set->size);
 
-       set->data [j] |= 1 << bit;
+       set->data [j] |= (gsize)1 << bit;
 }
 
+/*
+ * mono_bitset_test:
+ * @set: bitset ptr
+ * @pos: test bit at this pos
+ *
+ * Test bit at pos @pos, counting from 0.
+ * Returns a value != 0 if set, 0 otherwise.
+ */
 int
-mono_bitset_test (MonoBitSet *set, guint32 pos) {
+mono_bitset_test (const MonoBitSet *set, guint32 pos) {
        int j = pos / BITS_PER_CHUNK;
        int bit = pos % BITS_PER_CHUNK;
 
        g_return_val_if_fail (pos < set->size, 0);
 
-       return set->data [j] & (1 << bit);
+       return (set->data [j] & ((gsize)1 << bit)) > 0;
+}
+
+/*
+ * mono_bitset_test_bulk:
+ * @set: bitset ptr
+ * @pos: test bit at this pos
+ *
+ * Return 32/64 bits from the bitset, starting from @pos, which must be 
+ * divisible with 32/64.
+ */
+gsize
+mono_bitset_test_bulk (const MonoBitSet *set, guint32 pos) {
+       int j = pos / BITS_PER_CHUNK;
+
+       if (pos >= set->size)
+               return 0;
+       else
+               return set->data [j];
 }
 
+/*
+ * mono_bitset_clear:
+ * @set: bitset ptr
+ * @pos: unset bit at this pos
+ *
+ * Unset bit at pos 'pos', counting from 0.
+ */
 void
 mono_bitset_clear (MonoBitSet *set, guint32 pos) {
        int j = pos / BITS_PER_CHUNK;
        int bit = pos % BITS_PER_CHUNK;
 
-       g_return_if_fail (pos < set->size);
+       g_assert (pos < set->size);
 
-       set->data [j] &= ~(1 << bit);
+       set->data [j] &= ~((gsize)1 << bit);
 }
 
+/*
+ * mono_bitset_clear_all:
+ * @set: bitset ptr
+ *
+ * Unset all bits.
+ */
 void
 mono_bitset_clear_all (MonoBitSet *set) {
-       int i;
-       for (i = 0; i < set->size / BITS_PER_CHUNK; ++i)
-               set->data [i] = 0;
+       memset (set->data, 0, set->size / 8);
 }
 
+/*
+ * mono_bitset_set_all:
+ * @set: bitset ptr
+ *
+ * Set all bits.
+ */
+void
+mono_bitset_set_all (MonoBitSet *set) {
+       memset (set->data, -1, set->size / 8);
+}
+
+/*
+ * mono_bitset_invert:
+ * @set: bitset ptr
+ *
+ * Flip all bits.
+ */
 void
 mono_bitset_invert (MonoBitSet *set) {
        int i;
@@ -98,43 +180,61 @@ mono_bitset_invert (MonoBitSet *set) {
                set->data [i] = ~set->data [i];
 }
 
+/*
+ * mono_bitset_size:
+ * @set: bitset ptr
+ *
+ * Returns the number of bits this bitset can hold.
+ */
 guint32
-mono_bitset_size (MonoBitSet *set) {
+mono_bitset_size (const MonoBitSet *set) {
        return set->size;
 }
 
-#if 1
 /* 
  * should test wich version is faster.
  */
+#if 1
+
+/*
+ * mono_bitset_count:
+ * @set: bitset ptr
+ *
+ * return number of bits that is set.
+ */
 guint32
-mono_bitset_count (MonoBitSet *set) {
-       static const unsigned char table [16] = {
-               0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
-       };
+mono_bitset_count (const MonoBitSet *set) {
        guint32 i, count;
-       const unsigned char *b;
+       gsize d;
 
        count = 0;
        for (i = 0; i < set->size / BITS_PER_CHUNK; ++i) {
+               d = set->data [i];
                /* there is probably some asm code that can do this much faster */
-               if (set->data [i]) {
-                       b = (unsigned char*) (set->data + i);
-                       count += table [b [0] & 0xf];
-                       count += table [b [0] >> 4];
-                       count += table [b [1] & 0xf];
-                       count += table [b [1] >> 4];
-                       count += table [b [2] & 0xf];
-                       count += table [b [2] >> 4];
-                       count += table [b [3] & 0xf];
-                       count += table [b [3] >> 4];
+               if (d) {
+#if SIZEOF_VOID_P == 8
+                       /* 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);
+                       d = (((d >> 2) & 0x33333333) + (d & 0x33333333));
+                       d = (((d >> 4) + d) & 0x0f0f0f0f);
+                       d += (d >> 8);
+                       d += (d >> 16);
+                       count += (d & 0x0000003f);
+#endif
                }
        }
        return count;
 }
 #else
 guint32
-mono_bitset_count (MonoBitSet *set) {
+mono_bitset_count (const MonoBitSet *set) {
        static const guint32 table [] = {
                0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF
        };
@@ -149,7 +249,7 @@ mono_bitset_count (MonoBitSet *set) {
                        val = (val & table [2]) ((val >> 4) & table [2]);
                        val = (val & table [3]) ((val >> 8) & table [3]);
                        val = (val & table [4]) ((val >> 16) & table [4]);
-                       count= val;
+                       count += val;
                }
        }
        return count;
@@ -157,29 +257,203 @@ mono_bitset_count (MonoBitSet *set) {
 
 #endif
 
+#if 0
+const static int 
+bitstart_mask [] = {
+       0xffffffff, 0xfffffffe, 0xfffffffc, 0xfffffff8,
+       0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80,
+       0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800,
+       0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000,
+       0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000,
+       0xfff00000, 0xffe00000, 0xffc00000, 0xff800000,
+       0xff000000, 0xfe000000, 0xfc000000, 0xf8000000,
+       0xf0000000, 0xe0000000, 0xc0000000, 0x80000000,
+       0x00000000
+};
+
+#define my_g_bit_nth_lsf(m,n) (ffs((m) & bitstart_mask [(n)+1])-1)
+#define my_g_bit_nth_lsf_nomask(m) (ffs((m))-1)
+
+#else
+
+static inline gint
+my_g_bit_nth_lsf (gsize mask, gint nth_bit)
+{
+       nth_bit ++;
+       mask >>= nth_bit;
+
+       if ((mask == 0) || (nth_bit == BITS_PER_CHUNK))
+               return -1;
+
+#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;
+               nth_bit ++;
+       }
+
+       return nth_bit;
+#endif
+}
+
+static inline gint
+my_g_bit_nth_lsf_nomask (gsize mask)
+{
+       /* Mask is expected to be != 0 */
+#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;
+
+       while (! (mask & 0x1)) {
+               mask >>= 1;
+               nth_bit ++;
+       }
+
+       return nth_bit;
+#endif
+}
+
+#endif
+
+static inline int
+my_g_bit_nth_msf (gsize mask,
+              gint   nth_bit)
+{
+       int i;
+
+       if (nth_bit == 0)
+               return -1;
+
+       mask <<= BITS_PER_CHUNK - nth_bit;
+
+       i = BITS_PER_CHUNK;
+       while ((i > 0) && !(mask >> (BITS_PER_CHUNK - 8))) {
+               mask <<= 8;
+               i -= 8;
+       }
+       if (mask == 0)
+               return -1;
+
+       do {
+               i--;
+               if (mask & ((gsize)1 << (BITS_PER_CHUNK - 1)))
+                       return i - (BITS_PER_CHUNK - nth_bit);
+               mask <<= 1;
+    }
+       while (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
+ *
+ * Equivalent to mono_bitset_find_first (set, -1) but faster.
+ */
 int
-mono_bitset_find_first (MonoBitSet *set, gint pos) {
-       int j = pos / BITS_PER_CHUNK;
-       int bit = pos % BITS_PER_CHUNK;
+mono_bitset_find_start   (const MonoBitSet *set)
+{
+       int i;
+
+       for (i = 0; i < set->size / BITS_PER_CHUNK; ++i) {
+               if (set->data [i])
+                       return my_g_bit_nth_lsf_nomask (set->data [i]) + i * BITS_PER_CHUNK;
+       }
+       return -1;
+}
+
+/*
+ * mono_bitset_find_first:
+ * @set: bitset ptr
+ * @pos: pos to search _after_ (not including)
+ *
+ * Returns position of first set bit after @pos. If pos < 0 begin search from
+ * start. Return -1 if no bit set is found.
+ */
+int
+mono_bitset_find_first (const MonoBitSet *set, gint pos) {
+       int j;
+       int bit;
        int result, i;
 
-       g_return_val_if_fail (pos < set->size, -1);
+       if (pos < 0) {
+               j = 0;
+               bit = -1;
+       } else {
+               j = pos / BITS_PER_CHUNK;
+               bit = pos % BITS_PER_CHUNK;
+               g_assert (pos < set->size);
+       }
+       /*g_print ("find first from %d (j: %d, bit: %d)\n", pos, j, bit);*/
 
-       for (i = j; i < set->size / BITS_PER_CHUNK; ++i) {
-               if (set->data [i]) {
-                       result = g_bit_nth_lsf (set->data [i], bit);
-                       if (result != -1)
-                               return result + i * BITS_PER_CHUNK;
-               }
+       if (set->data [j]) {
+               result = my_g_bit_nth_lsf (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])
+                       return my_g_bit_nth_lsf (set->data [i], -1) + i * BITS_PER_CHUNK;
        }
        return -1;
 }
 
+/*
+ * mono_bitset_find_last:
+ * @set: bitset ptr
+ * @pos: pos to search _before_ (not including)
+ *
+ * Returns position of last set bit before pos. If pos < 0 search is
+ * started from the end. Returns -1 if no set bit is found.
+ */
 int
-mono_bitset_find_last (MonoBitSet *set, gint pos) {
+mono_bitset_find_last (const MonoBitSet *set, gint pos) {
        int j, bit, result, i;
 
-       if (pos == -1)
+       if (pos < 0)
                pos = set->size - 1;
                
        j = pos / BITS_PER_CHUNK;
@@ -187,77 +461,220 @@ mono_bitset_find_last (MonoBitSet *set, gint pos) {
 
        g_return_val_if_fail (pos < set->size, -1);
 
-       for (i = j; i >= 0; --i) {
-               if (set->data [i]) {
-                       result = g_bit_nth_msf (set->data [i], bit);
-                       if (result != -1)
-                               return result + i * BITS_PER_CHUNK;
+       if (set->data [j]) {
+               result = my_g_bit_nth_msf (set->data [j], bit);
+               if (result != -1)
+                       return result + j * BITS_PER_CHUNK;
+       }
+       for (i = --j; i >= 0; --i) {
+               if (set->data [i])
+                       return my_g_bit_nth_msf (set->data [i], BITS_PER_CHUNK) + i * BITS_PER_CHUNK;
+       }
+       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
+ * @new_size: number of bits the cloned bitset can hold
+ *
+ * Return a cloned bitset of size new_size. MONO_BITSET_DONT_FREE
+ * unset in cloned bitset. If new_size is 0, the cloned object is just
+ * as big.
+ */
 MonoBitSet*
-mono_bitset_clone (MonoBitSet *set, guint32 new_size) {
+mono_bitset_clone (const MonoBitSet *set, guint32 new_size) {
        MonoBitSet *result;
 
        if (!new_size)
                new_size = set->size;
        result = mono_bitset_new (new_size, set->flags);
        result->flags &= ~MONO_BITSET_DONT_FREE;
-       memcpy (result->data, set->data, result->size / 8);
+       memcpy (result->data, set->data, set->size / 8);
        return result;
 }
 
+/*
+ * mono_bitset_copyto:
+ * @src: bitset ptr to copy from
+ * @dest: bitset ptr to copy to
+ *
+ * Copy one bitset to another.
+ */
 void
-mono_bitset_copyto (MonoBitSet *set, MonoBitSet *dest) {
-
-       g_return_if_fail (dest->size <= set->size);
+mono_bitset_copyto (const MonoBitSet *src, MonoBitSet *dest) {
+       g_assert (dest->size <= src->size);
 
-       memcpy (dest->data, set->data, set->size / 8);
+       memcpy (&dest->data, &src->data, dest->size / 8);
 }
 
+/*
+ * mono_bitset_union:
+ * @dest: bitset ptr to hold union
+ * @src: bitset ptr to copy
+ *
+ * Make union of one bitset and another.
+ */
 void
-mono_bitset_union (MonoBitSet *dest, MonoBitSet *src) {
-       int i;
+mono_bitset_union (MonoBitSet *dest, const MonoBitSet *src) {
+       int i, size;
 
-       g_return_if_fail (src->size <= dest->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];
 }
 
+/*
+ * mono_bitset_intersection:
+ * @dest: bitset ptr to hold intersection
+ * @src: bitset ptr to copy
+ *
+ * Make intersection of one bitset and another.
+ */
 void
-mono_bitset_intersection (MonoBitSet *dest, MonoBitSet *src) {
-       int i;
+mono_bitset_intersection (MonoBitSet *dest, const MonoBitSet *src) {
+       int i, size;
 
-       g_return_if_fail (src->size <= dest->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];
 }
 
-gboolean
-mono_bitset_equal (MonoBitSet *src, MonoBitSet *src1) {
+/*
+ * mono_bitset_intersection_2:
+ * @dest: bitset ptr to hold intersection
+ * @src1: first bitset
+ * @src2: second bitset
+ *
+ * Make intersection of two bitsets
+ */
+void
+mono_bitset_intersection_2 (MonoBitSet *dest, const MonoBitSet *src1, const MonoBitSet *src2) {
+       int i, size;
+
+       g_assert (src1->size <= dest->size);
+       g_assert (src2->size <= dest->size);
+
+       size = dest->size / BITS_PER_CHUNK;
+       for (i = 0; i < size; ++i)
+               dest->data [i] = src1->data [i] & src2->data [i];
+}
+
+/*
+ * mono_bitset_sub:
+ * @dest: bitset ptr to hold bitset - src
+ * @src: bitset ptr to copy
+ *
+ * Unset all bits in dest, which are set in src.
+ */
+void
+mono_bitset_sub (MonoBitSet *dest, const MonoBitSet *src) {
+       int i, size;
+
+       g_assert (src->size <= dest->size);
+
+       size = src->size / BITS_PER_CHUNK;
+       for (i = 0; i < size; ++i)
+               dest->data [i] &= ~src->data [i];
+}
 
+/*
+ * mono_bitset_equal:
+ * @src: bitset ptr
+ * @src1: bitset ptr
+ *
+ * return TRUE if their size are the same and the same bits are set in
+ * both bitsets.
+ */
+gboolean
+mono_bitset_equal (const MonoBitSet *src, const MonoBitSet *src1) {
+       int i;
        if (src->size != src1->size)
                return FALSE;
 
-       return memcpy (src->data, src1->data, src->size / 8) == 0;
+       for (i = 0; i < src->size / BITS_PER_CHUNK; ++i)
+               if (src->data [i] != src1->data [i])
+                       return FALSE;
+       return TRUE;
+}
+
+/*
+ * mono_bitset_foreach:
+ * @set: bitset ptr
+ * @func: Function to call for every set bit
+ * @data: pass this as second arg to func
+ *
+ * Calls func for every bit set in bitset. Argument 1 is the number of
+ * the bit set, argument 2 is data
+ */
+void
+mono_bitset_foreach (MonoBitSet *set, MonoBitSetFunc func, gpointer data)
+{
+       int i, j;
+       for (i = 0; i < set->size / BITS_PER_CHUNK; ++i) {
+               if (set->data [i]) {
+                       for (j = 0; j < BITS_PER_CHUNK; ++j)
+                               if (set->data [i] & ((gsize)1 << j))
+                                       func (j + i * BITS_PER_CHUNK, data);
+               }
+       }
 }
 
 #ifdef TEST_BITSET
 
 /*
  * Compile with: 
- * gcc -Wall -DTEST_BITSET -o monobitset monobitset.c `pkg-config --cflags --libs glib-2.0`
+ * gcc -g -Wall -DTEST_BITSET -o monobitset monobitset.c `pkg-config --cflags --libs glib-2.0`
  */
 int 
 main() {
-       MonoBitSet *set1, *set2, *set3;
+       MonoBitSet *set1, *set2, *set3, *set4;
        int error = 1;
+       int count, i;
 
        set1 = mono_bitset_new (60, 0);
+       set4 = mono_bitset_new (60, 0);
 
        if (mono_bitset_count (set1) != 0)
                return error;
@@ -268,6 +685,8 @@ main() {
                return error;
        error++;
 
+       /* g_print("should be 33: %d\n", mono_bitset_find_first (set1, 0)); */
+       
        if (mono_bitset_find_first (set1, 0) != 33)
                return error;
        error++;
@@ -276,6 +695,11 @@ main() {
                return error;
        error++;
 
+       /* test 5 */
+       if (mono_bitset_find_first (set1, -100) != 33)
+               return error;
+       error++;
+
        if (mono_bitset_find_last (set1, -1) != 33)
                return error;
        error++;
@@ -284,10 +708,15 @@ main() {
                return error;
        error++;
 
+       if (mono_bitset_find_last (set1, -100) != 33)
+               return error;
+       error++;
+
        if (mono_bitset_find_last (set1, 34) != 33)
                return error;
        error++;
 
+       /* test 10 */
        if (!mono_bitset_test (set1, 33))
                return error;
        error++;
@@ -311,6 +740,7 @@ main() {
                return error;
        error++;
 
+       /* test 15 */
        set3 = mono_bitset_clone (set2, 0);
        mono_bitset_union (set3, set1);
        if (mono_bitset_count (set3) != (mono_bitset_size (set3) - 1))
@@ -327,10 +757,62 @@ main() {
                return error;
        error++;
 
+       mono_bitset_set (set4, 0);
+       mono_bitset_set (set4, 1);
+       mono_bitset_set (set4, 10);
+       if (mono_bitset_count (set4) != 3)
+               return error;
+       error++;
+
+       count = 0;
+       for (i = mono_bitset_find_first (set4, -1); i != -1; i = mono_bitset_find_first (set4, i)) {
+               count ++;
+               switch (count) {
+               case 1:
+                 if (i != 0)
+                   return error;
+                 break;
+               case 2:
+                 if (i != 1)
+                   return error;
+                 break;
+               case 3:
+                 if (i != 10)
+                   return error;
+                 break;
+               }
+               /* g_print ("count got: %d at %d\n", count, i); */
+       }
+       if (count != 3)
+               return error;
+       error++;
+
+       if (mono_bitset_find_first (set4, -1) != 0)
+               return error;
+       error++;
+
+       /* 20 */
+       mono_bitset_set (set4, 31);
+       if (mono_bitset_find_first (set4, 10) != 31)
+               return error;
+       error++;
+
+       mono_bitset_free (set1);
+
+       set1 = mono_bitset_new (200, 0);
+       mono_bitset_set (set1, 0);
+       mono_bitset_set (set1, 1);
+       mono_bitset_set (set1, 10);
+       mono_bitset_set (set1, 31);
+       mono_bitset_set (set1, 150);
+
        mono_bitset_free (set1);
        mono_bitset_free (set2);
        mono_bitset_free (set3);
+       mono_bitset_free (set4);
 
+       g_print ("total tests passed: %d\n", error - 1);
+       
        return 0;
 }