00001
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;
00044 using boost::python::list;
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
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
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;
00177 {
00178
00179
00180
00181
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()) {
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) {
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
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;
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;
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;
00231 using boost::python::converter::rvalue_from_python_storage;
00232 using boost::python::throw_error_already_set;
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;
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