SWIG and Arrays (of ints)

Hi all,

I'm trying to get SWIG to create a wrapper for some C code.
Specifically, there are several functions that take, as parameters, an
int* (they also take the length of the array). I don't know how to do
the typemap for this - I want to be able to write

My_module.my_c_function([1,2,3])

for the corresponding C function

void my_c_function(int size, int* ary)

Additionally, one of the functions takes an integer array as a
parameter, and I'd like it instead to return an array in Ruby (full of
Nums). I know how to get it to return the argument (instead of doing
the pointer passing thing), but then it just thinks I want to pass it
an integer instead of an array of integers.

Anyone have any idea how to help me? Everything I've seen pertains to
char** and I'm not sure how to convert it to work how I want with
int*.

TIA,

Kurt

Kurt Dresner wrote:

Hi all,

I'm trying to get SWIG to create a wrapper for some C code.
Specifically, there are several functions that take, as parameters, an
int* (they also take the length of the array). I don't know how to do
the typemap for this - I want to be able to write

My_module.my_c_function([1,2,3])

for the corresponding C function

void my_c_function(int size, int* ary)

Additionally, one of the functions takes an integer array as a
parameter, and I'd like it instead to return an array in Ruby (full of
Nums). I know how to get it to return the argument (instead of doing
the pointer passing thing), but then it just thinks I want to pass it
an integer instead of an array of integers.

Anyone have any idea how to help me? Everything I've seen pertains to
char** and I'm not sure how to convert it to work how I want with
int*.

Passing an array of integers from Ruby to C with SWIG requires multi-argument "in" and "freearg" typemaps:

%typemap(ruby,in) (int size, int *ary) {
   int i;
   if (!rb_obj_is_kind_of($input,rb_cArray))
     rb_raise(rb_eArgError, "Expected Array of Integers");
   $1 = RARRAY($input)->len;
   $2 = malloc($1*sizeof(int));
   for (i=0; i<$1; ++i)
     ($2)[i] = NUM2INT(RARRAY($input)->ptr[i]);
}
%typemap(freearg) (int size, int *ary) {
    if ($2) free($2);
}

There's room for improvement in handling (or better: preventing) exceptions raised from NUM2INT (proper error message and deallocation of C array).

Regarding output: It's not clear to me if you want in/out semantics or output only. I think you can achieve in/out with an additional multi-argument "argout" typemap. Output only implementation depends on which function is responsible for allocating/freeing the array and which is responsible for determining the array's size. You may need an additional "arginit" typemap for this one.

   Tobias

Here are the actual functions I need to wrap:

/* This one allocates a cmac, which is the thing I'm going to be
using. I tell it how many
* states it has, how many responses it has, and some other
parameters. The typemap you
* provided I think will work rather well for this function.
*/
int allocate_cmac(int num_state, int *qnt_state,
       int num_resp, int num_cell,
       int memory, int rfield_shape,
       int collision_flag);

/* With this function, I provide the ID of the cmac that was returned
to me in the allocate
* function. I then provide two arrays: the input states and the
desired responses. These
* have to be of the sizes num_state and num_resp from the last
function. I think a similar
* typemap will work just fine, since the C code presumably knows the
size of the arrays.
* I just won't provide it.
*/
int train_cmac(int cmac_id, int *state, int *respns, int beta1, int beta2);

/* This is the one I'm stuck on. I need to provide the ID, which will
work, and then an array
* of state ints. That will work too, as in the last one. Now,
however, I need to provide
* an array for the response. This array is then filled up with the
response. Two things are
* confusing me. I should probably do some sort of argout so I can
get both the int
* (success/failure) return value (which I can probably map to
true/nil right?) and the array
* return value. The thing is, I don't know how to get it to create a
Ruby array for this
* return value, since in the interface code, I don't know how big the
array is. The C code
* knows (presumably - I didn't write it). So I don't know how to
write the argout to take care
* of it. I have no idea what to do with this.
*/
int cmac_response(int cmac_id, int *state, int *respns);

Any ideas?

-Kurt

···

