Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

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 <vector>
00016 
00017 #include <boost/python.hpp>
00018 
00019 using namespace boost::python;
00020 
00034   template < typename ContainerType >
00035   struct to_tuple
00036   {
00041     static PyObject* convert (ContainerType const& c)
00042     {
00043       using boost::python::incref; // works around gcc 2.96 bug
00044       using boost::python::list; // dito 
00045       list result;
00046       typename ContainerType::const_iterator i = c.begin();
00047       for( ; i != c.end(); ++i)
00048         {
00049           result.append(*i);
00050         }
00051       return incref(tuple(result).ptr());
00052     }
00053   };
00054 
00066   template < typename T >
00067   struct std_vector_to_tuple 
00068   {
00069     std_vector_to_tuple ()
00070     {
00071       to_python_converter < std::vector < T >, 
00072                             to_tuple < std::vector < T > >  > ();
00073     }
00074   };
00075 
00076 // /** Interface to AxesType enumeration. */
00077 // struct AxesOwner
00078 // {
00079 //   public:
00080 //     AxesOwner(){};
00081 //     typedef AxesType enum_type;
00082 // };
00083 
00084 // /** Conversion of AxesType enumeration. */
00085 // struct EnumTypeConverters
00086 //   : python::enum_as_int_converters <AxesOwner::enum_type>
00087 // {
00088 // };
00089 
00102   struct default_policy
00103   {
00104     static bool check_convertibility_per_element() { return false; }
00105 
00106     template <typename ContainerType>
00107     static bool check_size(boost::type<ContainerType>, std::size_t sz)
00108     {
00109       return true;
00110     }
00111 
00112     template <typename ContainerType>
00113     static void assert_size(boost::type<ContainerType>, std::size_t sz) {}
00114 
00115     template <typename ContainerType>
00116     static void reserve(ContainerType& a, std::size_t sz) {}
00117   };
00118 
00131   struct variable_capacity_policy : default_policy
00132   {
00133     template <typename ContainerType>
00134     static void reserve(ContainerType& a, std::size_t sz)
00135     {
00136       a.reserve(sz);
00137     }
00138 
00139     template <typename ContainerType, typename ValueType>
00140     static void set_value(ContainerType& a, std::size_t i, ValueType const& v)
00141     {
00142       assert(a.size() == i);
00143       a.push_back(v);
00144     }
00145   };
00146 
00158   template <typename ContainerType, typename ConversionPolicy>
00159   struct from_python_sequence
00160   {
00161     typedef typename ContainerType::value_type container_element_type;
00162 
00163     from_python_sequence()
00164     {
00165       boost::python::converter::registry::push_back(
00166         &convertible,
00167         &construct,
00168         boost::python::type_id<ContainerType>());
00169     }
00170 
00173     static void* convertible(PyObject* obj_ptr)
00174     {
00175       using namespace boost::python;
00176       using boost::python::allow_null; // works around gcc 2.96 bug
00177       {
00178         // Restriction to list, tuple, iter, xrange until
00179         // Boost.Python overload resolution is enhanced.
00180          //
00181          // add PySequence_Check() for numarray.
00182          //
00183          if (!(   PyList_Check(obj_ptr)
00184                   || PyTuple_Check(obj_ptr)
00185                   || PyIter_Check(obj_ptr)
00186                   || PyRange_Check(obj_ptr)
00187                   || PySequence_Check(obj_ptr) )) return 0;
00188       }
00189       handle<> obj_iter(allow_null(PyObject_GetIter(obj_ptr)));
00190       if (!obj_iter.get()) { // must be convertible to an iterator
00191         PyErr_Clear();
00192         return 0;
00193       }
00194       if (ConversionPolicy::check_convertibility_per_element()) {
00195         int obj_size = PyObject_Length(obj_ptr);
00196         if (obj_size < 0) { // must be a measurable sequence
00197           PyErr_Clear();
00198           return 0;
00199         }
00200         if (!ConversionPolicy::check_size(
00201           boost::type<ContainerType>(), obj_size)) return 0;
00202         bool is_range = PyRange_Check(obj_ptr);
00203         //std::size_t i=0;
00204                 int i = 0;
00205 #ifndef _MSC_VER // because it causes c1001: internal compiler error
00206         for(;;i++) {
00207           handle<> py_elem_hdl(allow_null(PyIter_Next(obj_iter.get())));
00208           if (PyErr_Occurred()) {
00209             PyErr_Clear();
00210             return 0;
00211           }
00212           if (!py_elem_hdl.get()) break; // end of iteration
00213           object py_elem_obj(py_elem_hdl);
00214           extract<container_element_type> elem_proxy(py_elem_obj);
00215           if (!elem_proxy.check()) return 0;
00216           if (is_range) break; // in a range all elements are of the same type
00217         }
00218         if (!is_range) assert(i == obj_size );
00219 #endif
00220       }
00221       return obj_ptr;
00222     }
00223 
00225     static void construct(
00226       PyObject* obj_ptr,
00227       boost::python::converter::rvalue_from_python_stage1_data* data)
00228     {
00229       using namespace boost::python;
00230       using boost::python::allow_null; // works around gcc 2.96 bug
00231       using boost::python::converter::rvalue_from_python_storage; // dito
00232       using boost::python::throw_error_already_set; // dito
00233       handle<> obj_iter(PyObject_GetIter(obj_ptr));
00234       void* storage = (
00235         (rvalue_from_python_storage<ContainerType>*)
00236           data)->storage.bytes;
00237       new (storage) ContainerType();
00238       data->convertible = storage;
00239       ContainerType& result = *((ContainerType*)storage);
00240       std::size_t i=0;
00241       for(;;i++) {
00242         handle<> py_elem_hdl(allow_null(PyIter_Next(obj_iter.get())));
00243         if (PyErr_Occurred()) throw_error_already_set();
00244         if (!py_elem_hdl.get()) break; // end of iteration
00245         object py_elem_obj(py_elem_hdl);
00246         extract<container_element_type> elem_proxy(py_elem_obj);
00247         ConversionPolicy::set_value(result, i, elem_proxy());
00248       }
00249       ConversionPolicy::assert_size(boost::type<ContainerType>(), i);
00250     }
00251 
00252   };
00253 
00254 #endif // PY_CONVERSIONS_H

Generated for HippoDraw-1.14.8.5 by doxygen 1.4.3