std::vectorがどうなっているか
vertices.h
#include <vector> struct Vertex { float x; float y; float z; }; struct Container { std::vector<Vertex> vertices; };
に対してswigインターフェース
vertices.i
%module vertices %{ #include "vertices.h" %} %include "vertices.h" %include "std_vector.i" %template(VertexVector) std::vector<Vertex>;
とした時にVertexVectorがどんな実装になるか。
とりあえず
$ swig -python -c++ vertices.i $ ls vertices* vertices.h vertices.i vertices.py vertices_wrap.cxx
vertices.pyのstd::vector
class VertexVector(_object): def iterator(self): return _vertices.VertexVector_iterator(self) def __iter__(self): return self.iterator()
となっている。
_vertices.VertexVector_iteratorはvertices_wrap.cxxにある。
{ (char *)"VertexVector_iterator", _wrap_VertexVector_iterator, METH_VARARGS, NULL}
と登録されるので実体は_wrap_VertexVector_iterator。
なんか良くわからないが、VertexVector::iteratorの返り値はSwigPyIteratorだった。
SwigPyIteratorはvertices.pyに定義されていてforに関係あるところだけだと
class SwigPyIterator(_object): def next(self): return _vertices.SwigPyIterator_next(self) def __iter__(self): return self
vertices_wrap.cxxでは
{ (char *)"SwigPyIterator_next", _wrap_SwigPyIterator_next, METH_VARARGS, NULL},
と定義されている。
_wrap_SwigPyIterator_nextのソースを追う(抜粋)
SWIGINTERN PyObject *_wrap_SwigPyIterator_next(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { swig::SwigPyIterator *arg1; PyObject *result; result = (PyObject *)(arg1)->next(); } ↓ SwigPyIterator::PyObject *next() { PyObject *obj = value(); } ↓ typename ValueType = typename std::iterator_traits<OutIterator>::value_type PyObject *SwigPyIteratorOpen_T::value() const { return from(static_cast<const value_type&>(*(base::current))); } ↓ template <class Type> inline PyObject *from(const Type& val) { return traits_from<Type>::from(val); } ↓ template <class Type> struct traits_from { static PyObject *from(const Type& val) { // コピーコンストラクタを使ってnewしてるのを発見 return traits_from_ptr<Type>::from(new Type(val), 1); } };
newを回避したら速くなるか試してみる
ポインタが返り値の時はnewが呼ばれないので、
元のクラスに適当にポインタを返す関数を作ったら遅くなるのを回避できるようだ。
struct Container { std::vector<Vertex> vertices; Vertex* getVertex(int index){ return &vertices[index]; } };