On Sun, 21 Nov 2004 22:58:07 +0900, Tobias Peters <tpeters@invalid.uni-oldenburg.de> wrote:

Kurt Dresner wrote:

> Hi all,
>
> I'm trying to get SWIG to create a wrapper for some C code.
> Specifically, there are several functions that take, as parameters, an
> int* (they also take the length of the array). I don't know how to do
> the typemap for this - I want to be able to write
>
> My_module.my_c_function([1,2,3])
>
> for the corresponding C function
>
> void my_c_function(int size, int* ary)
>
> Additionally, one of the functions takes an integer array as a
> parameter, and I'd like it instead to return an array in Ruby (full of
> Nums). I know how to get it to return the argument (instead of doing
> the pointer passing thing), but then it just thinks I want to pass it
> an integer instead of an array of integers.
>
> Anyone have any idea how to help me? Everything I've seen pertains to
> char** and I'm not sure how to convert it to work how I want with
> int*.

Passing an array of integers from Ruby to C with SWIG requires
multi-argument "in" and "freearg" typemaps:

%typemap(ruby,in) (int size, int *ary) {
   int i;
   if (!rb_obj_is_kind_of($input,rb_cArray))
     rb_raise(rb_eArgError, "Expected Array of Integers");
   $1 = RARRAY($input)->len;
   $2 = malloc($1*sizeof(int));
   for (i=0; i<$1; ++i)
     ($2)[i] = NUM2INT(RARRAY($input)->ptr[i]);
}
%typemap(freearg) (int size, int *ary) {
    if ($2) free($2);
}

There's room for improvement in handling (or better: preventing)
exceptions raised from NUM2INT (proper error message and deallocation of
C array).

Regarding output: It's not clear to me if you want in/out semantics or
output only. I think you can achieve in/out with an additional
multi-argument "argout" typemap. Output only implementation depends on
which function is responsible for allocating/freeing the array and which
is responsible for determining the array's size. You may need an
additional "arginit" typemap for this one.

   Tobias

So here's what I have right now. The only thing that's missing is the
stuff to fix the last function.

%module unh_cmac
%include typemaps.i

#define ALBUS 65
#define RECTANGULAR 82
#define LINEAR 76
#define SPLINE 83
#define CUSTOM 67
#define VTRUE 1
#define VFALSE 0

%typemap(ruby,in) (int num_state, int *qnt_state) {
  int i;
  if (!rb_obj_is_kind_of($input,rb_cArray))
    rb_raise(rb_eArgError, "Expected Array of Integers");
  $1 = RARRAY($input)->len;
  $2 = malloc($1*sizeof(int));
  for (i=0; i<$1; ++i)
    ($2)[i] = NUM2INT(RARRAY($input)->ptr[i]);
}
%typemap(freearg) (int size, int *ary) {
   if ($2) free($2);
}
%typemap(ruby,out) int {
  if($1 == 0) {
    $result = Qnil;
  } else {
    $result = INT2NUM($1);
  }
}

int allocate_cmac(int num_state, int *qnt_state,
       int num_resp, int num_cell,
       int memory, int rfield_shape,
       int collision_flag);

%typemap(ruby,in) (int *state) {
  int i;
  int length;
  if (!rb_obj_is_kind_of($input,rb_cArray))
    rb_raise(rb_eArgError, "Expected Array of Integers");
  length = RARRAY($input)->len;
  $1 = malloc(length*sizeof(int));
  for (i=0; i<length; ++i)
    ($1)[i] = NUM2INT(RARRAY($input)->ptr[i]);
}
%typemap(freearg) (int *state) {
   if ($1) free($1);
}
%typemap(ruby,in) (int *respns) {
  int i;
  int length;
  if (!rb_obj_is_kind_of($input,rb_cArray))
    rb_raise(rb_eArgError, "Expected Array of Integers");
  length = RARRAY($input)->len;
  $1 = malloc(length*sizeof(int));
  for (i=0; i<length; ++i)
    ($1)[i] = NUM2INT(RARRAY($input)->ptr[i]);
}
%typemap(freearg) (int *respns) {
   if ($1) free($1);
}

