/**
 *  BitVector - Effecient bit vector class extension for Ruby
 *  Copyright (c) 2000 Robert Feldt, feldt@ce.chalmers.se
 *
 *  Robert Feldt
 *  Brolyckan 1
 *  SE-433 68 Savedalen
 *  SWEDEN
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#include "ruby.h"
#include "steffen_beyers_bit_vector/ToolBox.h"
#include "steffen_beyers_bit_vector/BitVector.h"

/* Wrap in struct so that GC works */
struct RBitVector {
  wordptr llbv;
};

/* BitVector class */
static VALUE cBitVector;

/* Constants that we pre-calc at module load time to get better
   performance at run-time. */
static VALUE mMarshal;
static VALUE mKernel;
static VALUE mMath;
static VALUE idNew;
static VALUE idSize;
static VALUE idAref;
static VALUE idDump;
static VALUE idLoad;
static VALUE idAdd;
static VALUE idMinus;
static VALUE idMult;
static VALUE idRand;
static VALUE idBetween;
static VALUE idCvarCarry;
static VALUE idLog10;
static VALUE maxunsignedint; 
static VALUE fixnum1;
static VALUE fixnum2;
static VALUE fixnum0;
static VALUE fixnum31;
static VALUE fixnum32;
static VALUE fixnum2_28;
static VALUE fixnumneg1;
static VALUE log10_2;
static VALUE fix2_to29;
VALUE num2_toX[31]; /* Fixnum 2**X where X in [0..30] */

/* prototype declarations */
static int	valid_bitref(VALUE ref, wordptr llbv);
static void	bv_error(char* method, char* errmsg, VALUE error);
static VALUE	make_ruby_bitvector(wordptr llbv);
static wordptr	get_lowlevel_bitvector(VALUE rbbv);
static void	get_lowlevel_bitvector_and_struct(VALUE rbbv, wordptr *llbv, struct RBitVector **sbv);
static VALUE	bv_version(VALUE klass);
static VALUE	bv_s_new(int argc, VALUE* argv, VALUE class);
static VALUE	bv_s_from_bin(VALUE class, VALUE bits, VALUE str);
static VALUE	bv_s_from_dec(VALUE class, VALUE bits, VALUE str);
static VALUE	bv_s_from_hex(VALUE class, VALUE bits, VALUE str);
static VALUE	bv_s_from_enum(VALUE class, VALUE bits, VALUE str);
static VALUE	bv_s_from_int(int argc, VALUE *argv, VALUE class);
static VALUE	bv_set_bit(VALUE self, VALUE bit, VALUE newval);
static VALUE	bv_concat(VALUE self, VALUE other);
static VALUE	bv_clone(VALUE self);
static VALUE	bv_init_from_bignum(VALUE self, VALUE bits, VALUE bignum);
static VALUE	bv_init_from_fixnum(VALUE self, VALUE bits, VALUE fixnum);
static VALUE	bv_initialize(int argc, VALUE *argv, VALUE self);
static VALUE	bv_aset(int argc, VALUE *argv, VALUE self);
static VALUE	bv_aset(int argc, VALUE *argv, VALUE self);
static VALUE	bv_length(VALUE self);
static void	randomize_bits(wordptr bitvector, N_int start, N_int end, double probability);
static VALUE	bv_randomize(int argc, VALUE *argv, VALUE self);
static VALUE	bv_fill(int argc, VALUE *argv, VALUE self);
static VALUE	bv_empty(int argc, VALUE *argv, VALUE self);
static VALUE	bv_flip(int argc, VALUE *argv, VALUE self);
static VALUE	bv_reverse(int argc, VALUE *argv, VALUE self);
static VALUE	bv_primes(VALUE self);
static VALUE	bv_is_empty(VALUE self);
static VALUE	bv_is_full(VALUE self);
static VALUE	bv_is_equal(VALUE self, VALUE other);
static VALUE	bv_lexicompare(VALUE self, VALUE other);
static VALUE	bv_compare(VALUE self, VALUE other);
static VALUE	bv_to_binstr(VALUE self);
static VALUE	bv_to_hexstr(VALUE self);
static VALUE	bv_to_decstr(VALUE self);
static VALUE	bv_to_enumstr(VALUE self);
static VALUE	bv_off(VALUE self, VALUE bit);
static VALUE	bv_on(VALUE self, VALUE bit);
static VALUE	bv_flipbit(VALUE self, VALUE bit);
static VALUE	bv_bitref(VALUE self, VALUE bit);
static VALUE	bv_aref(int argc, VALUE *argv, VALUE self);
static VALUE	bv_test(VALUE self, VALUE bit);
static VALUE	bv_set_norm(VALUE self);
static VALUE	bv_set_union(VALUE self, VALUE other);
static VALUE	bv_set_intersection(VALUE self, VALUE other);
static VALUE	bv_set_difference(VALUE self, VALUE other);
static VALUE	bv_set_exor(VALUE self, VALUE other);
static VALUE	bv_set_complement(VALUE self);
static VALUE	bv_set_is_subset(VALUE self, VALUE other);
static VALUE	bv_set_is_superset(VALUE self, VALUE other);
static VALUE	bv_set_min(VALUE self);
static VALUE	bv_set_max(VALUE self);
static VALUE	bv_get_lsb(VALUE self);
static VALUE	bv_set_lsb(VALUE self, VALUE newVal);
static VALUE	bv_get_msb(VALUE self);
static VALUE	bv_set_msb(VALUE self, VALUE newVal);
static VALUE	bv_rotate_left(VALUE self);
static VALUE	bv_rotate_right(VALUE self);
static VALUE	bv_shift_left(VALUE self, VALUE carryIn);
static VALUE	bv_shift_right(VALUE self, VALUE carryIn);
static VALUE	bv_move_left(VALUE self, VALUE steps);
static VALUE	bv_move_right(VALUE self, VALUE steps);
static VALUE	bv_increment(VALUE self);
static VALUE	bv_decrement(VALUE self);
static VALUE	bv_substitute(VALUE self, VALUE other, VALUE off1, VALUE len1, VALUE off2, VALUE len2);
static VALUE	bv_dump(VALUE self, VALUE limit);
static VALUE	bv_load(VALUE class, VALUE aString);
static VALUE	bv_to_uint(VALUE self);
static VALUE	bv_to_int(VALUE self);
static VALUE	bv_ones(VALUE self);
static VALUE	bv_zeroes(VALUE self);
static VALUE	bv_resize(VALUE self, VALUE newSize);
static VALUE	bv_set_carry(VALUE self, VALUE newVal);
static VALUE	bv_get_carry(VALUE self);
static VALUE	bv_add(VALUE self, VALUE other);
static VALUE	bv_sub(VALUE self, VALUE other);
static VALUE	bv_negate(VALUE self);
static VALUE	bv_abs(VALUE self);
static VALUE	bv_sign(VALUE self);
static VALUE	bv_multiply(VALUE self, VALUE other);
static VALUE	bv_divide(VALUE self, VALUE other);
static void	bv_free(struct RBitVector *rbv);
void		Init_bitvector(void);

/* Defines */
#define ZERO_OR_FALSE(v) ((fixnum0 == (v)) || (Qfalse == (v)))
#define ONE_OR_TRUE(v) ((fixnum1 == (v)) || (Qtrue == (v)))
#define KINDOF_INT(v) (Qtrue==rb_obj_is_kind_of(v, rb_cInteger))
#define KINDOF_BV(v) (Qtrue==rb_obj_is_kind_of(v, cBitVector))
#define BV_OBJ(v) (Qtrue==rb_obj_is_instance_of(v, cBitVector))
#define ISFLOAT(v) (T_FLOAT==TYPE(v))
#define KINDOF_RANGE(v) (Qtrue==rb_obj_is_kind_of(v, rb_cRange))
#define INSPECT(v) (RSTRING(rb_funcall(v,idInspect,0))->ptr)

