swigサンプル

swigのサンプル。

  • typemap(in) char * + int lenの引数をStringとして扱う
  • typemap(ignore)とtypemap(argout) 出力用のポインタを返り値で返す(複数あったらtupleにつめる)
  • numpyのarray入出力
  • downcast

など

example.h

#include <string>
#include <array>

class String
{
    std::string m_buf;

public:
    void setChar(const char *s);

    void setCharWithLen(const char *s, int len);

    void setString(const std::string &s);

    void getCharWithLen(char *s, int len)const;
};

class WString
{
    std::wstring m_buf;

public:
    void setChar(const wchar_t *s);

    void setCharWithLen(const wchar_t *s, int len);

    void setString(const std::wstring &s);

    void getCharWithLen(wchar_t *s, int len)const;
};

class Matrix
{
    std::array<float, 16> m_buf;

public:
    void set(const float *p, int len);

    void get(float *p, int len)const;
};

struct Vector3
{
    float x;
    float y;
    float z;

    Vector3();
    ~Vector3();
};

class Shape
{
public:
    virtual ~Shape(){}
    virtual void getAABB(Vector3 &min, Vector3 &max)=0;
};

class Box : public Shape
{
    Vector3 m_origin;
    float w;
    float h;
    float d;
public:
    Box();
    ~Box();
    void getAABB(Vector3 &min, Vector3 &max);
};

Box *create_box_shape(float w, float h, float d);

example.cpp

#include "example.h"
#include <fstream>

// std::coutだとクラッシュしたのでとりあえず
std::ofstream cout("example.log");

void String::setChar(const char *s)
{
    m_buf=s;
}

void String::setCharWithLen(const char *s, int len)
{
    m_buf.assign(s, s+len);
}

void String::setString(const std::string &s)
{
    m_buf=s;
}

void String::getCharWithLen(char *s, int len)const
{
    int i=0;
    for(auto it=m_buf.begin(); it!=m_buf.end() && i<len; ++it, ++i){
        s[i]=*it;
    }
    for(; i<len; ++i){
        s[i]=0;
    }
}

void WString::setChar(const wchar_t *s)
{
    m_buf=s;
}

void WString::setCharWithLen(const wchar_t *s, int len)
{
    m_buf.assign(s, s+len);
}

void WString::setString(const std::wstring &s)
{
    m_buf=s;
}

void WString::getCharWithLen(wchar_t *s, int len)const
{
    int i=0;
    for(auto it=m_buf.begin(); it!=m_buf.end() && i<len; ++it, ++i){
        s[i]=*it;
    }
    for(; i<len; ++i){
        s[i]=0;
    }
}

void Matrix::set(const float *p, int len)
{
    std::copy(p, p+len, m_buf.begin());
}

void Matrix::get(float *p, int len)const
{
    std::copy(m_buf.begin(), m_buf.end(), p);
}

Vector3::Vector3()
{
    cout << "Vector3::Vector3" << std::endl;
}

Vector3::~Vector3()
{
    cout << "Vector3::~Vector3" << std::endl;
}

Box::Box()
{
    cout << "Box::Box" << std::endl;
}

Box::~Box()
{
    cout << "Box::~Box" << std::endl;
}

void Box::getAABB(Vector3 &min, Vector3 &max)
{
    min=m_origin;
    min.x-=w;
    min.y-=h;
    min.z-=d;
    max=m_origin;
    max.x+=w;
    max.y+=h;
    max.z+=d;
};

Box *create_box_shape(float w, float h, float d)
{
    cout << "create_box_shape" << std::endl;
    return new Box;
}

example.i

%module example
%{
#include "example.h"
%}

//////////////////////////////////////////////////////////////////////////////
// setup numpy
//////////////////////////////////////////////////////////////////////////////
%{
#define SWIG_FILE_WITH_INIT
%}
%include "numpy.i"
%init %{
import_array();
%}

%apply (float* IN_ARRAY1, int DIM1) {(const float *p, int len)};
%apply (float* ARGOUT_ARRAY1, int DIM1) {(float *p, int len)};

//////////////////////////////////////////////////////////////////////////////
// typemaps
//////////////////////////////////////////////////////////////////////////////
#ifdef SWIGPYTHON
// for setCharWithLen
%typemap(in) (const char *s, int len){

    if (PyString_Check($input)) {
        $1=PyString_AsString($input);
        $2=PyString_Size($input);
    }
    else {
        PyErr_SetString(PyExc_TypeError,"not a string");
        return NULL;
    }

}

// for getCharWithLen
%typemap(ignore) (char *s, int len)(char tmpbuf[1024]) {
    $1=tmpbuf;    
    $2=1024;
}
%typemap(argout) (char *s, int len) {
    PyObject *o = $1[$2-1]=='\0'
        ? PyString_FromStringAndSize($1, strlen($1))
        : PyString_FromStringAndSize($1, $2)
        ;
    if ((!$result) || ($result == Py_None)) {
        // 単独の返り値
        $result = o;
    } 
    else {
        // 既存のtupple返り値に値を連結する
        PyObject *o3 = PyTuple_New(1);
        PyTuple_SetItem(o3,0,o);

        if (!PyTuple_Check($result)) {
            // tuple
            PyObject *tmp = $result;
            $result = PyTuple_New(1);
            PyTuple_SetItem($result, 0, tmp);
        }
        PyObject *o2 = $result;

        $result = PySequence_Concat(o2,o3);
        Py_DECREF(o2);
        Py_DECREF(o3);
    }
}

// for setCharWithLen
%typemap(in) (const wchar_t *s, int len){

    if (PyUnicode_Check($input)) {
        $1=PyUnicode_AsUnicode($input);
        $2=PyUnicode_GET_SIZE($input);
    }
    else {
        PyErr_SetString(PyExc_TypeError,"not a unicode");
        return NULL;
    }

}

