Chase
Chase

Reputation: 2826

Ruby C extension: turning int function into ruby value

I'm trying to wrap the following function to make a C extension.

int dsvd(float **a, int m, int n, float *w, float **v){
    //do some things
}

And I have my init, which isn't quite right:

void Init_svd() {
    VALUE rb_mSvd = rb_define_module("Svd");
    rb_define_method(rb_mSvd, "svd", dsvd, 0);
}

I know I need to wrap dsvd so that I can pass a Value to rb_define_method but I can't quite figure out the right way to do it. I tried adapting this answer, but couldn't quite figure it out. Any suggestions?

edit* I also read the Pragmatic Programmer section on C extensions, but that's focused on object creation/allocation. I'm trying to provide a function that performs some transformations and returns a value, so i couldn't make that match up conceptually.

Upvotes: 1

Views: 276

Answers (1)

cliffordheath
cliffordheath

Reputation: 2606

If the integer will fit into a Fixnum, you can use the macro INT2FIX to return a Fixnum value for the integer returned by dsvd(). Otherwise you have to use INT2NUM, which has a function-call overhead (it calls rb_int2inum). Look for these macros in ruby.h for more details.

Edited: Your comment indicates you need a lot more help. You want something like this. I have not compiled this, and it has no checking for argument sanity, but it should get you going). The signature of your method looks like the values passed in the arrays a and v might be changed, and this code does not copy back any changes to the Ruby versions (use rb_ary_store to assign elements).

    #include        <ruby.h>
    #include        <ruby/intern.h>

    static VALUE rb_mSvd;

    static VALUE
    rb_svd(VALUE self, VALUE a_array, VALUE m_v, VALUE n_v, VALUE w_v, VALUE v_array)
    {
            /* Note that there is no checking here for correct types or sane values! */
            long    a_len = RARRAY_LEN(a_array);                    /* get the length of first (array) argument */
            float*  a = (float*)malloc(sizeof(float)*a_len);        /* make space for the copies */
            int     m = NUM2INT(m_v);
            int     n = NUM2INT(n_v);
            float   w = NUM2DBL(w_v);
            long    v_len = RARRAY_LEN(v_array);
            float*  v = (float*)malloc(sizeof(float)*v_len);
            int     result;

            for (int i = 0; i < a_len; i++)
                    a[i] = NUM2DBL(rb_ary_entry(a_array, i));

            for (int i = 0; i < v_len; i++)
                    v[i] = NUM2DBL(rb_ary_entry(v_array, i));

            result = dsvd(&a, m, n, w, &v);

            free(a);
            free(v);
            return INT2NUM(result);
    }               

    void Init_svd()
    {
            rb_mSvd = rb_define_module("Svd");
            rb_define_method(rb_mSvd, "svd", rb_svd, 5);
    }

Upvotes: 3

Related Questions