Posts tagged ‘std::ifstream’

Tak jak zapowiadałem w moim poprzednim wpisie, rvalue_converter operujący na streamach jest też, a jakże. Krótkie wprowadzenie: mamy sobie wyeksportowane api, które m.in. prowadzi zapis danych do pliku, ale aby odciążyć sama metodę od żmudnych operacji na strumieniach, a jednocześnie dać jej dużą elastyczność dot. zapisu danych, dostaje ona gotową referencję do strumienia jako parametr, przykładowy kod może wyglądać tak:

class MyClass {
public:
writeToStream( std::ifstream& out ){}
}

No i teraz, fajnie by było mieć możliwość otwarcia pliku po stronie pythona i tylko przesłania samego uchwytu do naszej metody c++’owej. Otóż Ci którzy czytali poprzedni wpis o konwersji stringów już pewnie wiedzą, że to jest możliwe, może troche karkołomne, bo synchronizacja streamów to sprawa niebalna, no ale w moich testach wszystko działa poprawnie.

A oto i kod:

namespace tulips {
namespace converters {
namespace fstream {

  class custom_fstream
  {
    public:
		custom_fstream(
			const char* path,
			FILE* file,
			std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out
		) :
			m_fstream(path,mode),
			m_file(file)
		{
			fflush(m_file);
			m_fstream.seekg(ftell(m_file));
		}
		std::fstream& get_stream() { return m_fstream; }
		~custom_fstream(){ fseek( m_file, m_fstream.tellg(), SEEK_SET );}
    private:
      std::fstream m_fstream;
      FILE* m_file;
  };

  struct custom_fstream_from_python_file
  {
	custom_fstream_from_python_file()
	{
		bp::converter::registry::push_back(
			&convertible,
			&construct,
			bp::type_id<custom_fstream>());
	}

	static void* convertible(PyObject* obj_ptr)
	{
		if (!PyFile_Check(obj_ptr) || obj_ptr == Py_None) return 0;
		return obj_ptr;
	}

	static void construct(PyObject* obj_ptr, bp::converter::rvalue_from_python_stage1_data* data)
	{
		FILE* file = PyFile_AsFile(obj_ptr);
		void* storage = ((bp::converter::rvalue_from_python_storage<custom_fstream>*)data)->storage.bytes;
		new (storage) custom_fstream(PyString_AsString(PyFile_Name(obj_ptr)), file, std::ios::in|std::ios::out);
		data->convertible = storage;
	}
  };

  void init_converter()
  {
    custom_fstream_from_python_file();
  }

}}} // namespace tulips::converters::stream

No i teraz już możemy sobie przesyłać uchwyt do strumienia otwarty po stronie pythona :)