%typemap(ruby,out) int {
  if($1 == 0) {
    $result = Qfalse;
  } else {
    $result = Qtrue;
  }
}

int train_cmac(int cmac_id, int *state, int *respns, int beta1, int beta2);

/* Need stuff here */

int cmac_response(int cmac_id, int *state, int *respns);

-Kurt

···

On Mon, 22 Nov 2004 13:09:03 -0600, Kurt Dresner <omega697@gmail.com> wrote:

Here are the actual functions I need to wrap:

/* This one allocates a cmac, which is the thing I'm going to be
using. I tell it how many
* states it has, how many responses it has, and some other
parameters. The typemap you
* provided I think will work rather well for this function.
*/
int allocate_cmac(int num_state, int *qnt_state,
                         int num_resp, int num_cell,
                         int memory, int rfield_shape,
                         int collision_flag);

/* With this function, I provide the ID of the cmac that was returned
to me in the allocate
* function. I then provide two arrays: the input states and the
desired responses. These
* have to be of the sizes num_state and num_resp from the last
function. I think a similar
* typemap will work just fine, since the C code presumably knows the
size of the arrays.
* I just won't provide it.
*/
int train_cmac(int cmac_id, int *state, int *respns, int beta1, int beta2);

/* This is the one I'm stuck on. I need to provide the ID, which will
work, and then an array
* of state ints. That will work too, as in the last one. Now,
however, I need to provide
* an array for the response. This array is then filled up with the
response. Two things are
* confusing me. I should probably do some sort of argout so I can
get both the int
* (success/failure) return value (which I can probably map to
true/nil right?) and the array
* return value. The thing is, I don't know how to get it to create a
Ruby array for this
* return value, since in the interface code, I don't know how big the
array is. The C code
* knows (presumably - I didn't write it). So I don't know how to
write the argout to take care
* of it. I have no idea what to do with this.
*/
int cmac_response(int cmac_id, int *state, int *respns);

Any ideas?

-Kurt

On Sun, 21 Nov 2004 22:58:07 +0900, Tobias Peters > <tpeters@invalid.uni-oldenburg.de> wrote:
> Kurt Dresner wrote:
>
>
> > Hi all,
> >
> > I'm trying to get SWIG to create a wrapper for some C code.
> > Specifically, there are several functions that take, as parameters, an
> > int* (they also take the length of the array). I don't know how to do
> > the typemap for this - I want to be able to write
> >
> > My_module.my_c_function([1,2,3])
> >
> > for the corresponding C function
> >
> > void my_c_function(int size, int* ary)
> >
> > Additionally, one of the functions takes an integer array as a
> > parameter, and I'd like it instead to return an array in Ruby (full of
> > Nums). I know how to get it to return the argument (instead of doing
> > the pointer passing thing), but then it just thinks I want to pass it
> > an integer instead of an array of integers.
> >
> > Anyone have any idea how to help me? Everything I've seen pertains to
> > char** and I'm not sure how to convert it to work how I want with
> > int*.
>
> Passing an array of integers from Ruby to C with SWIG requires
> multi-argument "in" and "freearg" typemaps:
>
> %typemap(ruby,in) (int size, int *ary) {
> int i;
> if (!rb_obj_is_kind_of($input,rb_cArray))
> rb_raise(rb_eArgError, "Expected Array of Integers");
> $1 = RARRAY($input)->len;
> $2 = malloc($1*sizeof(int));
> for (i=0; i<$1; ++i)
> ($2)[i] = NUM2INT(RARRAY($input)->ptr[i]);
> }
> %typemap(freearg) (int size, int *ary) {
> if ($2) free($2);
> }
>
> There's room for improvement in handling (or better: preventing)
> exceptions raised from NUM2INT (proper error message and deallocation of
> C array).
>
> Regarding output: It's not clear to me if you want in/out semantics or
> output only. I think you can achieve in/out with an additional
> multi-argument "argout" typemap. Output only implementation depends on
> which function is responsible for allocating/freeing the array and which
> is responsible for determining the array's size. You may need an
> additional "arginit" typemap for this one.
>
> Tobias
>
>