swig typemap从c ++ struct到PyLong

时间:2012-02-19 08:30:44

标签: c++ struct swig

我正在尝试从C ++结构创建一个类型映射到PyLong。

例如,我有以下结构代表一个128位的数字,我想在Python接口中以一个简单的Python unsigned long访问它。

struct my_128 {
    u_int64_t raw[2];
};

如何创建这样的类型图?

2 个答案:

答案 0 :(得分:2)

如果没有完整的错误检查,这些类型地图可以正常工作:

%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);
}

答案 1 :(得分:0)

我有一些有用的东西,但它并不漂亮。问题是,似乎是从C中制作一个比long long is with a string更长的PyLong的唯一方法!

因此,对于一个带有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和persuade 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()调用它还没有正确处理“更短”的整数。