/*
 * NOTE: Strange GC bug if I use maxunsignedint instead of recalcing
 * the value.
 *
 * #define VALID_BITNUM(v) ((Qtrue == rb_obj_is_kind_of((v), rb_cInteger)) && (Qtrue == rb_funcall((v),idBetween,2,fixnum0, maxunsignedint)))
 */

#define VALID_BITNUM(v) ((Qtrue == rb_obj_is_kind_of((v), rb_cInteger)) && (Qtrue == rb_funcall((v),idBetween,2,fixnum0, UINT2NUM((N_int)(-1)))))
#define UINTABLE(v) (FIXNUM_P(v) || ((T_BIGNUM==TYPE(v)) && (FIX2INT(rb_funcall(v,idSize,0))<=sizeof(unsigned int))))

static int
valid_bitref(VALUE ref, wordptr llbv)
{
  N_int n;

  if(!KINDOF_INT(ref) || !UINTABLE(ref))
    return false;

  n = NUM2UINT(ref);
  return ((0<=n) && (n<bits_(llbv)));
}
#define VALID_BITREF(v,llbv) valid_bitref(v,llbv)
#define VALID_BITREF2(nint,llbv) ((0<=nint) && (nint<bits_(llbv)))

/** Error handling **/
static void
bv_error(char* method, char* errmsg, VALUE error)
{
  static char buffer[100];
  sprintf(buffer, "%s (%s)", errmsg, method);
  rb_raise(error, buffer);
}

#define BV_ERROR(method, errmsg, error) bv_error(method, errmsg, error)
#define BV_INDEX_ERROR(method) BV_ERROR(method, "invalid bit number", rb_eIndexError)
#define BV_SIZE_ERROR(method) BV_ERROR(method, "invalid size", rb_eArgError)
#define BV_MEMORY_ERROR(method) BV_ERROR(method, "unable to allocate memory", rb_eNoMemError)
#define BV_ERRORCODE(err, method) printf("Error %d in method %s\n", err, method)

/** Converting between Ruby and low-level object **/

/* Free struct */
static void
bv_free(struct RBitVector* rbv)
{
  if(rbv && rbv->llbv) {
    BitVector_Destroy(rbv->llbv);
  }
  if(rbv) {
    xfree(rbv);
  }
}

/* Make Ruby object from low-level object */
static VALUE
make_ruby_bitvector(wordptr llbv)
{
  struct RBitVector *rbv = ALLOC(struct RBitVector);
  rbv->llbv = llbv;
  return Data_Wrap_Struct(cBitVector, 0, bv_free, rbv);
}

/* Get struct from Ruby BitVector */
struct RBitVector *
get_struct_from_rbv(VALUE rbbv)
{
  struct RBitVector *p;
  Data_Get_Struct(rbbv, struct RBitVector, p);
  return p;
}

/* Get low-level object from ruby object */
static wordptr
get_lowlevel_bitvector(VALUE rbbv)
{
  struct RBitVector *p;
  Data_Get_Struct(rbbv, struct RBitVector, p);
  return p->llbv;
}
#define LLBV(rbbv) (get_lowlevel_bitvector(rbbv))

/* Get low-level object and struct from ruby object */
static void
get_lowlevel_bitvector_and_struct(VALUE rbbv, wordptr *llbv,
				  struct RBitVector **sbv)
{
  Data_Get_Struct(rbbv, struct RBitVector, *sbv);
  *llbv = (*sbv)->llbv;
}
#define LLASBV(rbbv,llbv,sbv) get_lowlevel_bitvector_and_struct(rbbv,llbv,sbv)

/** Class method **/
static VALUE
bv_version(VALUE klass)
{
  char buffer[100];
  sprintf(buffer, "BitVector version 0.1.6 using Steffen Beyer's Bit::Vector lib version %s", BitVector_Version());
  return rb_str_new2(buffer);
}

static VALUE
bv_s_new(int argc, VALUE* argv, VALUE class)
{
  VALUE tdata = make_ruby_bitvector(NULL);
  rb_obj_call_init(tdata, argc, argv);
  return tdata;
}

static VALUE
bv_s_from_bin(VALUE class, VALUE bits, VALUE str)
{
  VALUE obj = make_ruby_bitvector(NULL);
  wordptr objll = BitVector_Create(NUM2UINT(bits), false);
  ErrCode err;
  char* strp = RSTRING(str)->ptr;

  err = BitVector_from_Bin(objll, strp);
  if(err)
    rb_raise(rb_eArgError, "not a valid string");

  get_struct_from_rbv(obj)->llbv = objll;
  return obj;
}

static VALUE
bv_s_from_dec(VALUE class, VALUE bits, VALUE str)
{
  VALUE obj = make_ruby_bitvector(NULL);
  wordptr objll = BitVector_Create(NUM2UINT(bits), false);
  ErrCode err;
  char* strp = RSTRING(str)->ptr;

  err = BitVector_from_Dec(objll, strp);
  if(err)
    rb_raise(rb_eArgError, "not a valid string");

  get_struct_from_rbv(obj)->llbv = objll;
  return obj;
}

static VALUE
bv_s_from_hex(VALUE class, VALUE bits, VALUE str)
{
  VALUE obj = make_ruby_bitvector(NULL);
  wordptr objll = BitVector_Create(NUM2UINT(bits), false);
  ErrCode err;
  char* strp = RSTRING(str)->ptr;

  err = BitVector_from_Hex(objll, strp);
  if(err)
    rb_raise(rb_eArgError, "not a valid string");

  get_struct_from_rbv(obj)->llbv = objll;
  return obj;
}

static VALUE
bv_s_from_enum(VALUE class, VALUE bits, VALUE str)
{
  VALUE obj = make_ruby_bitvector(NULL);
  wordptr objll = BitVector_Create(NUM2UINT(bits), false);
  ErrCode err;
  char* strp = RSTRING(str)->ptr;

  err = BitVector_from_Enum(objll, strp);
  if(err)
    rb_raise(rb_eArgError, "not a valid string");

  get_struct_from_rbv(obj)->llbv = objll;
  return obj;
}

static VALUE
bv_s_from_int(int argc, VALUE *argv, VALUE class)
{
  VALUE num_bits;
  VALUE integer = argv[0];
  VALUE obj;
  VALUE temp;
  double t_d;
  int t_i;

  if(!KINDOF_INT(integer))
    rb_raise(rb_eArgError, "invalid type");
  
  if(argc==1) {
    /*
     * Calc minimum bits needed:
     * (Math.log10(integer.abs)/Math.log10(2)).ceil.to_i
     * Add one extra bit for sign bit.
     */
    temp = rb_funcall(integer, rb_intern("abs"), 0);
    temp = rb_funcall(mMath, idLog10, 1, temp);
    t_d = (RFLOAT(temp)->value) / 0.3010299957;
    t_i = (int)t_d;
    t_i += (((t_d-(int)t_d)>0.0)?1:0); /* Add 1 if decimals not zero */
    t_i++; /* Extra bit for sign */
    num_bits = INT2NUM(t_i);
  } else if(KINDOF_INT(argv[1])) {
    num_bits = argv[1];
  }
  
  obj = make_ruby_bitvector(NULL);

  if(FIXNUM_P(integer)) {
    return bv_init_from_fixnum(obj, num_bits, integer);
  } else {
    return bv_init_from_bignum(obj, num_bits, integer);
  }
}

