Using SWIG and the Python/C API to wrap a function which returns a std::map

wbinventor

I want to wrap a C++ routine which returns a std::map of integers and pointers to C++ class instances. I am having trouble getting this to work with SWIG and would appreciate any help that can be offered. I've tried to boil this issue down to its essence through a simple example.

The header test.h is defined as follows:

/* File test.h */
#include <stdlib.h>
#include <stdio.h>
#include <map>

class Test {
  private:
    static int n;
    int id;
  public:
    Test();
    void printId();
};

std::map<int, Test*> get_tests(int num_tests);

The implementation is defined in test.cpp below:

/* File test.cpp */
#include "test.h"

std::map<int, Test*> get_tests(int num_tests) {
  std::map<int, Test*> tests;

  for (int i=0; i < num_tests; i++)
    tests[i] = new Test();

  return tests;
}

int Test::n = 0;

Test::Test() { 
  id = n;
  n++;
}

void Test::printId() { 
  printf("Test ID = %d", id); 
}

I have written a SWIG interface file test.i to try to accommodate this routine so that I can return a std::map<int, Test*> as a dictionary in Python:

%module test

%{
  #define SWIG_FILE_WITH_INIT
  #include "test.h"
%}

%include <std_map.i>
%typemap(out) std::map<int, Test*> {

  $result = PyDict_New();
  int size = $1.size();

  std::map<int, Test*>::iterator iter;
  Test* test;
  int count;

  for (iter = $1.begin(); iter != $1.end(); ++iter) {
    count = iter->first;
    test = iter->second;
    PyDict_SetItem($result, PyInt_FromLong(count),           
      SWIG_NewPointerObj(SWIG_as_voidptr(test), SWIGTYPE_p_Test, SWIG_POINTER_NEW | 0));
  }
}

%include "test.h"

I wrap the routines and compile the SWIG-generated wrapper code, and link it as a shared library as follows:

> swig -python -c++ -o test_wrap.cpp test.i
> gcc -c test.cpp -o test.o -fpic -std=c++0x
> gcc -I/usr/include/python2.7 -c test_wrap.cpp -o test_wrap.o -fpic -std=c++0x
> g++ test_wrap.o test.o -o _test.so -shared -Wl,-soname,_test.so

I then want to be able to do the following from within Python:

import test

tests = test.get_tests(3)
print tests

for test in tests.values():
  test.printId()

If I run this as a script example.py, however, I get the following output:

> python example.py 
{0: <Swig Object of type 'Test *' at 0x7f056a7327e0>, 1: <Swig Object of type 'Test *' at     
0x7f056a732750>, 2: <Swig Object of type 'Test *' at 0x7f056a7329f0>}
Traceback (most recent call last):
  File "example.py", line 8, in <module>
    test.printId()
AttributeError: 'SwigPyObject' object has no attribute 'printId'

Any ideas why I get SwigPyObject instances as output, rather than the SWIG proxies for Test? Any help would be greatly appreciated!

Flexo

As it stands the problem you're seeing is caused by the default behaviours in the SWIG provided std_map.i. It supplies typemaps that try to wrap all std::map usage sensibly.

One of those is interfering with your own out typemap, so if we change your interface file to be:

%module test

%{
  #define SWIG_FILE_WITH_INIT
  #include "test.h"
%}

%include <std_map.i>
%clear std::map<int, Test*>;
%typemap(out) std::map<int, Test*> {

  $result = PyDict_New();
  int size = $1.size();

  std::map<int, Test*>::iterator iter;
  Test* test;
  int count;

  for (iter = $1.begin(); iter != $1.end(); ++iter) {
    count = iter->first;
    test = iter->second;
    PyObject *value = SWIG_NewPointerObj(SWIG_as_voidptr(test), SWIGTYPE_p_Test, 0);
    PyDict_SetItem($result, PyInt_FromLong(count), value);
  }
}

%include "test.h"

then your example works. The %clear suppresses the default typemaps from std_map.i, but leaves the definition itself. I'm not too clear on exactly what causes the problem beyond that without some more digging, but you could just use %template and the default behaviours instead probably unless there's a good reason not to.

As an aside, your call:

