Technique for using std::ifstream, std::ofstream in python via SWIG?

后端 未结 5 1669
滥情空心
滥情空心 2021-01-12 09:16

Is there a way to use std::[io]fstream\'s in python via swig?

I have a c-class with functions like:

void readFrom(std::istream& istr         


        
5条回答
  •  有刺的猬
    2021-01-12 09:32

    I made a few tweaks to the solution provided by @Flexo

    The main change was to use a boost::iostream::stream owned by a unique pointer

    Some other differences:

    • used a fragment for the iostream header requirements
    • removed the "io" namespace alias to avoid conflicts with code where that name is already used
    • took advantage of fileno() returning -1 for NULL or invalid FILE* arguments
    • use "%#include" "%#else" "%#endif" so the directives are in the wrap file and the same wrap file can be used for python2 and python3
    • included his suggestion for flushing the output stream because it violated the principle of least surprise without it
    • call Py_DECREF on the result from the python output stream flush() method call - this result is None so the world won't catch fire if None's reference counts grow but it's cleaner and guards against overflowing the refcount
    %fragment("iostream_header", "header") %{
    #include 
    #include 
    #include 
    #include 
    using boost_ofd_stream = boost::iostreams::stream;
    using boost_ifd_stream = boost::iostreams::stream;
    %}  
    
    %typemap(in, fragment="iostream_header") std::ostream& (std::unique_ptr stream) {
        PyObject *flush_result = PyObject_CallMethod($input, const_cast("flush"), nullptr);
        if (flush_result) Py_DECREF(flush_result);
    %#if PY_VERSION_HEX < 0x03000000
        int fd = fileno(PyFile_AsFile($input));
    %#else
        int fd = PyObject_AsFileDescriptor($input);
    %#endif
        if (fd < 0) { SWIG_Error(SWIG_TypeError, "File object expected."); SWIG_fail; }
        stream = std::make_unique(fd, boost::iostreams::never_close_handle);
        $1 = stream.get();
    }   
    
    %typemap(in, fragment="iostream_header") std::istream& (std::unique_ptr stream) {
    %#if PY_VERSION_HEX < 0x03000000
        int fd = fileno(PyFile_AsFile($input));
    %#else
        int fd = PyObject_AsFileDescriptor($input);
    %#endif
        if (fd < 0) { SWIG_Error(SWIG_TypeError, "File object expected.");  SWIG_fail; }
        stream = std::make_unique(fd, boost::iostreams::never_close_handle);
        $1 = stream.get();
    }   
    
    

提交回复
热议问题