/** Instance methods **/

static VALUE
bv_set_bit(VALUE self, VALUE bit, VALUE newval)
{
  wordptr selfll = LLBV(self);

  if(!VALID_BITREF(bit, selfll))
    BV_INDEX_ERROR("set_bit");

  if(ZERO_OR_FALSE(newval))
    BitVector_Bit_Copy(LLBV(self), NUM2UINT(bit), false);
  else
    BitVector_Bit_Copy(LLBV(self), NUM2UINT(bit), true);
  return self;
}

static VALUE
bv_concat(VALUE self, VALUE other)
{
  if(!KINDOF_BV(other))
    rb_raise(rb_eTypeError, "invalid type");
  return make_ruby_bitvector(BitVector_Concat(LLBV(self), LLBV(other)));
}

static VALUE
bv_clone(VALUE self)
{
  return make_ruby_bitvector(BitVector_Clone(LLBV(self)));
}

static VALUE
bv_init_from_bignum(VALUE self, VALUE bits, VALUE bignum)
{
  N_int num_bits = NUM2UINT(bits);
  wordptr selfll = BitVector_Create(num_bits, true);  
  N_int i;

  for(i = 0; i < num_bits; i++) {
    if(fixnum1 == rb_funcall(bignum, idAref, 1, INT2FIX(i)))
      BitVector_Bit_On(selfll, i);
  }

  get_struct_from_rbv(self)->llbv = selfll;  
  return self;
}

static VALUE
bv_init_from_fixnum(VALUE self, VALUE bits, VALUE fixnum)
{
  N_int num_bits = NUM2UINT(bits);
  wordptr selfll = BitVector_Create(num_bits, true);  
  N_int i;
  unsigned int v = FIX2UINT(fixnum);

  for(i = 0; i < num_bits; i++) {
    if(1 == (v & 0x01)) BitVector_Bit_On(selfll, i);
    v >>= 1;
  }
  get_struct_from_rbv(self)->llbv = selfll;  
  return self;
}

/**
 * BitVector.new(anInteger)       => Create bv with anInteger bits
 * BitVector.new(aBitVector)      => Create clone of aBitVector
 * BitVector.new(bs, anInteger)   => Create bv with bs bits, init from int
 * BitVector.new(nil or false, aFixnum)    => Create bv with 31 bits, init from fixnum
 * BitVector.new(true, aFixnum)    => Create bv with 32 bits, init from fixnum
 * BitVector.new(bs, aFixnum)      => Create bv with bs bits, init from fixnum
 * BitVector.new(nil, aBignum)    => Create bv with needed by bignum and init
 */
static VALUE
bv_initialize(int argc, VALUE *argv, VALUE self)
{
  N_int bits;

  if(1==argc) {
    if(VALID_BITNUM(argv[0])) {
      get_struct_from_rbv(self)->llbv = 
	BitVector_Create(NUM2UINT(argv[0]), true);
      /* printf("Creating BV %u\n", get_struct_from_rbv(self)->llbv); */
      return self;
    } else if(BV_OBJ(argv[0])) {
      get_struct_from_rbv(self)->llbv = BitVector_Clone(LLBV(argv[0]));
      return self;
    } else {
      rb_raise(rb_eArgError, "invalid parameter (must be Fixnum or BitVector)");
    }
  } else if(2==argc) {
    if(FIXNUM_P(argv[1])) {
      if(VALID_BITNUM(argv[0]))
	return bv_init_from_fixnum(self, argv[0], argv[1]);
      else if(RTEST(argv[0]))
	return bv_init_from_fixnum(self, fixnum32, argv[1]);
      else
	return bv_init_from_fixnum(self, fixnum31, argv[1]);
    } else if(T_BIGNUM == TYPE(argv[1])) {
      if(VALID_BITNUM(argv[0]))
	return bv_init_from_bignum(self, argv[0], argv[1]);
      else {
	bits = NUM2UINT(rb_funcall(argv[1],idSize,0))*8;
	return bv_init_from_bignum(self, INT2NUM(bits), argv[1]);
      }
    }
  }
  rb_raise(rb_eArgError, "invalid parameters");
}

/**
 * Similar to Array.[]=
 *
 * bv[i] = v            => Set value of bit i to v
 * bv[r] = v            => Set values of bits in range r to v
 * bv[s,l] = v          => Set values of bits in range s...(s+l) to v
 *
 * v can be {0, false} or {1, true} or bit vector of same size as the bits to
 * be assigned.
 */
static VALUE
bv_aset(int argc, VALUE *argv, VALUE self)
{
  N_int beg, len;
  wordptr selfll = LLBV(self);
  VALUE new_val;
  wordptr otherll;

  if (argc == 3) {
    if(!VALID_BITREF(argv[0],selfll))
      BV_INDEX_ERROR("aset");
    if(!KINDOF_INT(argv[1]))
      rb_raise(rb_eArgError, "arg2 has invalid type (should be kind-of Integer)");
    beg = NUM2UINT(argv[0]);
    len = NUM2UINT(argv[1]);
    new_val = argv[2];
    goto assign_bits;
  }
  if (argc != 2) {
    rb_raise(rb_eArgError, "wrong # of arguments(%d for 2 or 3)", argc);
  }
  if (KINDOF_INT(argv[0])) {
    if(!VALID_BITREF(argv[0],selfll))
      BV_INDEX_ERROR("aset");
    beg = NUM2UINT(argv[0]);
    len = 1;
    new_val = argv[1];
    goto assign_bits;
  }
  if (KINDOF_RANGE(argv[0]) &&
      rb_range_beg_len(argv[0], (long*)&beg, (long*)&len, 
		       bits_(selfll), 1)) {
    new_val = argv[1];
    goto assign_bits;
  }

  rb_raise(rb_eArgError, "invalid arguments");    

 assign_bits:
  if(ZERO_OR_FALSE(new_val))
    BitVector_Interval_Empty(selfll, beg, beg+len-1);
  else if(KINDOF_BV(new_val)) {
    otherll = LLBV(new_val);
    if(bits_(otherll) != len)
      rb_raise(rb_eRangeError, "size of bit vectors mismatch");
    BitVector_Interval_Copy(selfll, otherll, beg, 0, len);
  } else
    BitVector_Interval_Fill(selfll, beg, beg+len-1);
  return new_val;
}

/*
static VALUE
bv_aset(int argc, VALUE *argv, VALUE self)
{
  N_int beg, len;
  wordptr selfll = LLBV(self);

  if (argc == 3) {
    if(!VALID_BITREF(argv[0],selfll))
      BV_INDEX_ERROR("aset");
    if(!KINDOF_INT(argv[1]))
      rb_raise(rb_eArgError, "arg2 has invalid type (should be kind-of Integer)");
    beg = NUM2UINT(argv[0]);
    len = NUM2UINT(argv[1]);
    if(ZERO_OR_FALSE(argv[2]))
      BitVector_Interval_Empty(selfll, beg, beg+len-1);
    else
      BitVector_Interval_Fill(selfll, beg, beg+len-1);
    return argv[2];
  }
  if (argc != 2) {
    rb_raise(rb_eArgError, "wrong # of arguments(%d for 2 or 3)", argc);
  }
  if (KINDOF_INT(argv[0])) {
    if(!VALID_BITREF(argv[0],selfll))
      BV_INDEX_ERROR("aset");
    if(ZERO_OR_FALSE(argv[1]))
      BitVector_Bit_Off(selfll, NUM2UINT(argv[0]));
    else
      BitVector_Bit_On(selfll, NUM2UINT(argv[0]));
    return argv[1];
  }
  if (KINDOF_RANGE(argv[0]) &&
      rb_range_beg_len(argv[0], (long*)&beg, (long*)&len, 
		       bits_(selfll), 1)) {
    if(ZERO_OR_FALSE(argv[1]))
      BitVector_Interval_Empty(selfll, beg, beg+len-1);
    else
      BitVector_Interval_Fill(selfll, beg, beg+len-1);
    return argv[1];
  }
  rb_raise(rb_eArgError, "invalid arguments");    
}
 */

