New test.
[mono.git] / mono / utils / monobitset.c
1 #include <glib.h>
2 #include <string.h>
3
4 #include "monobitset.h"
5 #include "config.h"
6
7 #ifdef __GNUC__
8 #define MONO_ZERO_LEN_ARRAY 0
9 #else
10 #define MONO_ZERO_LEN_ARRAY 1
11 #endif
12
13 #define BITS_PER_CHUNK MONO_BITSET_BITS_PER_CHUNK
14
15 struct MonoBitSet {
16         gsize size;
17         gsize flags;
18         gsize data [MONO_ZERO_LEN_ARRAY];
19 };
20
21 /*
22  * mono_bitset_alloc_size:
23  * @max_size: The numer of bits you want to hold
24  * @flags: unused
25  *
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 ().
29  */
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;
33
34         return sizeof (MonoBitSet) + sizeof (gsize) * (real_size - MONO_ZERO_LEN_ARRAY);
35 }
36
37 /*
38  * mono_bitset_new:
39  * @max_size: The numer of bits you want to hold
40  * @flags: bitfield of flags
41  *
42  * Return a bitset of size max_size. It must be freed using
43  * mono_bitset_free.
44  */
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;
49
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;
54 }
55
56 /*
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
61  *
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.
65  */
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;
70
71         result->size = real_size * BITS_PER_CHUNK;
72         result->flags = flags | MONO_BITSET_DONT_FREE;
73         return result;
74 }
75
76 /*
77  * mono_bitset_free:
78  * @set: bitset ptr to free
79  *
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.
83  */
84 void
85 mono_bitset_free (MonoBitSet *set) {
86         if (!(set->flags & MONO_BITSET_DONT_FREE))
87                 g_free (set);
88 }
89
90 /*
91  * mono_bitset_set:
92  * @set: bitset ptr
93  * @pos: set bit at this pos
94  *
95  * Set bit at pos @pos, counting from 0.
96  */
97 void
98 mono_bitset_set (MonoBitSet *set, guint32 pos) {
99         int j = pos / BITS_PER_CHUNK;
100         int bit = pos % BITS_PER_CHUNK;
101
102         g_assert (pos < set->size);
103
104         set->data [j] |= (gsize)1 << bit;
105 }
106
107 /*
108  * mono_bitset_test:
109  * @set: bitset ptr
110  * @pos: test bit at this pos
111  *
112  * Test bit at pos @pos, counting from 0.
113  * Returns a value != 0 if set, 0 otherwise.
114  */
115 int
116 mono_bitset_test (const MonoBitSet *set, guint32 pos) {
117         int j = pos / BITS_PER_CHUNK;
118         int bit = pos % BITS_PER_CHUNK;
119
120         g_return_val_if_fail (pos < set->size, 0);
121
122         return (set->data [j] & ((gsize)1 << bit)) > 0;
123 }
124
125 /*
126  * mono_bitset_test_bulk:
127  * @set: bitset ptr
128  * @pos: test bit at this pos
129  *
130  * Return 32/64 bits from the bitset, starting from @pos, which must be 
131  * divisible with 32/64.
132  */
133 gsize
134 mono_bitset_test_bulk (const MonoBitSet *set, guint32 pos) {
135         int j = pos / BITS_PER_CHUNK;
136
137         if (pos >= set->size)
138                 return 0;
139         else
140                 return set->data [j];
141 }
142
143 /*
144  * mono_bitset_clear:
145  * @set: bitset ptr
146  * @pos: unset bit at this pos
147  *
148  * Unset bit at pos 'pos', counting from 0.
149  */
150 void
151 mono_bitset_clear (MonoBitSet *set, guint32 pos) {
152         int j = pos / BITS_PER_CHUNK;
153         int bit = pos % BITS_PER_CHUNK;
154
155         g_assert (pos < set->size);
156
157         set->data [j] &= ~((gsize)1 << bit);
158 }
159
160 /*
161  * mono_bitset_clear_all:
162  * @set: bitset ptr
163  *
164  * Unset all bits.
165  */
166 void
167 mono_bitset_clear_all (MonoBitSet *set) {
168         memset (set->data, 0, set->size / 8);
169 }
170
171 /*
172  * mono_bitset_set_all:
173  * @set: bitset ptr
174  *
175  * Set all bits.
176  */
177 void
178 mono_bitset_set_all (MonoBitSet *set) {
179         memset (set->data, -1, set->size / 8);
180 }
181
182 /*
183  * mono_bitset_invert:
184  * @set: bitset ptr
185  *
186  * Flip all bits.
187  */
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];
193 }
194
195 /*
196  * mono_bitset_size:
197  * @set: bitset ptr
198  *
199  * Returns the number of bits this bitset can hold.
200  */
201 guint32
202 mono_bitset_size (const MonoBitSet *set) {
203         return set->size;
204 }
205
206 /* 
207  * should test wich version is faster.
208  */
209 #if 1
210
211 /*
212  * mono_bitset_count:
213  * @set: bitset ptr
214  *
215  * return number of bits that is set.
216  */
217 guint32
218 mono_bitset_count (const MonoBitSet *set) {
219         guint32 i, count;
220         gsize d;
221
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
243                 }
244         }
245         return count;
246 }
247 #else
248 guint32
249 mono_bitset_count (const MonoBitSet *set) {
250         static const guint32 table [] = {
251                 0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF
252         };
253         guint32 i, count, val;
254
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;
265                 }
266         }
267         return count;
268 }
269
270 #endif
271
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
284 };
285
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)
288
289 #else
290
291 static inline gint
292 my_g_bit_nth_lsf (gsize mask, gint nth_bit)
293 {
294         nth_bit ++;
295         mask >>= nth_bit;
296
297         if ((mask == 0) || (nth_bit == BITS_PER_CHUNK))
298                 return -1;
299
300 #if defined(__i386__) && defined(__GNUC__)
301  {
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;
307  }
308 #elif defined(__x86_64) && defined(__GNUC__)
309  {
310         guint64 r;
311
312         __asm__("bsfq %1,%0\n\t"
313                         : "=r" (r) : "rm" (mask));
314         return nth_bit + r;
315  }
316 #else
317         while (! (mask & 0x1)) {
318                 mask >>= 1;
319                 nth_bit ++;
320         }
321
322         return nth_bit;
323 #endif
324 }
325
326 static inline gint
327 my_g_bit_nth_lsf_nomask (gsize mask)
328 {
329         /* Mask is expected to be != 0 */
330 #if defined(__i386__) && defined(__GNUC__)
331         int r;
332
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;
338
339         __asm__("bsfq %1,%0\n\t"
340                         : "=r" (r) : "rm" (mask));
341         return r;
342 #else
343         int nth_bit = 0;
344
345         while (! (mask & 0x1)) {
346                 mask >>= 1;
347                 nth_bit ++;
348         }
349
350         return nth_bit;
351 #endif
352 }
353
354 #endif
355
356 static inline int
357 my_g_bit_nth_msf (gsize mask,
358                gint   nth_bit)
359 {
360         int i;
361
362         if (nth_bit == 0)
363                 return -1;
364
365         mask <<= BITS_PER_CHUNK - nth_bit;
366
367         i = BITS_PER_CHUNK;
368         while ((i > 0) && !(mask >> (BITS_PER_CHUNK - 8))) {
369                 mask <<= 8;
370                 i -= 8;
371         }
372         if (mask == 0)
373                 return -1;
374
375         do {
376                 i--;
377                 if (mask & ((gsize)1 << (BITS_PER_CHUNK - 1)))
378                         return i - (BITS_PER_CHUNK - nth_bit);
379                 mask <<= 1;
380     }
381         while (mask);
382
383         return -1;
384 }
385
386 static int
387 find_first_unset (gulong mask, gint nth_bit)
388 {
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;
397                 }
398         } while (nth_bit < BITS_PER_CHUNK);
399         return -1;
400 }
401
402 /*
403  * mono_bitset_find_start:
404  * @set: bitset ptr
405  *
406  * Equivalent to mono_bitset_find_first (set, -1) but faster.
407  */
408 int
409 mono_bitset_find_start   (const MonoBitSet *set)
410 {
411         int i;
412
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;
416         }
417         return -1;
418 }
419
420 /*
421  * mono_bitset_find_first:
422  * @set: bitset ptr
423  * @pos: pos to search _after_ (not including)
424  *
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.
427  */
428 int
429 mono_bitset_find_first (const MonoBitSet *set, gint pos) {
430         int j;
431         int bit;
432         int result, i;
433
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);
441         }
442         /*g_print ("find first from %d (j: %d, bit: %d)\n", pos, j, bit);*/
443
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;
448         }
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;
452         }
453         return -1;
454 }
455
456 /*
457  * mono_bitset_find_last:
458  * @set: bitset ptr
459  * @pos: pos to search _before_ (not including)
460  *
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.
463  */
464 int
465 mono_bitset_find_last (const MonoBitSet *set, gint pos) {
466         int j, bit, result, i;
467
468         if (pos < 0)
469                 pos = set->size - 1;
470                 
471         j = pos / BITS_PER_CHUNK;
472         bit = pos % BITS_PER_CHUNK;
473
474         g_return_val_if_fail (pos < set->size, -1);
475
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;
480         }
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;
484         }
485         return -1;
486 }
487
488 /*
489  * mono_bitset_find_first_unset:
490  * @set: bitset ptr
491  * @pos: pos to search _after_ (not including)
492  *
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.
495  */
496 int
497 mono_bitset_find_first_unset (const MonoBitSet *set, gint pos) {
498         int j;
499         int bit;
500         int result, i;
501
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);
509         }
510         /*g_print ("find first from %d (j: %d, bit: %d)\n", pos, j, bit);*/
511
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;
516         }
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;
520                 }
521         }
522         return -1;
523 }
524
525 /*
526  * mono_bitset_clone:
527  * @set: bitset ptr to clone
528  * @new_size: number of bits the cloned bitset can hold
529  *
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.
533  */
534 MonoBitSet*
535 mono_bitset_clone (const MonoBitSet *set, guint32 new_size) {
536         MonoBitSet *result;
537
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;
544 }
545
546 /*
547  * mono_bitset_copyto:
548  * @src: bitset ptr to copy from
549  * @dest: bitset ptr to copy to
550  *
551  * Copy one bitset to another.
552  */
553 void
554 mono_bitset_copyto (const MonoBitSet *src, MonoBitSet *dest) {
555         g_assert (dest->size <= src->size);
556
557         memcpy (&dest->data, &src->data, dest->size / 8);
558 }
559
560 /*
561  * mono_bitset_union:
562  * @dest: bitset ptr to hold union
563  * @src: bitset ptr to copy
564  *
565  * Make union of one bitset and another.
566  */
567 void
568 mono_bitset_union (MonoBitSet *dest, const MonoBitSet *src) {
569         int i;
570
571         g_assert (src->size <= dest->size);
572
573         for (i = 0; i < dest->size / BITS_PER_CHUNK; ++i)
574                 dest->data [i] |= src->data [i];
575 }
576
577 /*
578  * mono_bitset_intersection:
579  * @dest: bitset ptr to hold intersection
580  * @src: bitset ptr to copy
581  *
582  * Make intersection of one bitset and another.
583  */
584 void
585 mono_bitset_intersection (MonoBitSet *dest, const MonoBitSet *src) {
586         int i;
587
588         g_assert (src->size <= dest->size);
589
590         for (i = 0; i < dest->size / BITS_PER_CHUNK; ++i)
591                 dest->data [i] = dest->data [i] & src->data [i];
592 }
593
594 /*
595  * mono_bitset_intersection_2:
596  * @dest: bitset ptr to hold intersection
597  * @src1: first bitset
598  * @src2: second bitset
599  *
600  * Make intersection of two bitsets
601  */
602 void
603 mono_bitset_intersection_2 (MonoBitSet *dest, const MonoBitSet *src1, const MonoBitSet *src2) {
604         int i;
605
606         g_assert (src1->size <= dest->size);
607         g_assert (src2->size <= dest->size);
608
609         for (i = 0; i < dest->size / BITS_PER_CHUNK; ++i)
610                 dest->data [i] = src1->data [i] & src2->data [i];
611 }
612
613 /*
614  * mono_bitset_sub:
615  * @dest: bitset ptr to hold bitset - src
616  * @src: bitset ptr to copy
617  *
618  * Unset all bits in dest, which are set in src.
619  */
620 void
621 mono_bitset_sub (MonoBitSet *dest, const MonoBitSet *src) {
622         int i;
623
624         g_assert (src->size <= dest->size);
625
626         for (i = 0; i < src->size / BITS_PER_CHUNK; ++i)
627                 dest->data [i] &= ~src->data [i];
628 }
629
630 /*
631  * mono_bitset_equal:
632  * @src: bitset ptr
633  * @src1: bitset ptr
634  *
635  * return TRUE if their size are the same and the same bits are set in
636  * both bitsets.
637  */
638 gboolean
639 mono_bitset_equal (const MonoBitSet *src, const MonoBitSet *src1) {
640         int i;
641         if (src->size != src1->size)
642                 return FALSE;
643
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;
648 }
649
650 /*
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
655  *
656  * Calls func for every bit set in bitset. Argument 1 is the number of
657  * the bit set, argument 2 is data
658  */
659 void
660 mono_bitset_foreach (MonoBitSet *set, MonoBitSetFunc func, gpointer data)
661 {
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);
668                 }
669         }
670 }
671
672 #ifdef TEST_BITSET
673
674 /*
675  * Compile with: 
676  * gcc -g -Wall -DTEST_BITSET -o monobitset monobitset.c `pkg-config --cflags --libs glib-2.0`
677  */
678 int 
679 main() {
680         MonoBitSet *set1, *set2, *set3, *set4;
681         int error = 1;
682         int count, i;
683
684         set1 = mono_bitset_new (60, 0);
685         set4 = mono_bitset_new (60, 0);
686
687         if (mono_bitset_count (set1) != 0)
688                 return error;
689         error++;
690         
691         mono_bitset_set (set1, 33);
692         if (mono_bitset_count (set1) != 1)
693                 return error;
694         error++;
695
696         /* g_print("should be 33: %d\n", mono_bitset_find_first (set1, 0)); */
697         
698         if (mono_bitset_find_first (set1, 0) != 33)
699                 return error;
700         error++;
701
702         if (mono_bitset_find_first (set1, 33) != -1)
703                 return error;
704         error++;
705
706         /* test 5 */
707         if (mono_bitset_find_first (set1, -100) != 33)
708                 return error;
709         error++;
710
711         if (mono_bitset_find_last (set1, -1) != 33)
712                 return error;
713         error++;
714
715         if (mono_bitset_find_last (set1, 33) != -1)
716                 return error;
717         error++;
718
719         if (mono_bitset_find_last (set1, -100) != 33)
720                 return error;
721         error++;
722
723         if (mono_bitset_find_last (set1, 34) != 33)
724                 return error;
725         error++;
726
727         /* test 10 */
728         if (!mono_bitset_test (set1, 33))
729                 return error;
730         error++;
731
732         if (mono_bitset_test (set1, 32) || mono_bitset_test (set1, 34))
733                 return error;
734         error++;
735
736         set2 = mono_bitset_clone (set1, 0);
737         if (mono_bitset_count (set2) != 1)
738                 return error;
739         error++;
740
741         mono_bitset_invert (set2);
742         if (mono_bitset_count (set2) != (mono_bitset_size (set2) - 1))
743                 return error;
744         error++;
745
746         mono_bitset_clear (set2, 10);
747         if (mono_bitset_count (set2) != (mono_bitset_size (set2) - 2))
748                 return error;
749         error++;
750
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++;
757
758         mono_bitset_clear_all (set2);
759         if (mono_bitset_count (set2) != 0)
760                 return error;
761         error++;
762
763         mono_bitset_invert (set2);
764         if (mono_bitset_count (set2) != mono_bitset_size (set2))
765                 return error;
766         error++;
767
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++;
774
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;
791                 }
792                 /* g_print ("count got: %d at %d\n", count, i); */
793         }
794         if (count != 3)
795                 return error;
796         error++;
797
798         if (mono_bitset_find_first (set4, -1) != 0)
799                 return error;
800         error++;
801
802         /* 20 */
803         mono_bitset_set (set4, 31);
804         if (mono_bitset_find_first (set4, 10) != 31)
805                 return error;
806         error++;
807
808         mono_bitset_free (set1);
809
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);
816
817         mono_bitset_free (set1);
818         mono_bitset_free (set2);
819         mono_bitset_free (set3);
820         mono_bitset_free (set4);
821
822         g_print ("total tests passed: %d\n", error - 1);
823         
824         return 0;
825 }
826
827 #endif
828