pyconversions.h

Go to the documentation of this file.
00001 /* -*- mode:c++ -*- */
00002 
00012 #ifndef PY_CONVERSIONS_H
00013 #define PY_CONVERSIONS_H
00014 
00015 // include first to avoid _POSIX_C_SOURCE redefined warnings
00016 #include <boost/python.hpp>
00017 
00018 #include <vector>
00019 
00020 
00021 using namespace boost::python;
00022 
00036   template < typename ContainerType >
00037   struct to_tuple
00038   {
00043     static PyObject* convert (ContainerType const& c)
00044     {
00045       using boost::python::incref; // works around gcc 2.96 bug
00046       using boost::python::list; // ditto 
00047       list result;
00048       typename ContainerType::const_iterator i = c.begin();
00049       for( ; i != c.end(); ++i)
00050         {
00051           result.append(*i);
00052         }
00053       return incref(tuple(result).ptr());
00054     }
00055   };
00056 
00068   template < typename T >
00069   struct std_vector_to_tuple 
00070   {
00071     std_vector_to_tuple ()
00072     {
00073       to_python_converter < std::vector < T >, 
00074                             to_tuple < std::vector < T > >  > ();
00075     }
00076   };
00077 
00090   struct default_policy
00091   {
00092     static bool check_convertibility_per_element() { return false; }
00093 
00094     template <typename ContainerType>
00095     static bool check_size(boost::type<ContainerType>, std::size_t /* sz */ )
00096     {
00097       return true;
00098     }
00099 
00100     template <typename ContainerType>
00101     static void 
00102     assert_size(boost::type<ContainerType>, std::size_t /* sz */) {}
00103 
00104     template <typename ContainerType>
00105     static void reserve(ContainerType& a, std::size_t /* sz */ ) {}
00106   };
00107 
00120   struct variable_capacity_policy : default_policy
00121   {
00122     template <typename ContainerType>
00123     static void reserve(ContainerType& a, std::size_t sz)
00124     {
00125       a.reserve(sz);
00126     }
00127 
00128     template <typename ContainerType, typename ValueType>
00129     static void set_value(ContainerType& a, std::size_t i, ValueType const& v)
00130     {
00131       assert(a.size() == i);
00132       a.push_back(v);
00133     }
00134   };
00135 
00147   template <typename ContainerType, typename ConversionPolicy>
00148   struct from_python_sequence
00149   {
00150     typedef typename ContainerType::value_type container_element_type;
00151 
00152     from_python_sequence()
00153     {
00154       boost::python::converter::registry::push_back(
00155         &convertible,
00156         &construct,
00157         boost::python::type_id<ContainerType>());
00158     }
00159 
00162     static void* convertible(PyObject* obj_ptr)
00163     {
00164       using namespace boost::python;
00165       using boost::python::allow_null; // works around gcc 2.96 bug
00166       {
00167         // Restriction to list, tuple, iter, xrange until
00168         // Boost.Python overload resolution is enhanced.
00169          //
00170          // add PySequence_Check() for numarray.
00171          //
00172          if (!(   PyList_Check(obj_ptr)
00173                   || PyTuple_Check(obj_ptr)
00174                   || PyIter_Check(obj_ptr)
00175                   || PyRange_Check(obj_ptr)
00176                   || PySequence_Check(obj_ptr) )) return 0;
00177       }
00178       handle<> obj_iter(allow_null(PyObject_GetIter(obj_ptr)));
00179       if (!obj_iter.get()) { // must be convertible to an iterator
00180         PyErr_Clear();
00181         return 0;
00182       }
00183       if (ConversionPolicy::check_convertibility_per_element()) {
00184         int obj_size = PyObject_Length(obj_ptr);
00185         if (obj_size < 0) { // must be a measurable sequence
00186           PyErr_Clear();
00187           return 0;
00188         }
00189         if (!ConversionPolicy::check_size(
00190           boost::type<ContainerType>(), obj_size)) return 0;
00191         bool is_range = PyRange_Check(obj_ptr);
00192         //std::size_t i=0;
00193                 int i = 0;
00194 #ifndef _MSC_VER // because it causes c1001: internal compiler error
00195         for(;;i++) {
00196           handle<> py_elem_hdl(allow_null(PyIter_Next(obj_iter.get())));
00197           if (PyErr_Occurred()) {
00198             PyErr_Clear();
00199             return 0;
00200           }
00201           if (!py_elem_hdl.get()) break; // end of iteration
00202           object py_elem_obj(py_elem_hdl);
00203           extract<container_element_type> elem_proxy(py_elem_obj);
00204           if (!elem_proxy.check()) return 0;
00205           if (is_range) break; // in a range all elements are of the same type
00206         }
00207         if (!is_range) assert(i == obj_size );
00208 #endif
00209       }
00210       return obj_ptr;
00211     }
00212 
00214     static void construct(
00215       PyObject* obj_ptr,
00216       boost::python::converter::rvalue_from_python_stage1_data* data)
00217     {
00218       using namespace boost::python;
00219       using boost::python::allow_null; // works around gcc 2.96 bug
00220       using boost::python::converter::rvalue_from_python_storage; // dito
00221       using boost::python::throw_error_already_set; // dito
00222       handle<> obj_iter(PyObject_GetIter(obj_ptr));
00223       void* storage = (
00224         (rvalue_from_python_storage<ContainerType>*)
00225           data)->storage.bytes;
00226       new (storage) ContainerType();
00227       data->convertible = storage;
00228       ContainerType& result = *((ContainerType*)storage);
00229       std::size_t i=0;
00230       for(;;i++) {
00231         handle<> py_elem_hdl(allow_null(PyIter_Next(obj_iter.get())));
00232         if (PyErr_Occurred()) throw_error_already_set();
00233         if (!py_elem_hdl.get()) break; // end of iteration
00234         object py_elem_obj(py_elem_hdl);
00235         extract<container_element_type> elem_proxy(py_elem_obj);
00236         ConversionPolicy::set_value(result, i, elem_proxy());
00237       }
00238       ConversionPolicy::assert_size(boost::type<ContainerType>(), i);
00239     }
00240 
00241   };
00242 
00243 #endif // PY_CONVERSIONS_H

Generated for HippoDraw Class Library by doxygen