static VALUE
bv_length(VALUE self)
{
  return INT2NUM(bits_(LLBV(self)));
}

static void
randomize_bits(wordptr bitvector, N_int start, N_int end, double probability)
{
  double randfloat;
  N_int i;
  N_long rand_bits;
  N_int current = start;
  N_int bits_left = end-start+1;
  N_int chunk_size;

  if(probability != 0.5) {
    for(i = start; i <= end; i++)
      if(RFLOAT(rb_funcall(mKernel, idRand, 1, fixnum0))->value <= probability)
	BitVector_bit_flip(bitvector, i);
  } else {
    i = bits_left/28;
    for(; i>0; i--) {
      /* Get a random fixnum. We only use 28 bits from it so that we're sure no */
      /* Bignums are involved. */
      rand_bits = FIX2UINT(rb_funcall(mKernel, idRand, 1, fixnum2_28));

      /* Copy them to bitvector */
      BitVector_Chunk_Store(bitvector, 28, current, rand_bits);
      current += 28;
    }

    if(bits_left % 28) {
      rand_bits = FIX2UINT(rb_funcall(mKernel, idRand, 1, fixnum2_28));
      BitVector_Chunk_Store(bitvector, bits_left%28, current, rand_bits);
    }
  }
}

/**
 * bv.randomize(prob=0.5)       => Randomize all bits with probability prob
 * bv.randomize(s, prob=0.5)    => Randomize bit s with probability prob
 * bv.randomize(s, l, prob=0.5) => Randomize bits s...(s+l) with prob
 * bv.randomize(range, prob=0.5) => Randomize bits in range with prob
 */
static VALUE
bv_randomize(int argc, VALUE *argv, VALUE self)
{
  wordptr selfll = LLBV(self);
  double prob = 0.5;
  N_int beg, len;

  if(argc==0) {
    beg = 0;
    len = bits_(selfll);
  } else if(argc==1) {
    if(KINDOF_INT(argv[0])) {
      if(!VALID_BITREF(argv[0],selfll))
	BV_INDEX_ERROR("randomize");
      beg = NUM2UINT(argv[0]);
      len = 1;
    } else if(ISFLOAT(argv[0])) {
      beg = 0;
      len = bits_(selfll);
      prob = RFLOAT(argv[0])->value;
    } else if(KINDOF_RANGE(argv[0])) {
      rb_range_beg_len(argv[0], (long*)&beg, (long*)&len, bits_(selfll), 1);
    } else
      rb_raise(rb_eArgError, "invalid parameters");
  } else if(argc==2) {
    if(VALID_BITNUM(argv[0]) && VALID_BITNUM(argv[1])) {
      beg = NUM2UINT(argv[0]);
      len = NUM2UINT(argv[1]);
    } else if(VALID_BITNUM(argv[0]) && ISFLOAT(argv[1])) {
      beg = NUM2UINT(argv[0]);
      len = 1;
      prob = RFLOAT(argv[1])->value;
    } else if(rb_obj_is_kind_of(argv[0], rb_cRange) &&
	      T_FLOAT == TYPE(argv[1])) {
      rb_range_beg_len(argv[0], (long*)&beg, (long*)&len, bits_(selfll), 1);
      prob = RFLOAT(argv[1])->value;
    } else
      rb_raise(rb_eArgError, "invalid parameters");
  } else if(argc==3) {
    if(VALID_BITNUM(argv[0]) && VALID_BITNUM(argv[1]) &&
       (T_FLOAT == TYPE(argv[2]))) {
      beg = NUM2UINT(argv[0]);
      len = NUM2UINT(argv[1]);
      prob = RFLOAT(argv[2])->value;
    } else {
      rb_raise(rb_eArgError, "invalid parameters");
    }
  } else {
    rb_raise(rb_eArgError, "invalid parameters");
  }

 randomize_now:
  if(!VALID_BITREF2(beg,selfll))
    BV_INDEX_ERROR("randomize");
  randomize_bits(selfll, beg, beg+len-1, prob);
  return self;
}

/**
 * bv.fill         => All bits gets value 1
 * bv.fill(s)      => Bit s gets value 1
 * bv.fill(s,l)    => Bits s...(s+l) gets value 1
 * bv.fill(range)  => Bits in range gets value 1
 */
static VALUE
bv_fill(int argc, VALUE *argv, VALUE self)
{
  wordptr selfll = LLBV(self);
  N_int beg, len;

  if(argc==0)
    BitVector_Fill(selfll);
  else if(argc==2) {
    if(!VALID_BITREF(argv[0],selfll))
      BV_INDEX_ERROR("fill");
    beg = NUM2UINT(argv[0]);
    len = NUM2UINT(argv[1]);
    BitVector_Interval_Fill(selfll, beg, beg+len-1);
  } else if((argc==1) && VALID_BITREF(argv[0],selfll))
    BitVector_Bit_On(selfll, NUM2UINT(argv[0]));
  else if (rb_range_beg_len(argv[0], (long*)&beg, (long*)&len, 
			    bits_(selfll), 1)) {
    if(!VALID_BITREF2(beg,selfll))
      BV_INDEX_ERROR("fill");
    BitVector_Interval_Fill(selfll, beg, beg+len-1);
  } else
    rb_raise(rb_eArgError, "invalid parameters");

  return self;
}

/**
 * bv.empty         => All bits gets value 0
 * bv.empty(s)      => Bits s gets value 0
 * bv.empty(s,l)    => Bits s...(s+l) gets value 0
 * bv.empty(range)  => Bits in range gets value 0
 */
static VALUE
bv_empty(int argc, VALUE *argv, VALUE self)
{
  wordptr selfll = LLBV(self);
  N_int beg, len;

  if(argc==0)
    BitVector_Empty(selfll);
  else if(argc==2) {
    beg = NUM2UINT(argv[0]);
    len = NUM2UINT(argv[1]);
    BitVector_Interval_Empty(selfll, beg, beg+len-1);
  } else if((argc==1) && VALID_BITREF(argv[0],selfll))
    BitVector_Bit_Off(selfll, NUM2UINT(argv[0]));
  else if (rb_range_beg_len(argv[0], (long*)&beg, (long*)&len, bits_(selfll), 1))
    BitVector_Interval_Empty(selfll, beg, beg+len-1);

  return self;
}

/**
 * bv.flip         => All bits are flipped
 * bv.flip(s)      => Bits s is flipped
 * bv.flip(s,l)    => Bits s...(s+l) are flipped
 * bv.flip(range)  => Bits in range are flipped
 */
static VALUE
bv_flip(int argc, VALUE *argv, VALUE self)
{
  wordptr selfll = LLBV(self);
  N_int beg, len;

  if(argc==0)
    BitVector_Flip(selfll);
  else if(argc==2) {
    beg = NUM2UINT(argv[0]);
    len = NUM2UINT(argv[1]);
    BitVector_Interval_Flip(selfll, beg, beg+len-1);
  } else if((argc==1) && VALID_BITREF(argv[0],selfll))
    BitVector_bit_flip(selfll, NUM2UINT(argv[0]));
  else if (rb_range_beg_len(argv[0], (long*)&beg, (long*)&len, bits_(selfll), 1))
    BitVector_Interval_Flip(selfll, beg, beg+len-1);

  return self;
}

