Передача Python StringIO в C ++ stringstream с помощью swig - PullRequest
0 голосов
/ 17 февраля 2012

У меня есть некоторый код на python, который генерирует переменную StringIO.Я хотел бы передать эту переменную в функцию C ++ с помощью параметра stringstream (при условии, что C ++ stringstream является наиболее близким соответствием Python StringIO).Есть ли простой способ с помощью Swig сделать этот перевод?

Я вижу, что в модулях swig есть std_sstream.i, который содержит некоторый код stringstream, но я не могу найти никаких ссылок на него в документации swig или каких-либо примеров его использования в веб-поиске.

Чтобы попытаться прояснить ситуацию, я приведу ниже очень простой код.Вот test.cpp, который исправлен, и я не могу его изменить:

#include <iostream>
#include <sstream>

#include "test.h"

using namespace std;

void StTest(stringstream &ss)
{
    cout << ss << endl;
}

Вот test.h, который также исправлен:

#include <sstream>

using namespace std;

void StTest(stringstream &ss);

Вот код Python, который я могу редактировать икоторая вызывает функцию C ++ StTest (мы назовем этот test_test.py):

#!/usr/bin/env python

import StringIO
import test

ss = StringIO.StringIO()
ss.write("Hello")

# Maybe some thing here to convert ss from StringIO to stringstream

test.StTest(ss)

Поэтому я ищу что-то, что может сделать преобразование из StringIO в stringstream в приведенной выше строке с комментариями.

Вот мой начальный файл в файле test.i для swig:

/* test.i */
%module test

%{
#include "test.h"
%}

%include "std_sstream.i"
%include "test.h"

Я включил "std_sstream.i" в test.i, поскольку это то, что следует использоватьЯ предполагаю.Нужно ли что-то добавить в этот файл, чтобы заставить его что-то делать?

В настоящее время сообщение об ошибке при запуске test_test.py:

TypeError: in method 'StTest', argument 1 of type 'stringstream &'

1 Ответ

1 голос
/ 17 февраля 2012

Почему бы просто не вызвать PyArg_ParseTuple со строкой, которую вы получаете при вызове StringIO.getvalue()?

С чем-то вроде этого?

const char* cstring;
if (!PyArg_ParseTuple(args,"s", &cstring)) //Note the &
        return NULL;
std::string stdstring = cstring;
std::stringstream buffer(stdstring);

Также см. C API для cStringIO here .

После дополнительных требований я попытался найти решение с использованием SWIG в рамках фиксированных ограничений.

Первым возможным решением было встроенное или расширяемое решение (расширить StTest довозьмите строку и затем сделайте расширение, сделайте stringstream и вызовите StTest), но, поскольку в приведенном примере есть только один метод и нет классов, это не соответствует ограничениям.

Возможный интерфейсный файл выглядел следующим образом.

/* test.i */
%module test

%{
#include "test.h"
#include <sstream>
#include <iostream>
%}
using namespace std;
%include "std_sstream.i"
%include "test.h"

%include <typemaps.i>

%typemap(in) std::stringstream & (char *buf = 0, size_t size = 0, int alloc = 0, std::stringstream stream)
{
  if (SWIG_AsCharPtrAndSize($input, &buf, &size, &alloc) != SWIG_OK)
  {
    %argument_fail(SWIG_TypeError, "(TYPEMAP, SIZE)", $symname, $argnum);
  }

  stream.write(buf, size - 1);

  $1 = &stream;
}

Обратите внимание, что SWIG проигнорировал карту типов в приведенном выше файле интерфейса, но не уверен, почему.Ему удалось создать объекты потока строк в Python, но они не были бы переданы вашему StTest, что приводило к той же ошибке типа, потому что тип объектов не был типом потока строк & (также сопоставленный тип swig несоответствовать типам, сгенерированным std_sstream.i, возможно потому, что он не содержит сопоставления типов).

Далее была реализация подхода, предложенного мной для переопределения оболочки SWIG, получившаяся в результате функция-обертка выглядела следующим образом.(Не будет включать весь файл-обертку, так как он имеет длину более 18000 строк)

SWIGINTERN PyObject *_wrap_StTest(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
  PyObject *resultobj = 0;
  void *argp1 = 0 ;
  int res1 = 0 ;
  PyObject * obj0 = 0 ;
  int argc;
  PyObject *argv[3];
  int ii;
  char *cstring;
  std::stringstream testbuffer;
  if (!PyTuple_Check(args)) SWIG_fail;
  argc = args ? (int)PyObject_Length(args) : 0;
  for (ii = 0; (ii < 2) && (ii < argc); ii++) {
    argv[ii] = PyTuple_GET_ITEM(args,ii);
  }
  if (argc == 1) {

  if (!PyArg_ParseTuple(args,"s",&cstring)) 
SWIG_fail;
  std::string teststring = cstring;
  testbuffer.str(cstring);
  std::cout << "the string in the stream: " << testbuffer.str() << std::endl;
  }  

  StTest(testbuffer);
  resultobj = SWIG_Py_Void();
  return resultobj;
fail:
  return NULL;
}   

Строка в строке потока печатается правильно, однако передача строкового потока в функцию StTest печатает местоположение в памяти потока строки,Это ожидается, потому что поток строк не связан, как в принятом ответе следующего вопроса переполнения стека .

Я предполагаю, что StTest(testbuffer); можно заменить версией, использующей привязку boost, и она будет работать по мере необходимости, но была в состоянии проверить.

Ссылки, которые были полезны, включали

...