Tuesday 15 May 2012

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



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

i want wrap c++ routine returns std::map of integers , pointers c++ class instances. having problem getting work swig , appreciate help can offered. i've tried boil issue downwards essence through simple example.

the header test.h defined 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 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; (int i=0; < num_tests; i++) tests[i] = new test(); homecoming tests; } int test::n = 0; test::test() { id = n; n++; } void test::printid() { printf("test id = %d", id); }

i have written swig interface file test.i seek accommodate routine can homecoming std::map<int, test*> 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; (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 routines , compile swig-generated wrapper code, , link shared library 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 want able next within python:

import test tests = test.get_tests(3) print tests test in tests.values(): test.printid()

if run script example.py, however, next output:

> python example.py {0: <swig object of type 'test *' @ 0x7f056a7327e0>, 1: <swig object of type 'test *' @ 0x7f056a732750>, 2: <swig object of type 'test *' @ 0x7f056a7329f0>} traceback (most recent phone call last): file "example.py", line 8, in <module> test.printid() attributeerror: 'swigpyobject' object has no attribute 'printid'

any ideas why swigpyobject instances output, rather swig proxies test? help appreciated!

as stands problem you're seeing caused default behaviours in swig provided std_map.i. supplies typemaps seek wrap std::map usage sensibly.

one of interfering own out typemap, if alter interface file 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; (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 illustration works. %clear suppresses default typemaps std_map.i, leaves definition itself. i'm not clear on causes problem beyond without more digging, utilize %template , default behaviours instead unless there's reason not to.

as aside, call:

swig_newpointerobj(swig_as_voidptr(test), swigtype_p_test, swig_pointer_new | 0));

probably doesn't wanted - transfers ownership of pointer python, meaning 1 time python proxy finished phone call delete , leave dangling pointer in map.

you can utilize $descriptor avoid having figure out swig's internal name mangling scheme, becomes:

// no ownership, lookup descriptor: swig_newpointerobj(swig_as_voidptr(test), $descriptor(test*), 0);

python c++ swig

No comments:

Post a Comment