/**
 * bv.reverse         => All bits are reversed
 * bv.reverse(s)      => Bits s reversed (ie. nothing happens!)
 * bv.reverse(s,l)    => Bits s...(s+l) are reversed
 * bv.reverse(range)  => Bits in range are reversed
 */
static VALUE
bv_reverse(int argc, VALUE *argv, VALUE self)
{
  wordptr selfll = LLBV(self);
  wordptr newll;
  N_int beg, len;

  if(argc==0) {
    newll = BitVector_Create(bits_(selfll), false);
    BitVector_Reverse(newll, selfll);
    BitVector_Destroy(selfll);
    get_struct_from_rbv(self)->llbv = newll;
  } else if(argc==2) {
    beg = NUM2UINT(argv[0]);
    len = NUM2UINT(argv[1]);
    BitVector_Interval_Reverse(selfll, beg, beg+len-1);
  } else if (rb_range_beg_len(argv[0], (long*)&beg, (long*)&len, bits_(selfll), 1))
    BitVector_Interval_Reverse(selfll, beg, beg+len-1);

  return self;
}

static VALUE
bv_primes(VALUE self)
{
  BitVector_Primes(LLBV(self));
  return self;
}

static VALUE
bv_is_empty(VALUE self)
{
  if(BitVector_is_empty(LLBV(self)))
    return Qtrue;
  else
    return Qfalse;
}

static VALUE
bv_is_full(VALUE self)
{
  if(BitVector_is_full(LLBV(self)))
    return Qtrue;
  else
    return Qfalse;
}

static VALUE
bv_is_equal(VALUE self, VALUE other)
{
  if(KINDOF_BV(other) && BitVector_equal(LLBV(self), LLBV(other)))
    return Qtrue;
  else
    return Qfalse;
}

static VALUE
bv_lexicompare(VALUE self, VALUE other)
{
  if(!KINDOF_BV(other))
    rb_raise(rb_eTypeError, "invalid type (lexicompare)");
  return INT2FIX(BitVector_Lexicompare(LLBV(self), LLBV(other)));
}

static VALUE
bv_compare(VALUE self, VALUE other)
{
  if(!KINDOF_BV(other))
    rb_raise(rb_eTypeError, "invalid type (<=> or compare)");
  return INT2FIX(BitVector_Compare(LLBV(self), LLBV(other)));
}

static VALUE
bv_to_binstr(VALUE self)
{
  charptr p = BitVector_to_Bin(LLBV(self));
  VALUE str = rb_str_new2(p);
  BitVector_Dispose(p);
  return str;
}

static VALUE
bv_to_hexstr(VALUE self)
{
  charptr p = BitVector_to_Hex(LLBV(self));
  VALUE str = rb_str_new2(p);
  BitVector_Dispose(p);
  return str;
}

static VALUE
bv_to_decstr(VALUE self)
{
  charptr p = BitVector_to_Dec(LLBV(self));
  VALUE str = rb_str_new2(p);
  BitVector_Dispose(p);
  return str;
}

static VALUE
bv_to_enumstr(VALUE self)
{
  charptr p = BitVector_to_Enum(LLBV(self));
  VALUE str = rb_str_new2(p);
  BitVector_Dispose(p);
  return str;
}

static VALUE
bv_off(VALUE self, VALUE bit)
{
  BitVector_Bit_Off(LLBV(self), NUM2UINT(bit));
  return self;
}

static VALUE
bv_on(VALUE self, VALUE bit)
{
  BitVector_Bit_On(LLBV(self), NUM2UINT(bit));
  return self;
}

static VALUE
bv_flipbit(VALUE self, VALUE bit)
{
  if(BitVector_bit_flip(LLBV(self), NUM2UINT(bit)))
    return fixnum1;
  else
    return fixnum0;
}

static VALUE
bv_bitref(VALUE self, VALUE bit)
{
  if(BitVector_bit_test(LLBV(self), NUM2UINT(bit)))
    return fixnum1;
  else
    return fixnum0;
}

static VALUE
bv_aref(int argc, VALUE *argv, VALUE self)
{
  N_int beg, len, i, cnt;
  wordptr selfll = LLBV(self);
  wordptr newll;

  /* bv[anInteger] */
  if (argc == 1 && KINDOF_INT(argv[0])) {
    if(!VALID_BITREF(argv[0], selfll))
      BV_INDEX_ERROR("aref");
    beg = NUM2UINT(argv[0]);
    len = 1;
    goto get_aref_bits;
  }
  
  /* bv[anInteger, anInteger] */
  if (argc == 2 && KINDOF_INT(argv[0]) && KINDOF_INT(argv[1])) {
    if(!VALID_BITREF(argv[0], selfll))
      BV_INDEX_ERROR("aref");
    beg = NUM2UINT(argv[0]);
    len = NUM2UINT(argv[1]);
    goto get_aref_bits;
  }

  /* bv[aRange] */
  if (argc==1 && KINDOF_RANGE(argv[0])) {
    rb_range_beg_len(argv[0], (long*)&beg, (long*)&len, bits_(selfll), 1);
    if(!VALID_BITREF2(beg, selfll))
      BV_INDEX_ERROR("aref");
    goto get_aref_bits;
  }

  rb_raise(rb_eArgError, "invalid arguments");    

 get_aref_bits:
  if(len==1) {
    if(BitVector_bit_test(selfll, beg))
      return fixnum1;
    else
      return fixnum0;
  } else if(len==0) {
    return Qnil;
  } else {
    newll = BitVector_Create(len, true);
    BitVector_Interval_Copy(newll, selfll, 0, beg, len); /* Does not work!! */
    return make_ruby_bitvector(newll);
  }
}

static VALUE
bv_test(VALUE self, VALUE bit)
{
  if(BitVector_bit_test(LLBV(self), NUM2UINT(bit)))
    return Qtrue;
  else
    return Qfalse;
}

static VALUE
bv_set_norm(VALUE self)
{
  return INT2NUM(Set_Norm(LLBV(self)));
}

static VALUE
bv_set_union(VALUE self, VALUE other)
{
  wordptr selfll = LLBV(self);
  wordptr otherll;
  wordptr newll;
  int bits = bits_(selfll);
  int bits_other;

  if(!KINDOF_BV(other))
    rb_raise(rb_eTypeError, "invalid type (union)");
  otherll = LLBV(other);
  bits_other = bits_(otherll);

  if(bits != bits_other)
    rb_raise(rb_eArgError, "vectors differ in length");

  newll = BitVector_Create(bits, false); /* No need to clear */
  Set_Union(newll, selfll, otherll);

  return make_ruby_bitvector(newll);
}

static VALUE
bv_set_intersection(VALUE self, VALUE other)
{
  wordptr selfll = LLBV(self);
  wordptr otherll;
  wordptr newll;
  int bits = bits_(selfll);
  int bits_other;

  if(!KINDOF_BV(other))
    rb_raise(rb_eTypeError, "invalid type (union)");
  otherll = LLBV(other);
  bits_other = bits_(otherll);

  if(bits != bits_other)
    rb_raise(rb_eArgError, "vectors differ in length");

  newll = BitVector_Create(bits, false); /* No need to clear */
  Set_Intersection(newll, selfll, otherll);

  return make_ruby_bitvector(newll);
}

static VALUE
bv_set_difference(VALUE self, VALUE other)
{
  wordptr selfll = LLBV(self);
  wordptr otherll;
  wordptr newll;
  int bits = bits_(selfll);
  int bits_other;

  if(!KINDOF_BV(other))
    rb_raise(rb_eTypeError, "invalid type (union)");
  otherll = LLBV(other);
  bits_other = bits_(otherll);

  if(bits != bits_other)
    rb_raise(rb_eArgError, "vectors differ in length");

  newll = BitVector_Create(bits, false); /* No need to clear */
  Set_Difference(newll, selfll, otherll);

  return make_ruby_bitvector(newll);
}

