Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to receive reference and pointer arguments in Python + SWIG?

Tags:

c++

python

swig

I have a C++ function in which two arguments are given as the following example.

void func(int& n, char** data)
{
  *data = other_func1(); // returns a char array
  n = other_func2(); // returns the length of the array
}

I can easily use this function in C or C++, but I do not know how I can call it from a Python module generated with SWIG. I suppose that I will have to write another C++ function which returns, for example, std::pair. But if possible, I would like to know a workaround in the Python side. Could anyone help?

like image 900
Akira Okumura Avatar asked Mar 03 '13 11:03

Akira Okumura


1 Answers

For quite a lot of cases (e.g. int *n) it would be sufficient to write:

%apply int *OUTPUT { int *n };

which uses some default typemaps that SWIG provides for output parameters. (There is also INOUT and INPUT which are similar).

In this instance though we don't quite match any of the predefined cases, so we need to do the same thing manually. That's basically two typemaps per argument - an input typemap which creates something temporary for the actual function call and uses that instead of some real input and an argout that marshals the result back from the temporary to Python. In the case of Python it makes sense to use a tuple for returning multiple arguments.

An example:

%module test

%typemap(in,numinputs=0) int& n (int temp) "$1 = &temp;"
%typemap(in,numinputs=0) char **data (char *temp) "$1 = &temp;"

%typemap(argout) char **data {
  %append_output(PyString_FromString(*$1));
}

%typemap(argout) int& n {
  %append_output(PyInt_FromLong(*$1));
}

%inline %{
  void foo(int& n, char **data) {
    static char str[] = "Hello world";
    *data = str;
    n = sizeof str;
  }
%}

Points to note:

The temporary variables (int temp, char *temp) automatically get renamed which stops the apparent name clash. %append_output is a SWIG macro that expands to add something to the back of the $result tuple in Python. If your function foo were dynamically allocated memory you'd need to handle that. The freearg typemap is often useful if the in typemap needs to dynamically allocate memory.

This was sufficient to allow me to compile and run it like:

import test

len,str = test.foo()

print len
print str
like image 177
Flexo Avatar answered Oct 24 '22 19:10

Flexo