tags:

views:

105

answers:

1

I'm trying to write a typemap that converts multiple/variable arguments into one input parameter.

For example, say I have a function that takes a vector.

void foo(vector<int> x);

And I want to call it like this (happens to be in Perl)

foo(1,2,3,4);

The typemap should take arguments ($argnum, ...), gather them into one vector and then pass that to foo.

I have this so far:

typedef vector<int> vectori;
%typemap(in) (vectori) {
  for (int i=$argnum-1; i<items; i++) {
      $1->push_back( <argv i> );   // This is language dependent, of course.
  }
}

This would work, except that SWIG checks the number of arguments

if ((items < 1) || (items > 1)) {
  SWIG_croak("Usage: foo(vectori);");
}

If I do:

 void foo(vectori, ...);

SWIG will expect to call foo with two arguments.

 foo(arg1, arg2);

Perhaps there's a way to tell SWIG to suppress arg2 from the call to foo?

I can't use this in my .i:

void foo(...)

because I want to have different typemaps, depending on the types that foo is expecting (an array of int, strings, whatever). Maybe there's a way to give a type to "..."

Is there a way to do this?

A: 

SWIG determines the argument count at the time SWIG generates the bindings. SWIG does provide some limited support for variable argument lists but I'm not sure this is the right approach to take. If you're interested, you can read more about it in the SWIG vararg documentation section.

I think a better approach would be to pass these values in as an array reference. Your typemap would then look something like this (not tested):

%typemap(in) vectori (vector<int> tmp)
{
    if (!SvROK($input))
        croak("Argument $argnum is not a reference.");

    if (SvTYPE(SvRV($input)) != SVt_PVAV) 
        croak("Argument $argnum is not an array.");

    $1 = &$tmp;

    AV *arrayValue = (AV*)SvRV($input);
    int arrayLen = av_len(arrayLen);

    for (int i=0; i<=arrayLen; ++i) 
    {
        SV* scalarValue = av_fetch(arrayValue , i, 0);
        $1->push_back( SvPV(*scalarValue, PL_na) );
    }
};

Then from Perl you'd use array notation:

@myarray = (1, 2, 3, 4);
foo(\@myarray);
Aaron Saarela