static VALUE
bv_set_exor(VALUE self, VALUE other)
{
  wordptr selfll = LLBV(self);
  wordptr otherll;
  wordptr newll;
  int bits = bits_(selfll);
  int bits_other;

  if(!KINDOF_BV(other))
    rb_raise(rb_eTypeError, "invalid type (union)");
  otherll = LLBV(other);
  bits_other = bits_(otherll);

  if(bits != bits_other)
    rb_raise(rb_eArgError, "vectors differ in length");

  newll = BitVector_Create(bits, false); /* No need to clear */
  Set_ExclusiveOr(newll, selfll, otherll);

  return make_ruby_bitvector(newll);
}


static VALUE
bv_set_complement(VALUE self)
{
  wordptr selfll = LLBV(self);
  wordptr newll;

  newll = BitVector_Create(bits_(selfll), false); /* No need to clear */
  Set_Complement(newll, selfll);

  return make_ruby_bitvector(newll);
}

static VALUE
bv_set_is_subset(VALUE self, VALUE other)
{
  if(KINDOF_BV(other) && Set_subset(LLBV(self), LLBV(other)))
    return Qtrue;
  else
    return Qfalse;
}

static VALUE
bv_set_is_superset(VALUE self, VALUE other)
{
  if(KINDOF_BV(other) && Set_subset(LLBV(other), LLBV(self)))
    return Qtrue;
  else
    return Qfalse;
}

static VALUE
bv_set_min(VALUE self)
{
  return INT2NUM(Set_Min(LLBV(self)));
}

static VALUE
bv_set_max(VALUE self)
{
  return INT2NUM(Set_Max(LLBV(self)));
}

static VALUE
bv_get_lsb(VALUE self)
{
  if(BitVector_lsb_(LLBV(self)))
    return fixnum1;
  else
    return fixnum0;
}

static VALUE
bv_set_lsb(VALUE self, VALUE newVal)
{
  if(ZERO_OR_FALSE(newVal))
    BitVector_LSB(LLBV(self), false);
  else
    BitVector_LSB(LLBV(self), true);
  return self;
}

static VALUE
bv_get_msb(VALUE self)
{
  if(BitVector_msb_(LLBV(self)))
    return fixnum1;
  else
    return fixnum0;
}

static VALUE
bv_set_msb(VALUE self, VALUE newVal)
{
  if(ZERO_OR_FALSE(newVal))
    BitVector_MSB(LLBV(self), false);
  else
    BitVector_MSB(LLBV(self), true);
  return self;
}

static VALUE
bv_rotate_left(VALUE self)
{
  if(BitVector_rotate_left(LLBV(self)))
    return fixnum1;
  else
    return fixnum0;
}

static VALUE
bv_rotate_right(VALUE self)
{
  if(BitVector_rotate_right(LLBV(self)))
    return fixnum1;
  else
    return fixnum0;
}

static VALUE
bv_shift_left(VALUE self, VALUE carryIn)
{
  if(BitVector_shift_left(LLBV(self), !ZERO_OR_FALSE(carryIn)))
    return fixnum1;
  else
    return fixnum0;
}

static VALUE
bv_shift_right(VALUE self, VALUE carryIn)
{
  if(BitVector_shift_right(LLBV(self), !ZERO_OR_FALSE(carryIn)))
    return fixnum1;
  else
    return fixnum0;
}

static VALUE
bv_move_left(VALUE self, VALUE steps)
{
  if(!KINDOF_INT(steps))
    rb_raise(rb_eTypeError, "invalid type");
  BitVector_Move_Left(LLBV(self), NUM2UINT(steps));
  return self;
}

static VALUE
bv_move_right(VALUE self, VALUE steps)
{
  if(!KINDOF_INT(steps))
    rb_raise(rb_eTypeError, "invalid type");
  BitVector_Move_Right(LLBV(self), NUM2UINT(steps));
  return self;
}

static VALUE
bv_increment(VALUE self)
{
  BitVector_increment(LLBV(self));
  return self;
}

static VALUE
bv_decrement(VALUE self)
{
  BitVector_decrement(LLBV(self));
  return self;
}

static VALUE
bv_substitute(VALUE self, VALUE other, 
	      VALUE off1, VALUE len1, VALUE off2, VALUE len2)
{
  wordptr selfll = LLBV(self);
  wordptr otherll = LLBV(other);
  N_int self_bits = bits_(selfll);
  N_int other_bits = bits_(otherll);
  N_int offset1;
  N_int offset2;

  if(!(KINDOF_INT(off1) && KINDOF_INT(off2) && 
       KINDOF_INT(len1) && KINDOF_INT(len2)))
    rb_raise(rb_eArgError, "invalid arg types");

  offset1 = NUM2UINT(off1);
  offset2 = NUM2UINT(off2);

  if(!(offset1 >= 0 && offset1<(self_bits+1) &&
       offset2 >= 0 && offset2<(other_bits+1)))
    BV_INDEX_ERROR("substitute");

  BitVector_Interval_Substitute(selfll, otherll,
				offset1, NUM2UINT(len1),
				offset2, NUM2UINT(len2));
  return self;
}

static VALUE
bv_dump(VALUE self, VALUE limit)
{
  N_int num_chars;
  wordptr selfll = LLBV(self);
  charptr str = BitVector_Block_Read(selfll, &num_chars);
  VALUE dumped_str = rb_str_new2(str);
  VALUE ary = rb_ary_new();

  BitVector_Dispose(str);
  rb_ary_push(ary, INT2NUM(bits_(selfll)));
  rb_ary_push(ary, dumped_str);
  return rb_funcall(mMarshal, idDump, 1, ary);
}

static VALUE
bv_load(VALUE class, VALUE aString)
{
  VALUE ary = rb_funcall(mMarshal, idLoad, 1, aString);
  VALUE argv[1];
  VALUE obj;
  VALUE temp;

  argv[0] = rb_ary_entry(ary, 0);
  obj = bv_s_new(1, argv, class);
  temp = rb_ary_entry(ary,1);
  BitVector_Block_Store(LLBV(obj), RSTRING(temp)->ptr, RSTRING(temp)->len);
  return obj;
}

static VALUE
bv_to_uint(VALUE self)
{
  wordptr selfll = LLBV(self);
  N_int num_bits = bits_(selfll);
  VALUE acc = fixnum0;
  VALUE temp;
  N_int i, bits_left, current = num_bits;
  N_long l;

  if(num_bits < 30) {
    l = BitVector_Chunk_Read(selfll, num_bits, 0);
    return UINT2NUM((unsigned int)l);
  } else {
    i = num_bits/29;
    for(i = 0; i < (num_bits/29); i++) {
      current -= 29;
      acc = rb_funcall(acc, idMult, 1, fix2_to29); /* acc *= (2**29) */
      l = BitVector_Chunk_Read(selfll, 29, current);
      temp = INT2FIX((unsigned int)l);
      acc = rb_funcall(acc, idAdd, 1, temp); /* acc += temp */
    }
    bits_left = num_bits%29;
    if(bits_left) {
      /* acc *= (2**bits_left) */
      acc = rb_funcall(acc, idMult, 1, num2_toX[bits_left]); 
      l = BitVector_Chunk_Read(selfll, bits_left, 0);
      temp = UINT2NUM((unsigned int)l);
      acc = rb_funcall(acc, idAdd, 1, temp); /* acc += temp */
    }
    return acc;
  }
}