// for setChar
%typemap(in) const wchar_t *s {

    if (PyUnicode_Check($input)) {
        $1=PyUnicode_AsUnicode($input);
    }
    else {
        PyErr_SetString(PyExc_TypeError,"not a unicode");
        return NULL;
    }

}

// for getCharWithLen
%typemap(ignore) (wchar_t *s, int len)(wchar_t tmpbuf[1024]) {
    $1=tmpbuf;    
    $2=1024;
}
%typemap(argout) (wchar_t *s, int len) {
    PyObject *o = $1[$2-1]=='\0'
        ? PyUnicode_FromUnicode($1, wcslen($1))
        : PyUnicode_FromUnicode($1, $2)
        ;
    if ((!$result) || ($result == Py_None)) {
        // 単独の返り値
        $result = o;
    } 
    else if(PyTuple_Check($result)){
        // 既存のtuple返り値と連結
        PyObject *o2 = $result;

        PyObject *o3 = PyTuple_New(1);
        PyTuple_SetItem(o3,0,o);

        $result = PySequence_Concat(o2,o3);
        Py_DECREF(o2);
        Py_DECREF(o3);
    }
    else{
        // 非tuple返り値と連結
        PyObject *o2=$result;
        $result=PyTuple_New(2);
        PyTuple_SetItem($result, 0, o2);
        PyTuple_SetItem($result, 1, o);
    }
}

// for getAABB
%typemap(ignore) (Vector3 &min, Vector3 &max)(Vector3 tmpmin, Vector3 tmpmax) {
    $1=&tmpmin;    
    $2=&tmpmax;
}
%typemap(argout) (Vector3 &min, Vector3 &max) {
    Vector3 *v1=new Vector3;
    *v1=*$1;
    Vector3 *v2=new Vector3;
    *v2=*$2;
    if ((!$result) || ($result == Py_None)) {
        // 単独の返り値
        $result =  PyTuple_New(2);
        PyTuple_SetItem($result, 0, SWIG_NewPointerObj(v1, $1_descriptor, 1));
        PyTuple_SetItem($result, 1, SWIG_NewPointerObj(v2, $2_descriptor, 1));
    } 
    else if(PyTuple_Check($result)){
        // tuple連結
        PyObject *o1 = $result;
        PyObject *o2 =  PyTuple_New(2);
        PyTuple_SetItem(o2, 0, SWIG_NewPointerObj(v1, $1_descriptor, 1));
        PyTuple_SetItem(o2, 1, SWIG_NewPointerObj(v2, $2_descriptor, 1));
        $result = PySequence_Concat(o1, o2);
        Py_DECREF(o1);
        Py_DECREF(o2);
    }
    else{
        // 3tuple
        PyObject *o=$result;
        $result =  PyTuple_New(3);
        PyTuple_SetItem($result, 0, o);
        PyTuple_SetItem($result, 1, SWIG_NewPointerObj(v1, $1_descriptor, 1));
        PyTuple_SetItem($result, 2, SWIG_NewPointerObj(v2, $2_descriptor, 1));
    }
}

//////////////////////////////////////////////////////////////////////
#endif

%newobject create_box_shape;

%include example.h

//////////////////////////////////////////////////////////////////////
// extend
//////////////////////////////////////////////////////////////////////
%extend Box {

    static Box* downcast(Shape* s){
        return (Box*)s;
    }

};

setup.py

#!/usr/bin/env python
"""
libexample
"""
MODULE_NAME='example'
PY_MODULE_DIR='build/lib.win32-2.7/'+MODULE_NAME

import os
from distutils.core import setup, Extension
from distutils.dir_util import mkpath


mkpath(PY_MODULE_DIR)

include_dirs=[
        '/Python27/Lib/site-packages/numpy/core/include',
        ]

ext= Extension(MODULE_NAME+'.___init__',
        sources=['example.i', 'example.cpp'],
        swig_opts=['-I'+d for d in include_dirs]+[
            '-module', '__init__',
            '-outdir', PY_MODULE_DIR,
            '-c++',
            '-fastdispatch',
            '-DSWIG_TYPE_TABLE='+MODULE_NAME,
            ],
        include_dirs=include_dirs,
        extra_compile_args=[
            '-Wno-unused-parameter',
            '-Wno-unused-but-set-variable',
            '-std=c++0x',
            ],
        define_macros=[
            ],
        library_dirs=[],
        libraries=[]
        )

setup (name = MODULE_NAME,
       version = '0.1',
       author      = "ousttrue",
       description = """simple opengl utility""",
       ext_modules = [ext],
       py_modules = [MODULE_NAME],
       )

使用例

#!/usr/bin/env python

import example
import numpy

# string
s=example.String()

s.setChar("hoge")
print type(s.getCharWithLen())
print s.getCharWithLen()

s.setCharWithLen("fuga")
print type(s.getCharWithLen())
print s.getCharWithLen()

# wstring
w=example.WString()

w.setChar(u"hoge")
print type(w.getCharWithLen())
print w.getCharWithLen()

w.setCharWithLen(u"fuga")
print type(w.getCharWithLen())
print w.getCharWithLen()

# numpy.array
m=example.Matrix()
data=numpy.array([
    1, 2, 3, 4,
    5, 6, 7, 8,
    9, 10, 11, 12,
    13, 14, 15, 16
    ], 'f')
print type(data)
print data
m.set(data)
print type(m.get(16))
print m.get(16)

#b=example.Box()

# shape
b=example.create_box_shape(1, 2, 3)
s=example.Box.downcast(b)
print s

aabbMin, aabbMax=s.getAABB()
print aabbMin, aabbMax