#include "ruby.h" #include "string.h" static VALUE cBitSet; static ID id_new, id_first, id_end; struct BitSet { int len; unsigned char *ptr; }; int ZERO_TABLE[] = { 8, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; int ONE_TABLE[] = { 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 8 }; int MAX_TABLE[] = { 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }; int COUNT_TABLE[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, }; void bs_resize(struct BitSet *bits, int len) { int arylen; int arybytes, arymod; int bytes, mod; arylen = bits->len; arybytes = (arylen + 7) / 8; arymod = arylen % 8; bytes = (len + 7) / 8; mod = len % 8; if (len==arylen) { return; } else if (lenptr = REALLOC_N(bits->ptr, unsigned char, bytes); bits->len = len; if (mod>0) { bits->ptr[bytes-1] &= (1<arylen) { bits->ptr = REALLOC_N(bits->ptr, unsigned char, bytes); memset(bits->ptr+arybytes, 0, bytes-arybytes); bits->len = len; } } int bs_get(struct BitSet *bits, int index) { int byte_offset; int bit_offset; unsigned char c; int bit; if (index >= bits->len) { bit = 0; } else { byte_offset = index / 8; bit_offset = index % 8; c = bits->ptr[byte_offset]; if (c & (1 << bit_offset)) { bit = 1; } else { bit = 0; } } return bit; } void bs_set(struct BitSet *bits, int index, int bit) { int byte_offset; int bit_offset; unsigned char c; if (index >= bits->len) { bs_resize(bits, index+1); } byte_offset = index / 8; bit_offset = index % 8; c = bits->ptr[byte_offset]; if (bit) { c |= (1 << bit_offset); } else { c &= ~(1 << bit_offset); } bits->ptr[byte_offset] = c; } void bs_sets(struct BitSet *bits, int first, int end, int bit) { int first_offset; int end_offset; int first_mod; int end_mod; int bytes; int i; unsigned char c; if (bits->len < end) { bs_resize(bits, end); } first_offset = first / 8; first_mod = first % 8; end_offset = end / 8; end_mod = end % 8; bytes = end_offset - first_offset + 1; if (first_mod==0 && end_mod==7) { memset(bits->ptr+first_offset, bit ? 0xff : 0x00, bytes); return; } if (end-first < 16) { for(i=first; i<=end; i++) { bs_set(bits, i, bit); } return; } if (first_mod != 0) { c = bits->ptr[first_offset]; if (bit) { c |= ~((1 << first_mod) - 1); } else { c &= ((1 << first_mod) - 1); } bits->ptr[first_offset] = c; first_offset++; bytes--; } if (end_mod != 7) { c = bits->ptr[end_offset]; if (bit) { c |= ((2 << end_mod) - 1); } else { c &= ~((2 << end_mod) - 1); } bits->ptr[end_offset] = c; bytes--; } if (bytes>0) { memset(bits->ptr+first_offset, bit ? 0xff : 0x00, bytes); } return; } void bs_fill(VALUE obj, struct BitSet *bits, int fill) { int i; VALUE vfirst, vend; int first, end; switch(TYPE(obj)) { case T_FIXNUM: bs_set(bits, FIX2INT(obj), fill); break; case T_ARRAY: for(i=0; i< (RARRAY(obj)->len); i++) { bs_fill( (RARRAY(obj)->ptr[i]), bits, fill); } break; default: if (rb_class_of(obj)==rb_cRange) { vfirst = rb_funcall(obj, id_first, 0); vend = rb_funcall(obj, id_end, 0); Check_Type(vfirst, T_FIXNUM); Check_Type(vend, T_FIXNUM); first = FIX2INT(vfirst); end = FIX2INT(vend); if (rb_funcall(obj, rb_intern("exclude_end?"), 0) == Qtrue) { end--; } if (first>end || first<0 || end<0) { rb_raise(rb_eRangeError, "not valid range"); } bs_sets(bits, first, end, fill); } else { rb_raise(rb_eTypeError, "not valid index"); } } } void bs_or(struct BitSet *bits, struct BitSet *x) { unsigned char *ptr, *xptr; int bytes; int i; if (bits->len < x->len) { bs_resize(bits, x->len); } bytes = (x->len+7) / 8; ptr = bits->ptr; xptr = x->ptr; for(i=0; ilen+7) / 8; mod = bits->len % 8; ptr = bits->ptr; for(i=0; i0) { c = *--ptr; *ptr = c & ((1<len + 7) / 8; srest = sbits->len % 8; xbytes = (xbits->len + 7) / 8; xrest = xbits->len % 8; sptr = sbits->ptr; xptr = xbits->ptr; while(sbytes && xbytes) { *sptr++ &= *xptr++; sbytes--; xbytes--; } while(sbytes) { if (sbytes) { sch = *sptr; if (--sbytes == 0) { sch &= (1<len < x->len) { bs_resize(bits, x->len); } bytes = (x->len+7) / 8; ptr = bits->ptr; xptr = x->ptr; for(i=0; ilen+7) / 8; index = (bytes-1) * 8; ptr = bits->ptr + bytes - 1; while(index>=0) { c = *ptr--; pos = MAX_TABLE[c]; if (pos) { index = index + pos - 1; return index; } index -= 8; } return -1; } int bs_min(struct BitSet *bits) { int index; int len; int pos; unsigned char *ptr, c; index = 0; ptr = bits->ptr; len = bits->len; while(indexptr); } static VALUE bits_s_new(int argc, VALUE *argv, VALUE self) { struct BitSet *bits; VALUE arg; VALUE obj; int len; int bytes; obj = Data_Make_Struct(self, struct BitSet, NULL, bits_free, bits); if (argc>0) { arg = argv[0]; } else { arg = INT2FIX(1); } switch(TYPE(arg)) { case T_FIXNUM: len = FIX2INT(arg); if (len<1) { rb_raise(rb_eArgError, "array size"); } bytes = (len+7)/8; bits->len = len; bits->ptr = ALLOC_N(unsigned char, bytes); memset(bits->ptr, 0, bytes); break; case T_STRING: bytes = RSTRING(arg)->len; bits->len = bytes*8; bits->ptr = ALLOC_N(unsigned char, bytes); memcpy(bits->ptr, RSTRING(arg)->ptr, bytes); break; default: rb_raise(rb_eArgError, "not valid value"); } return obj; } static VALUE bits_s_from_bin(VALUE self, VALUE arg) { struct BitSet *bits; VALUE retobj; unsigned char ch, *ptr, *bptr; int len; int bytes; int bitcnt; Check_Type(arg, T_STRING); len = RSTRING(arg)->len; if (len<1) { rb_raise(rb_eArgError, "array size"); } bytes = (len+7)/8; retobj = Data_Make_Struct(self, struct BitSet, NULL, bits_free, bits); bits->len = len; bits->ptr = ALLOC_N(unsigned char, bytes); memset(bits->ptr, 0, bytes); ch = 0; bitcnt = 0; ptr = (unsigned char *)RSTRING(arg)->ptr; bptr = bits->ptr; while(len--) { switch(*ptr++) { case '0': case '-': case 'f': case 'F': case 'N': break; default: ch |= 1 << bitcnt; } bitcnt++; if (bitcnt==8) { *bptr++ = ch; ch = 0; bitcnt = 0; } } if (bitcnt) { *bptr++ = ch; } return retobj; } static VALUE bits_length(VALUE self) { struct BitSet *bits; Data_Get_Struct(self, struct BitSet, bits); return INT2FIX(bits->len); } static VALUE bits_bytes(VALUE self) { struct BitSet *bits; Data_Get_Struct(self, struct BitSet, bits); return INT2FIX((bits->len+7)/8); } static VALUE bits_resize(VALUE self, VALUE obj) { struct BitSet *bits; int len; Check_Type(obj, T_FIXNUM); len = FIX2INT(obj); if (len<1) { rb_raise(rb_eArgError, "array size"); } Data_Get_Struct(self, struct BitSet, bits); bs_resize(bits, len); return self; } static VALUE bits_to_s(VALUE self) { struct BitSet *bits; unsigned char *ptr; int i; VALUE str; Data_Get_Struct(self, struct BitSet, bits); str = rb_str_new(0, bits->len); ptr = (unsigned char *)RSTRING(str)->ptr; for(i=0; ilen; i++) { *ptr++ = bs_get(bits, i) ? '1' : '0'; } return str; } static VALUE bits_dup(VALUE self) { struct BitSet *orig; struct BitSet *dups; VALUE obj; int bytes; Data_Get_Struct(self, struct BitSet, orig); obj = Data_Make_Struct(CLASS_OF(self), struct BitSet, NULL, bits_free, dups); dups->len = orig->len; bytes = (dups->len+7)/8; dups->ptr = ALLOC_N(unsigned char, bytes); memcpy(dups->ptr, orig->ptr, bytes); return obj; } static VALUE bits_clear(VALUE self) { struct BitSet *bits; Data_Get_Struct(self, struct BitSet, bits); memset(bits->ptr, 0, (bits->len+7)/8); return self; } static VALUE bits_get(VALUE self, VALUE vidx) { struct BitSet *bits; int index; int bit; Data_Get_Struct(self, struct BitSet, bits); Check_Type(vidx, T_FIXNUM); index = FIX2INT(vidx); if (index<0) { rb_raise(rb_eRangeError, "index range"); } bit = bs_get(bits, index); return INT2FIX(bit); } static VALUE bits_set(VALUE self, VALUE vidx, VALUE vobj) { struct BitSet *bits; int index; int bit; Data_Get_Struct(self, struct BitSet, bits); Check_Type(vidx, T_FIXNUM); index = FIX2INT(vidx); if (index<0) { rb_raise(rb_eRangeError, "index range"); } bit = to_bit(vobj); bs_set(bits, index, bit); return self; } static VALUE bits_on(int argc, VALUE *argv, VALUE self) { struct BitSet *bits; int i; Data_Get_Struct(self, struct BitSet, bits); for(i=0; ilen = bits->len; bytes = (rbits->len+7)/8; rbits->ptr = ALLOC_N(unsigned char, bytes); memcpy(rbits->ptr, bits->ptr, bytes); Data_Get_Struct(other, struct BitSet, xbits); bs_or(rbits, xbits); return obj; } static VALUE bits_not(VALUE self) { VALUE obj; struct BitSet *bits, *rbits; int bytes; Data_Get_Struct(self, struct BitSet, bits); obj = Data_Make_Struct(CLASS_OF(self), struct BitSet, NULL, bits_free, rbits); rbits->len = bits->len; bytes = (rbits->len+7)/8; rbits->ptr = ALLOC_N(unsigned char, bytes); memcpy(rbits->ptr, bits->ptr, bytes); bs_not(rbits); return obj; } static VALUE bits_and(VALUE self, VALUE other) { VALUE obj; struct BitSet *bits, *rbits, *xbits; int bytes; Data_Get_Struct(self, struct BitSet, bits); obj = Data_Make_Struct(CLASS_OF(self), struct BitSet, NULL, bits_free, rbits); rbits->len = bits->len; bytes = (rbits->len+7)/8; rbits->ptr = ALLOC_N(unsigned char, bytes); memcpy(rbits->ptr, bits->ptr, bytes); Data_Get_Struct(other, struct BitSet, xbits); bs_and(rbits, xbits); return obj; } static VALUE bits_xor(VALUE self, VALUE other) { VALUE obj; struct BitSet *bits, *rbits, *xbits; int bytes; Data_Get_Struct(self, struct BitSet, bits); obj = Data_Make_Struct(CLASS_OF(self), struct BitSet, NULL, bits_free, rbits); rbits->len = bits->len; bytes = (rbits->len+7)/8; rbits->ptr = ALLOC_N(unsigned char, bytes); memcpy(rbits->ptr, bits->ptr, bytes); Data_Get_Struct(other, struct BitSet, xbits); bs_xor(rbits, xbits); return obj; } static VALUE bits_minus(VALUE self, VALUE other) { VALUE obj; struct BitSet y; struct BitSet *bits, *rbits, *xbits, *ybits; int bytes; Data_Get_Struct(self, struct BitSet, bits); Data_Get_Struct(other, struct BitSet, xbits); obj = Data_Make_Struct(CLASS_OF(self), struct BitSet, NULL, bits_free, rbits); rbits->len = bits->len; bytes = (rbits->len+7)/8; rbits->ptr = ALLOC_N(unsigned char, bytes); memcpy(rbits->ptr, bits->ptr, bytes); ybits = &y; ybits->len = xbits->len; bytes = (xbits->len+7)/8; ybits->ptr = ALLOC_N(unsigned char, bytes); memcpy(ybits->ptr, xbits->ptr, bytes); if (ybits->len < rbits->len) { bs_resize(ybits, rbits->len); } bs_not(ybits); bs_and(rbits, ybits); return obj; } static VALUE bits_cmp(VALUE self, VALUE other) { struct BitSet *sbits, *obits; int smax,omax,bytes; unsigned char *sptr,*optr, sc, oc; Data_Get_Struct(self, struct BitSet, sbits); Data_Get_Struct(other, struct BitSet, obits); smax = bs_max(sbits); omax = bs_max(obits); if (smax < omax) { return INT2FIX(-1); } else if (smax > omax) { return INT2FIX(1); } if (smax < 0) { return INT2FIX(0); } bytes = (smax+7)/8; sptr = sbits->ptr + bytes - 1; optr = obits->ptr + bytes - 1; while(bytes--) { sc = *sptr--; oc = *optr--; if (sc oc) { return INT2FIX(1); } } return INT2FIX(0); } static VALUE bits_zero(VALUE self) { struct BitSet *bits; unsigned char *ptr; int bytes; int i; Data_Get_Struct(self, struct BitSet, bits); bytes = (bits->len+7)/8; ptr = bits->ptr; for(i=0 ; ilen+7)/8; ptr = bits->ptr; for(i=0 ; i=0) { return INT2FIX(index); } else { return Qnil; } } static VALUE bits_min(VALUE self) { struct BitSet *bits; int index; Data_Get_Struct(self, struct BitSet, bits); index = bs_min(bits); if (index>=0) { return INT2FIX(index); } else { return Qnil; } } static VALUE bits_norm(VALUE self) { VALUE obj; struct BitSet *bits; int index; obj = bits_dup(self); Data_Get_Struct(obj, struct BitSet, bits); index = bs_max(bits); if (index<0) { index = 1; } else { index = index + 1; } bs_resize(bits, index); return obj; } static VALUE bits_normx(VALUE self) { struct BitSet *bits; int index; Data_Get_Struct(self, struct BitSet, bits); index = bs_max(bits); index = bs_max(bits); if (index<0) { index = 1; } else { index = index + 1; } bs_resize(bits, index); return self; } static VALUE bits_to_ary(VALUE self) { VALUE ary; struct BitSet *bits; unsigned char *ptr, c; int bytes; int from, to, rest, index, len, cnt; Data_Get_Struct(self, struct BitSet, bits); bytes = (bits->len+7)/8; ary = rb_ary_new(); ptr = bits->ptr; index = 0; len = bits->len; from = -1; to = -1; rest = 0; while(indexrest) { cnt = rest; } rest -= cnt; index += cnt; if (rest>0) { c = c >> cnt; from = index; } } else { cnt = ONE_TABLE[c]; rest -= cnt; index += cnt; if (rest>0) { c = c >> cnt; to = index - 1; if (from==to) { rb_ary_push(ary, INT2FIX(from)); } else { rb_ary_push(ary, rb_funcall(rb_cRange, id_new, 2, INT2FIX(from), INT2FIX(to))); } from = -1; to = -1; } } } if (from >= 0) { to = index - 1; if (from==to) { rb_ary_push(ary, INT2FIX(from)); } else { rb_ary_push(ary, rb_funcall(rb_cRange, id_new, 2, INT2FIX(from), INT2FIX(to))); } } return ary; } static VALUE bits_to_bytes(VALUE self) { struct BitSet *bits; int bytes; Data_Get_Struct(self, struct BitSet, bits); bytes = (bits->len+7)/8; return rb_str_new((char *)bits->ptr,bytes); } static VALUE bits_each(VALUE self) { struct BitSet *bits; int idx,len; Data_Get_Struct(self, struct BitSet, bits); len = bits->len; for(idx=0; idxlen+7)/8; count = 0; ptr = bits->ptr; for(i=0 ; i", bits_cmp, 1); /* tested */ rb_define_method(cBitSet, "zero?", bits_zero, 0); /* tested */ rb_define_method(cBitSet, "nonzero?", bits_nonzero, 0); /* tested */ rb_define_method(cBitSet, "max", bits_max, 0); /* tested */ rb_define_method(cBitSet, "min", bits_min, 0); /* tested */ rb_define_method(cBitSet, "normalize", bits_norm, 0); /* tested */ rb_define_method(cBitSet, "normalize!", bits_normx, 0); /* tested */ rb_define_method(cBitSet, "to_ary", bits_to_ary, 0); /* tested */ rb_define_method(cBitSet, "to_bytes", bits_to_bytes, 0); /* tested */ rb_define_method(cBitSet, "count", bits_count, 0); /* tested */ rb_define_method(cBitSet, "each", bits_each, 0); /* tested */ /* rb_include_module(cBitSet, rb_mEnumerable); */ id_new = rb_intern("new"); id_first = rb_intern("first"); id_end = rb_intern("end"); }