static VALUE
bv_to_int(VALUE self)
{
  wordptr selfll = LLBV(self);
  VALUE uint = bv_to_uint(self);
  VALUE temp;

  if(-1 == BitVector_Sign(selfll)) {
    temp = rb_big_pow(fixnum2, UINT2NUM(bits_(selfll)));
    return rb_funcall(uint, idMinus, 1, temp);
  } else {
    return uint;
  }
}

static VALUE
bv_ones(VALUE self)
{
  VALUE ary = rb_ary_new();
  wordptr selfll = LLBV(self);
  N_int i = 0;

  for(i = 0; i < bits_(selfll); i++) {
    if(BitVector_bit_test(selfll, i))
      rb_ary_push(ary, INT2FIX(i));
  }

  return ary;
}

static VALUE
bv_zeroes(VALUE self)
{
  VALUE ary = rb_ary_new();
  wordptr selfll = LLBV(self);
  N_int i = 0;

  for(i = 0; i < bits_(selfll); i++) {
    if(!BitVector_bit_test(selfll, i))
      rb_ary_push(ary, INT2FIX(i));
  }

  return ary;
}

static VALUE
bv_resize(VALUE self, VALUE newSize)
{
  wordptr llbv;
  struct RBitVector *sbv;
  N_int new_bits;

  LLASBV(self, &llbv, &sbv);
  if(!VALID_BITNUM(newSize))
    BV_SIZE_ERROR("resize");

  sbv->llbv = BitVector_Resize(llbv, NUM2UINT(newSize));
  if(NULL == sbv->llbv)
    BV_MEMORY_ERROR("resize");

  return self;
}

static VALUE
bv_set_carry(VALUE self, VALUE newVal)
{
#ifdef HAVE_RB_CVAR_DECLARE
  rb_cvar_set(cBitVector, idCvarCarry, newVal);
#else
  rb_cvar_set(cBitVector, idCvarCarry, newVal, Qfalse);
#endif
}

static VALUE
bv_get_carry(VALUE self)
{
  return rb_cvar_get(cBitVector, idCvarCarry);
}

static VALUE
bv_add(VALUE self, VALUE other)
{
  wordptr selfll = LLBV(self);
  N_int num_bits = bits_(selfll);
  wordptr otherll;
  wordptr newll;
  boolean carry = 0;
  VALUE argv[2];

  if(KINDOF_BV(other)) {
    otherll = LLBV(other);
  } else if(KINDOF_INT(other)) {
    argv[0] = other;
    argv[1] = UINT2NUM(num_bits);
    otherll = LLBV(bv_s_from_int(2, argv, cBitVector));
  } else {
    rb_raise(rb_eTypeError, "invalid type");
  }

  if(bits_(otherll) != num_bits)
    BV_SIZE_ERROR("add");

  newll = BitVector_Create(num_bits, false);
  BitVector_compute(newll, selfll, otherll, false, &carry);

  bv_set_carry(self, (carry ? fixnum1 : fixnum0));

  return make_ruby_bitvector(newll);
}

static VALUE
bv_sub(VALUE self, VALUE other)
{
  wordptr selfll = LLBV(self);
  N_int num_bits = bits_(selfll);
  wordptr otherll;
  wordptr newll;
  boolean carry = 0;
  VALUE argv[2];

  if(KINDOF_BV(other)) {
    otherll = LLBV(other);
  } else if(KINDOF_INT(other)) {
    argv[0] = other;
    argv[1] = UINT2NUM(num_bits);
    otherll = LLBV(bv_s_from_int(2, argv, cBitVector));
  } else {
    rb_raise(rb_eTypeError, "invalid type");
  }

  if(bits_(otherll) != num_bits)
    BV_SIZE_ERROR("sub");

  newll = BitVector_Create(num_bits, false);
  BitVector_compute(newll, selfll, otherll, true, &carry);

  bv_set_carry(self, (carry ? fixnum1 : fixnum0));

  return make_ruby_bitvector(newll);
}

static VALUE
bv_negate(VALUE self)
{
  wordptr selfll = LLBV(self);
  N_int num_bits = bits_(selfll);
  wordptr newll;

  newll = BitVector_Create(num_bits, false);
  BitVector_Negate(newll, selfll);
  return make_ruby_bitvector(newll);
}

static VALUE
bv_abs(VALUE self)
{
  wordptr selfll = LLBV(self);
  N_int num_bits = bits_(selfll);
  wordptr newll;

  newll = BitVector_Create(num_bits, false);
  BitVector_Absolute(newll, selfll);
  return make_ruby_bitvector(newll);
}

static VALUE
bv_sign(VALUE self)
{
  Z_int sign = BitVector_Sign(LLBV(self));
  switch(sign) {
  case -1:
    return fixnumneg1;
  case 1:
    return fixnum1;
  case 0:
    return fixnum0;
  }
}

static VALUE
bv_multiply(VALUE self, VALUE other)
{
  wordptr selfll = LLBV(self);
  N_int num_bits = bits_(selfll);
  wordptr otherll;
  wordptr newll;
  VALUE argv[2];
  ErrCode err;

  if(KINDOF_BV(other)) {
    otherll = LLBV(other);
  } else if(KINDOF_INT(other)) {
    argv[0] = other;
    argv[1] = UINT2NUM(num_bits);
    otherll = LLBV(bv_s_from_int(2, argv, cBitVector));
  } else {
    rb_raise(rb_eTypeError, "invalid type");
  }

  if(bits_(otherll) != num_bits)
    BV_SIZE_ERROR("add");

  newll = BitVector_Create(2*num_bits, false); /* Expand since multiply... */
  
  if(err = BitVector_Multiply(newll, selfll, otherll))    
    BV_ERRORCODE(err, "multiply");

  return make_ruby_bitvector(newll);
}

static VALUE
bv_divide(VALUE self, VALUE other)
{
  wordptr selfll = LLBV(self);
  N_int num_bits = bits_(selfll);
  wordptr otherll;
  wordptr qll;
  wordptr rll;
  VALUE argv[2];

  if(KINDOF_BV(other)) {
    otherll = LLBV(other);
  } else if(KINDOF_INT(other)) {
    argv[0] = other;
    argv[1] = UINT2NUM(num_bits);
    otherll = LLBV(bv_s_from_int(2, argv, cBitVector));
  } else {
    rb_raise(rb_eTypeError, "invalid type");
  }

  if(bits_(otherll) != num_bits)
    BV_SIZE_ERROR("add");

  qll = BitVector_Create(num_bits, false);
  rll = BitVector_Create(num_bits, false);
  BitVector_Divide(qll, selfll, otherll, rll);
  BitVector_Destroy(rll); /* TODO: Make use of Remainder */

  return make_ruby_bitvector(qll);
}

