SWIG and Arrays (of ints)

K

Kurt Dresner

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
 
T

Tobias Peters

Kurt said:
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) = NUM2INT(RARRAY($input)->ptr);
}
%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
 
K

Kurt Dresner

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



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) = NUM2INT(RARRAY($input)->ptr);
}
%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
 
K

Kurt Dresner

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) = NUM2INT(RARRAY($input)->ptr);
}
%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) = NUM2INT(RARRAY($input)->ptr);
}
%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) = NUM2INT(RARRAY($input)->ptr);
}
%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


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




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) = NUM2INT(RARRAY($input)->ptr);
}
%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

 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,161
Messages
2,570,892
Members
47,430
Latest member
7dog123

Latest Threads

Top