00001
00002
00012 #ifndef PY_CONVERSIONS_H
00013 #define PY_CONVERSIONS_H
00014
00015
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;
00046 using boost::python::list;
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 )
00096 {
00097 return true;
00098 }
00099
00100 template <typename ContainerType>
00101 static void
00102 assert_size(boost::type<ContainerType>, std::size_t ) {}
00103
00104 template <typename ContainerType>
00105 static void reserve(ContainerType& a, std::size_t ) {}
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;
00166 {
00167
00168
00169
00170
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()) {
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) {
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
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;
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;
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;
00220 using boost::python::converter::rvalue_from_python_storage;
00221 using boost::python::throw_error_already_set;
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;
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