/** Init code **/
void Init_bitvector()
{
  int i;
  char buffer[20];

  BitVector_Boot();
  
  mMarshal = rb_eval_string("Marshal");
  mKernel = rb_eval_string("Kernel");
  mMath = rb_eval_string("Math");
  idNew = rb_intern("new");
  idSize = rb_intern("size");
  idAref = rb_intern("[]");
  idDump = rb_intern("dump");
  idLoad = rb_intern("load");
  idAdd = rb_intern("+");
  idMinus = rb_intern("-");
  idMult = rb_intern("*");
  idRand = rb_intern("rand");
  idBetween = rb_intern("between?");
  idCvarCarry = rb_intern("@@carry");
  idLog10 = rb_intern("log10");
  fixnum1 = INT2FIX(1);
  fixnum2 = INT2FIX(2);
  fixnum0 = INT2FIX(0);
  fixnumneg1 = INT2FIX(-1);
  fixnum31 = INT2FIX(31);
  fixnum32 = INT2FIX(32);
  fixnum2_28 = UINT2NUM(1<<28);
  fix2_to29 = INT2FIX(1<<29);
  for(i=0; i<31; i++)
    num2_toX[i] = UINT2NUM(1<<i);
  log10_2 = rb_eval_string("Math.log10(2.0)");

  /*
   * Max size of bit vectors is the max value that can be held in an
   * N_int since Steffen Beyer's Bit::Vector uses N_int to specify
   * size when creating a bit vector.
   */

  maxunsignedint = UINT2NUM((N_int)(-1));

  /*
  rb_funcall(rb_funcall(fixnum2, rb_intern("**"), 1, INT2FIX(sizeof(N_int)*8)), 
		       rb_intern("-"), 1, fixnum1);
  */

  cBitVector = rb_define_class("BitVector", rb_cObject);

  rb_define_singleton_method(cBitVector, "version", bv_version, 0);

  rb_define_singleton_method(cBitVector, "new", bv_s_new, -1);
  rb_define_singleton_method(cBitVector, "from_bin", bv_s_from_bin, 2);
  rb_define_singleton_method(cBitVector, "from_dec", bv_s_from_dec, 2);
  rb_define_singleton_method(cBitVector, "from_hex", bv_s_from_hex, 2);
  rb_define_singleton_method(cBitVector, "from_enum", bv_s_from_enum, 2);
  rb_define_singleton_method(cBitVector, "from_int", bv_s_from_int, -1);

  rb_define_method(cBitVector, "initialize", bv_initialize, -1);
  rb_define_method(cBitVector, "length", bv_length, 0);

  rb_define_method(cBitVector, "clone", bv_clone, 0);

  rb_define_method(cBitVector, "concat", bv_concat, 1);

  rb_define_method(cBitVector, "fill", bv_fill, -1);
  rb_define_method(cBitVector, "empty", bv_empty, -1);
  rb_define_method(cBitVector, "flip", bv_flip, -1);
  rb_define_method(cBitVector, "reverse", bv_reverse, -1);

  rb_define_method(cBitVector, "primes", bv_primes, 0);

  rb_define_method(cBitVector, "empty?", bv_is_empty, 0);
  rb_define_method(cBitVector, "full?", bv_is_full, 0);
  rb_define_method(cBitVector, "equal?", bv_is_equal, 1);
  rb_define_method(cBitVector, "==", bv_is_equal, 1);
  rb_define_method(cBitVector, "lexicompare", bv_lexicompare, 1);
  rb_define_method(cBitVector, "compare", bv_compare, 1);
  rb_define_method(cBitVector, "<=>", bv_compare, 1);

  rb_define_method(cBitVector, "to_bin_str", bv_to_binstr, 0);
  rb_define_method(cBitVector, "inspect", bv_to_binstr, 0);
  rb_define_method(cBitVector, "to_hex_str", bv_to_hexstr, 0);
  rb_define_method(cBitVector, "to_dec_str", bv_to_decstr, 0);
  rb_define_method(cBitVector, "to_enum_str", bv_to_enumstr, 0);

  rb_define_method(cBitVector, "on", bv_on, 1);
  rb_define_method(cBitVector, "bit_on", bv_on, 1);
  rb_define_method(cBitVector, "off", bv_off, 1);
  rb_define_method(cBitVector, "bit_off", bv_off, 1);
  rb_define_method(cBitVector, "flip_bit", bv_flipbit, 1);
  rb_define_method(cBitVector, "bit_flip", bv_flipbit, 1);

  rb_define_method(cBitVector, "bit", bv_bitref, 1);
  rb_define_method(cBitVector, "test?", bv_test, 1);
  rb_define_method(cBitVector, "[]", bv_aref, -1);

  rb_define_method(cBitVector, "set", bv_set_bit, 2);
  rb_define_method(cBitVector, "[]=", bv_aset, -1);
 
  rb_define_method(cBitVector, "union", bv_set_union, 1);
  rb_define_method(cBitVector, "|", bv_set_union, 1);
  rb_define_method(cBitVector, "intersection", bv_set_intersection, 1);
  rb_define_method(cBitVector, "&", bv_set_intersection, 1);
  rb_define_method(cBitVector, "difference", bv_set_difference, 1);
  rb_define_method(cBitVector, "-", bv_set_difference, 1);
  rb_define_method(cBitVector, "exclusive_or", bv_set_exor, 1);
  rb_define_method(cBitVector, "^", bv_set_exor, 1);
  rb_define_method(cBitVector, "complement", bv_set_complement, 0);
  rb_define_method(cBitVector, "~", bv_set_complement, 0);
  rb_define_method(cBitVector, "subset?", bv_set_is_subset, 1);
  rb_define_method(cBitVector, "superset?", bv_set_is_superset, 1);
  rb_define_method(cBitVector, "norm", bv_set_norm, 0);
  rb_define_method(cBitVector, "min", bv_set_min, 0);
  rb_define_method(cBitVector, "min", bv_set_min, 0);
  rb_define_method(cBitVector, "max", bv_set_max, 0);
  rb_define_method(cBitVector, "max", bv_set_max, 0);

  rb_define_method(cBitVector, "msb=", bv_set_msb, 1);
  rb_define_method(cBitVector, "msb", bv_get_msb, 0);
  rb_define_method(cBitVector, "lsb=", bv_set_lsb, 1);
  rb_define_method(cBitVector, "lsb", bv_get_lsb, 0);
  rb_define_method(cBitVector, "rotate_left", bv_rotate_left, 0);
  rb_define_method(cBitVector, "rotate_right", bv_rotate_right, 0);
  rb_define_method(cBitVector, "shift_left", bv_shift_left, 1);
  rb_define_method(cBitVector, "shift_right", bv_shift_right, 1);
  rb_define_method(cBitVector, "<<", bv_move_left, 1);
  rb_define_method(cBitVector, ">>", bv_move_right, 1);

  rb_define_method(cBitVector, "succ", bv_increment, 0);
  rb_define_method(cBitVector, "pred", bv_decrement, 0);

  rb_define_method(cBitVector, "_dump", bv_dump, 1);
  rb_define_singleton_method(cBitVector, "_load", bv_load, 1);

  rb_define_method(cBitVector, "substitute", bv_substitute, 5);

  rb_define_method(cBitVector, "to_i", bv_to_int, 0);
  rb_define_method(cBitVector, "to_uint", bv_to_uint, 0);

  rb_define_method(cBitVector, "ones", bv_ones, 0);
  rb_define_method(cBitVector, "zeroes", bv_zeroes, 0);

  rb_define_method(cBitVector, "randomize", bv_randomize, -1);

  rb_define_method(cBitVector, "resize", bv_resize, 1);

#ifdef HAVE_RB_CVAR_DECLARE
  rb_cvar_declare(cBitVector, idCvarCarry, fixnum0);
#else
  rb_cvar_set(cBitVector, idCvarCarry, fixnum0, Qtrue);
#endif

  rb_define_singleton_method(cBitVector, "carry", bv_get_carry, 0);
  rb_define_method(cBitVector, "+", bv_add, 1);
  rb_define_method(cBitVector, "-", bv_sub, 1);
  rb_define_method(cBitVector, "-@", bv_negate, 0);
  rb_define_method(cBitVector, "abs", bv_abs, 0);
  rb_define_method(cBitVector, "sign", bv_sign, 0);
  rb_define_method(cBitVector, "*", bv_multiply, 1);
  rb_define_method(cBitVector, "/", bv_divide, 1);
}
