Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cython: working with C++ streams

The Problem

How does one use c++ streams (like std::ifstream or ostream) from Cython? In c++, you could do the following:

std::ofstream output { filename, std::ios::binary };
output.write(...);

How would you achieve the same in Cython?

Current status

I have wrapped the structures from fstream in Cython so that I can use their names in function declarations, but the tricky part is to use (wrap in Cython, perhaps) the write method and to create the streams. I haven't found any code examples on the internet.

P.S. I know one possible answer would be to just use Python's IO but I need to pass/return the streams to and from C++ code that I'm interfacing with.

This is the code that wraps the stream declarations:

cdef extern from "<iostream>" namespace "std":
    cdef cppclass basic_istream[T]:
        pass

    cdef cppclass basic_ostream[T]:
        pass

    ctypedef basic_istream[char] istream

    ctypedef basic_ostream[char] ostream
like image 410
piotrMocz Avatar asked Jun 22 '15 15:06

piotrMocz


1 Answers

There isn't much particularly special about the c++ iostreams compared to wrapping any other C++ class. The only tricky bit was getting access to std::ios_base::binary, which I did by telling Cython that std::ios_base was a namespace and not a class.

# distutils: language = c++

cdef extern from "<iostream>" namespace "std":
    cdef cppclass ostream:
        ostream& write(const char*, int) except +

# obviously std::ios_base isn't a namespace, but this lets
# Cython generate the correct C++ code
cdef extern from "<iostream>" namespace "std::ios_base":
    cdef cppclass open_mode:
        pass
    cdef open_mode binary
    # you can define other constants as needed

cdef extern from "<fstream>" namespace "std":
    cdef cppclass ofstream(ostream):
        # constructors
        ofstream(const char*) except +
        ofstream(const char*, open_mode) except+

def test_ofstream(str s):
    cdef ofstream* outputter
    # use try ... finally to ensure destructor is called
    outputter = new ofstream("output.txt",binary)
    try:
        outputter.write(s,len(s))
    finally:
        del outputter

The other thing to add is that I haven't bothered with the full templated class heirarchy - that might be useful if you also want the wchar variants, but it's much easier to only tell Cython about the classes you're actually using.

like image 61
DavidW Avatar answered Sep 20 '22 07:09

DavidW