Fredrik Jagenheim wrote:
> ts wrote:
> >
> >  Well, in ruby
> > [snip solution in ruby]
>
> I had to interface with a C-library that took, among other things, an
> array of bitmaps as input. Otherwise, I would have done it in Ruby, of
> course.
>

I assumed it was mainly for experimentation until you said that.

Your example showed the first mutable Fixnum object that I've seen
and you must have wondered why a simple task was so tough to get
right in an extension.

Have a look at the same thing implemented (for amusement only) as an
extension to the Integer class (Fixnum/Bignum's parent).  Notice how
the input array is created from a sequence of parameters in both the
Ruby and C versions, so you call with (1,2,3) instead of ([1,2,3]).
(Method Bitmask#add_bits is defined with "-1" arguments.)

Method Bitmask#add_bit in Ruby is now:
    bitmask | 1 << bit
not:
    bitmask |= 1 << bit

which means that you would need bitmask = bitmask.add_bit(...) when
accumulating single results.  Apart from this "new" problem, you
should find that things look simpler (e.g. no Bitmask.new).

> As for the solution, Tim was correct in that rb_iterate wasn't what I
> neded. The for loop solved the problem I had.

OK, I saw that, but you may be tempted to try another approach.
A similar loop to Tim's is still there.

It's a kind of "Hello bit-World" extension if anyone needs one   :-)

>
> Thanks everyone,
> //Fredrik
>

and thank you,

:daz


-------8<------ Bitmask.c

#include "ruby.h"

static ID id_lshift, id_or;

static VALUE
add_bit(VALUE obj, VALUE bit)  /* OK with Fixnum or Bignum */
{
    VALUE bit_or = rb_funcall(INT2FIX(1), id_lshift, 1, bit);

    return rb_funcall(obj, id_or, 1, bit_or);
}

static VALUE
bm_add_bit(VALUE self, VALUE bit)
{
    return add_bit(self, bit);
}

static VALUE
bm_add_bits(int argc, VALUE *argv, VALUE self)
{
    VALUE arr_bits, result = self;
    int x;

    rb_scan_args(argc, argv, "0*", &arr_bits);

    for (x = 0; x < RARRAY(arr_bits)->len; x++)
        result = add_bit(result, RARRAY(arr_bits)->ptr[x]);

    return result;
}

void Init_Bitmask() {
    rb_define_method(rb_cInteger, "add_bit",  bm_add_bit, 1);
    rb_define_method(rb_cInteger, "add_bits", bm_add_bits, -1);

    id_lshift = rb_intern("<<");
    id_or     = rb_intern("|");
}


       /*  E N D  */


/***
###-----  extconf.rb

require 'mkmf'
create_makefile('Bitmask')

# - to build ...
# make
# -  then  ...
# make install

###-----  test_Bitmask.rb

require 'Bitmask'

class Integer
  def add_rubits(*args)  ###  Ruby add_bits
    res = self
    args.each {|bx| res = res.add_bit(bx)}
    res
  end
end

show = lambda{ |res| puts 'value: 0x%03x  [%08b]' % [res, res] }

bm = 0

show[ bm = bm.add_bit(2) ]
show[ bm = bm.add_bit(4) ]

puts '------------'
show[ 0.add_bits(2, 4) ]

puts '------------'
MSK1 = 0b11110011
bm = MSK1;  show[ bm.add_bits(  31, 33) ]
bm = MSK1;  show[ bm.add_rubits(31, 33) ]  # Ruby
                     bit_arr = [31, 33]
bm = MSK1;  show[ bm.add_bits(*bit_arr) ]

puts '------------'
MSK2 = 2**41
bm = MSK2;  show[ bm.add_bits(  19, 3, 9, 17, 6, 18) ]
bm = MSK2;  show[ bm.add_rubits(19, 3, 9, 17, 6, 18) ]  # Ruby


 ***/