c++ - Boost.Python custom converter -


i have class taking vector parameter (a binary file content).

i convert python 'str' type vector of unsigned char 1 of class method.

boost_python_module(hello) {  class_<hello>("hello").      // method takes string parameter , print      .def("printchar", &hello::printchar)      // method takes vector<unsigned char> parameter      .def("storefile", &hello::storefile) } 

using custom converter seems need if modify boost::python::converter::registry modify calls printchar , python methods passing string parameter converted vector.

how can register per-method converter ?

there 2 approaches problem:

  • export helper function hello.storefile accepts boost::python::str, constructs std::vector<unsigned char> string, , delegates c++ hello::storefile member function.
  • write custom converter. while converters cannot registered on per-function basis, scoped not perform unintended conversions. approach provides more reusability.

helper function

using helper function not affect other exported function. thus, conversion between python string , std::vector<unsigned char> occur hello.storefile.

void hello_storefile(hello& self, boost::python::str str) {   std::cout << "hello_storefile" << std::endl;   // obtain handle string.   const char* begin = pystring_asstring(str.ptr());   // delegate hello::storefile().   self.storefile(std::vector<unsigned char>(begin, begin + len(str))); }  ...  boost_python_module(hello) {   namespace python = boost::python;    python::class_<hello>("hello")     // method takes string parameter , print     .def("printchar", &hello::printchar)     // method takes vector<unsigned char> parameter     .def("storefile", &hello_storefile)     ; } 

custom converter

a converter registration has 3 parts:

  • a function checks if pyobject convertible. return of null indicates pyobject cannot use registered converter.
  • a construct function constructs c++ type pyobject. function called if converter(pyobject) not return null.
  • the c++ type constructed.

therefore, given c++ type, if converter(pyobject) returns non-null value, construct(pyobject) create c++ type. c++ type serves key registry, boost.python should not perform unintended conversions.

in context of question, want converter std::vector<unsigned char> converter(pyobject) returns non-null if pyobject pystring, , converter(pyobject) use pyobject create , populate std::vector<unsigned char>. conversion occur if exported c++ functions have std::vector<unsigned char> (or const reference) parameter , argument provided python string. therefore, custom converter not affect exported functions have std::string parameters.

here complete example. have opted make converter generic allow multiple types constructable python string. chaining support, should have same feel other boost.python types.

#include <iostream> #include <list> #include <string> #include <vector>  #include <boost/foreach.hpp> #include <boost/python.hpp>  class hello { public:   void printchar(const std::string& str)   {     std::cout << "printchar: " << str << std::endl;   }    void storefile(const std::vector<unsigned char>& data)   {     std::cout << "storefile: " << data.size() << ": ";     boost_foreach(const unsigned char& c, data)       std::cout << c;     std::cout << std::endl;   } };  /// @brief type allows conversions of python strings //         vectors. struct pystring_converter {    /// @note registers converter python interable type   ///       provided type.   template <typename container>   pystring_converter&   from_python()   {     boost::python::converter::registry::push_back(       &pystring_converter::convertible,       &pystring_converter::construct<container>,       boost::python::type_id<container>());     return *this;   }    /// @brief check if pyobject string.   static void* convertible(pyobject* object)   {     return pystring_check(object) ? object : null;   }    /// @brief convert pystring container.   ///   /// container concept requirements:   ///   ///   * container::value_type copyconstructable char.   ///   * container can constructed , populated 2 iterators.   ///     i.e. container(begin, end)   template <typename container>   static void construct(     pyobject* object,     boost::python::converter::rvalue_from_python_stage1_data* data)   {     namespace python = boost::python;     // object borrowed reference, create handle indicting     // borrowed proper reference counting.     python::handle<> handle(python::borrowed(object));      // obtain handle memory block converter has allocated     // c++ type.     typedef python::converter::rvalue_from_python_storage<container>                                                                  storage_type;     void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes;      // allocate c++ type converter's memory block, , assign     // handle converter's convertible variable.  c++     // container populated passing begin , end iterators of     // python object container's constructor.     const char* begin = pystring_asstring(object);     data->convertible = new (storage) container(       begin,                          // begin       begin + pystring_size(object)); // end   } };  boost_python_module(hello) {   namespace python = boost::python;    // register pystring conversions.   pystring_converter()     .from_python<std::vector<unsigned char> >()     .from_python<std::list<char> >()     ;    python::class_<hello>("hello")     // method takes string parameter , print     .def("printchar", &hello::printchar)     // method takes vector<unsigned char> parameter     .def("storefile", &hello::storefile)     ; } 

and example usage:

>>> hello import hello >>> h = hello() >>> h.printchar('abc') printchar: abc >>> h.storefile('def') storefile: 3: def >>> h.storefile([c c in 'def']) traceback (most recent call last):   file "<stdin>", line 1, in <module> boost.python.argumenterror: python argument types in     hello.storefile(hello, list) did not match c++ signature:     storefile(hello {lvalue}, std::vector<unsigned char,                                            std::allocator<unsigned char> >) 

for more on custom converters , c++ containers, consider reading this answer.


Comments

Popular posts from this blog

node.js - Bad Request - node js ajax post -

Why does Ruby on Rails generate add a blank line to the end of a file? -

keyboard - Smiles and long press feature in Android -