SWIG_NewPointerObj(SWIG_as_voidptr(test), SWIGTYPE_p_Test, SWIG_POINTER_NEW | 0));

Probably doesn't do what you wanted - it transfers ownership of the pointer to Python, meaning once the Python proxy is finished with it will call delete for you and leave a dangling pointer in your map.

You can also use $descriptor to avoid having to figure out SWIG's internal name mangling scheme, so it becomes:

// No ownership, lookup descriptor:
SWIG_NewPointerObj(SWIG_as_voidptr(test), $descriptor(Test*), 0);

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

How to use SWIG to wrap std::function objects?

From Dev

Using std::function in std::map

From Dev

Using std::function in std::map

From Dev

std::function which returns any summable type?

From Dev

Problems wrapping and using a function that returns a struct with SWIG (python)

From Dev

Which is faster: calling glGetUniformLocation or using std::map?

From Dev

Swig std::map<std::string, T>

From Dev

Swig std::map<std::string, T>

From Dev

Wrap delegate in std::function?

From Dev

Using pipe operator in function which returns Observable

From Dev

How to properly wrap std::vector<std::size_t> with SWIG for Python? Problems with std::size_t

From Dev

Function which returns a QList

From Dev

Howto call Oracle function which returns a string using Hibernate/JPA?

From Dev

function which returns true is the string is in upper-case using XSLT

From Dev

Using SWIG to wrap C++ for Python. 'vector' not declared

From Dev

How to wrap final tempate class from C++ using swig?

From Dev

How to proper generify a method which returns an instance using Reflection API?

From Dev

Function which returns function scheme

From Dev

Technique for using std::ifstream, std::ofstream in python via SWIG?

From Dev

Compiler Error with static map and std::function using VS2012

From Dev

wrap C ++ function in c # that returns pointer

From Dev

How to unit test (using Jasmine) a function in a controller which calls a factory service which returns a promise

From Dev

Wrap c++11 std::function in another std::function?

From Dev

SWIG argument error when using "using std::vector" in python

From Dev

SWIG argument error when using "using std::vector" in python

From Dev

How to map data which returns when making Api call in react-native

From Dev

Function which returns multiple values

From Dev

A Function Which Returns Parent Functions

From Dev

Function which returns multiple values

Related Related

  1. 1

    How to use SWIG to wrap std::function objects?

  2. 2

    Using std::function in std::map

  3. 3

    Using std::function in std::map

  4. 4

    std::function which returns any summable type?

  5. 5

    Problems wrapping and using a function that returns a struct with SWIG (python)

  6. 6

    Which is faster: calling glGetUniformLocation or using std::map?

  7. 7

    Swig std::map<std::string, T>

  8. 8

    Swig std::map<std::string, T>

  9. 9

    Wrap delegate in std::function?

  10. 10

    Using pipe operator in function which returns Observable

  11. 11

    How to properly wrap std::vector<std::size_t> with SWIG for Python? Problems with std::size_t

  12. 12

    Function which returns a QList

  13. 13

    Howto call Oracle function which returns a string using Hibernate/JPA?

  14. 14

    function which returns true is the string is in upper-case using XSLT

  15. 15

    Using SWIG to wrap C++ for Python. 'vector' not declared

  16. 16

    How to wrap final tempate class from C++ using swig?

  17. 17

    How to proper generify a method which returns an instance using Reflection API?

  18. 18

    Function which returns function scheme

  19. 19

    Technique for using std::ifstream, std::ofstream in python via SWIG?

  20. 20

    Compiler Error with static map and std::function using VS2012

  21. 21

    wrap C ++ function in c # that returns pointer

  22. 22

    How to unit test (using Jasmine) a function in a controller which calls a factory service which returns a promise

  23. 23

    Wrap c++11 std::function in another std::function?

  24. 24

    SWIG argument error when using "using std::vector" in python

  25. 25

    SWIG argument error when using "using std::vector" in python

  26. 26

    How to map data which returns when making Api call in react-native

  27. 27

    Function which returns multiple values

  28. 28

    A Function Which Returns Parent Functions

  29. 29

    Function which returns multiple values

HotTag

Archive