简体   繁体   中英

How can I reuse code across swig typemaps?

I have two swig typemaps with a bunch of duplicate code in them. I'd like to consolidate the code as follows:

%{
   #include "structure_defs.h"
%}

%ignore Cartesian2PyList(const schrodinger::Cartesian&);
PyObject* Cartesian2PyList(const schrodinger::Cartesian& cartesian)
{
  PyObject *o;
  o = PyList_New(3);
  PyObject* item = PyFloat_FromDouble(cartesian.x);
  PyList_SetItem(o, 0, item);
  item = PyFloat_FromDouble(cartesian.y);
  PyList_SetItem(o, 1, item);
  item = PyFloat_FromDouble(cartesian.z);
  PyList_SetItem(o, 2, item);
  return o; 
}

%typemap(out) schrodinger::Cartesian
{
  $result = Cartesian2PyList($1);
}
%typemap(out) std::vector<schrodinger::Cartesian>
{
  PyObject *o;
  o = PyList_New($1.size());
  for (uint i=0; i<$1.size(); i++) {
    PyObject *elem = Cartesian2PyList($1.at(i));
    PyList_SetItem(o, i, elem);
  }
  $result = o;
}

%include "cartesian.h"

However, this fails to compile, because the definition for Cartesian2PyList cannot be found at compile time. What is the best way to reuse code in multiple typemaps?

You can pass code straight through to the generated .c file using %{ %} . The simplest way to re-use code inside a wrapper is therefore to just put it inside those, probably as a static function so that it doesn't clash with anything else in the same module. In your example this would work:

%{
   #include "structure_defs.h"
%}

%{
static PyObject* Cartesian2PyList(const schrodinger::Cartesian& cartesian)
{
  PyObject *o;
  o = PyList_New(3);
  PyObject* item = PyFloat_FromDouble(cartesian.x);
  PyList_SetItem(o, 0, item);
  item = PyFloat_FromDouble(cartesian.y);
  PyList_SetItem(o, 1, item);
  item = PyFloat_FromDouble(cartesian.z);
  PyList_SetItem(o, 2, item);
  return o; 
}
%}

%typemap(out) schrodinger::Cartesian
{
  $result = Cartesian2PyList($1);
}
%typemap(out) std::vector<schrodinger::Cartesian>
{
  PyObject *o;
  o = PyList_New($1.size());
  for (uint i=0; i<$1.size(); i++) {
    PyObject *elem = Cartesian2PyList($1.at(i));
    PyList_SetItem(o, i, elem);
  }
  $result = o;
}

%include "cartesian.h"

You could merge the two %{ %} blocks into a single block here if you so wished.

I also removed the %ignore directive there because code inside %{ %} is just output into the generated module and not wrapped, so would be redundant. On the otherhand if you really did want to have it wrapped as well as defined in the generated code you could use %inline %{ ... %} , eg:

%inline %{
static PyObject* Cartesian2PyList(const schrodinger::Cartesian& cartesian)
{
    //...
}
%}

There are smarter things you can use if you're writing more generic SWIG code rather than just a single module, see fragments , %define and $typemap . In the simple case though just writing code for use inside the module only as shown above is sufficient.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM