我想创建一个从C++结构到PyLong的类型映射。swig typemap从C++ struct到PyLong
例如,我有以下表示128位数的结构,我想在Python接口中将它作为一个简单的Python无符号long来访问。
struct my_128 {
u_int64_t raw[2];
};
我该如何创建这样一个typemap?
我想创建一个从C++结构到PyLong的类型映射。swig typemap从C++ struct到PyLong
例如,我有以下表示128位数的结构,我想在Python接口中将它作为一个简单的Python无符号long来访问。
struct my_128 {
u_int64_t raw[2];
};
我该如何创建这样一个typemap?
缺席全部的差错检验,这些typemaps工作:
%typemap(in) struct my_128 {
PyObject* temp;
PyObject* shift;
if(!PyLong_Check($input) && !PyInt_Check($input))
{
PyErr_SetString(PyExc_TypeError,"Must be int or long type");
return NULL;
}
$1.raw[0] = PyInt_AsUnsignedLongLongMask($input); // low 64-bits
shift = PyInt_FromLong(64);
temp = PyNumber_Rshift($input,shift);
$1.raw[1] = PyInt_AsUnsignedLongLongMask(temp); // high 64-bits
Py_DECREF(temp);
Py_DECREF(shift);
}
%typemap(out) struct my_128 {
PyObject* low;
PyObject* high;
PyObject* shift;
PyObject* intermediate;
low = PyLong_FromUnsignedLongLong($1.raw[0]);
high = PyLong_FromUnsignedLongLong($1.raw[1]);
shift = PyInt_FromLong(64);
intermediate = PyNumber_Lshift(high,shift);
$result = PyNumber_Add(low,intermediate);
Py_DECREF(low);
Py_DECREF(high);
Py_DECREF(intermediate);
Py_DECREF(shift);
}
我有一些工作,但它不漂亮。问题是它似乎是从C制作PyLong的唯一方法,它比long long
is with a string更长!
因此,对于类型表是把你的my_128
,并公开其作为PyLong当它从一个函数返回,你可以这样做:
%typemap(out) my_128 {
std::ostringstream s;
s << "0x"
<< std::setfill('0') << std::setw(8) << std::hex << $1.raw[0]
<< std::setfill('0') << std::setw(8) << std::hex << $1.raw[1];
char *c = strdupa(s.str().c_str()); // Avoids a const cast without leaking ever
$result = PyLong_FromString(c,0,0);
}
它打印其十六进制为stringstream
,然后从构建一个PyLong 。
另一种方式的相应类型映射甚至更丑陋。我们需要通过调用内置的hex()
来让我们的PyLong和说服python把它转换成合适的字符串。
然后,我们需要将它按摩到我们可以从(两个)stringstreams
(否则第一个窃取所有输入)中读取的东西。这最终看起来像:
%typemap(in) my_128 {
PyObject *moduleName = PyString_FromString((char*)"__builtin__");
assert(moduleName);
PyObject *module = PyImport_Import(moduleName);
assert(module);
PyObject *hex = PyObject_GetAttrString(module,(char*)"hex");
assert(hex);
PyObject *args = PyTuple_Pack(1,$input);
assert(args);
PyObject *result = PyObject_CallObject(hex, args);
assert(result);
std::string str(PyString_AsString(result));
if (str.find("0x")!=std::string::npos) {
str=str.substr(2);
}
if (str.find("L") != std::string::npos) {
str=str.substr(0,str.size()-1);
}
assert(str.size());
if (str.size() > 16) {
PyErr_SetString(PyExc_ValueError, "Expected at most a 128-bit int");
return NULL;
}
std::istringstream s1(str.substr(0,8));
if (!(s1 >> std::hex >> $1.raw[0])) {
$1.raw[0]=0;
}
std::istringstream s2(str.substr(8,16));
if (!(s2 >> std::hex >> $1.raw[1])) {
$1.raw[1]=0;
}
// TODO: check that these really worked!
}
这可能会使用一堆更多的错误处理仍然。
%module test
%{
#include <sstream>
#include <iomanip>
#include <string.h>
#include <iostream> //for testing
%}
// Typemaps go here
%inline {
struct my_128 {
u_int64_t raw[2];
};
my_128 create() {
const my_128 r = {0xdeadbeef, 0xdeadbeef};
return r;
}
void display (my_128 in) {
std::cout << std::setfill('0') << std::setw(8) << std::hex << in.raw[0]
<< std::setfill('0') << std::setw(8) << std::hex << in.raw[1] << std::endl;
}
}
从快速初始测试为:
Python 2.7.1+ (r271:86832, Apr 11 2011, 18:05:24) [GCC 4.5.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import test >>> test.create() 16045690984833335023L >>> test.display(16045690984833335023L) deadbeefdeadbeef >>> test.display(test.create()) deadbeefdeadbeef >>> test.display(test.create()+1) deadbeefdeadbef0 >>> test.display(test.create()+100) deadbeefdeadbf53 >>> test.display(test.create()+10000000) deadbeefdf46556f >>> test.display(test.create()+100000000000000000000) Traceback (most recent call last): File "", line 1, in ValueError: Expected at most a 128-bit int >>> test.display(test.create()+100000000000000000) e01104683c37beef >>> test.display(test.create()+10000000000000) deadc8082d205eef >>>
虽然它尚未办理“短”整数正确,因为substr()
电话
我测试过这些。
+1,这远比我的解决方案更好 - 我错过了'PyNumber'功能 – Flexo 2012-02-22 09:22:50