1 #ifndef SCITBX_BOOST_PYTHON_CONTAINER_CONVERSIONS_H
2 #define SCITBX_BOOST_PYTHON_CONTAINER_CONVERSIONS_H
4 #include <boost/python/list.hpp>
5 #include <boost/python/tuple.hpp>
6 #include <boost/python/extract.hpp>
7 #include <boost/python/to_python_converter.hpp>
9 namespace scitbx {
namespace boost_python {
namespace container_conversions {
11 template <
typename ContainerType>
14 static PyObject*
convert(ContainerType
const& a)
16 boost::python::list result;
17 typedef typename ContainerType::const_iterator const_iter;
18 for(const_iter p=a.begin();p!=a.end();p++) {
19 result.append(boost::python::object(*p));
21 return boost::python::incref(boost::python::tuple(result).ptr());
24 static const PyTypeObject*
get_pytype() {
return &PyTuple_Type; }
31 template <
typename ContainerType>
32 static bool check_size(boost::type<ContainerType>, std::size_t )
37 template <
typename ContainerType>
38 static void assert_size(boost::type<ContainerType>, std::size_t ) {}
40 template <
typename ContainerType>
41 static void reserve(ContainerType& a, std::size_t sz) {}
48 template <
typename ContainerType>
49 static bool check_size(boost::type<ContainerType>, std::size_t sz)
51 return ContainerType::size() == sz;
54 template <
typename ContainerType>
55 static void assert_size(boost::type<ContainerType>, std::size_t sz)
57 if (!
check_size(boost::type<ContainerType>(), sz)) {
58 PyErr_SetString(PyExc_RuntimeError,
59 "Insufficient elements for fixed-size array.");
60 boost::python::throw_error_already_set();
64 template <
typename ContainerType>
65 static void reserve(ContainerType& , std::size_t sz)
67 if (sz > ContainerType::size()) {
68 PyErr_SetString(PyExc_RuntimeError,
69 "Too many elements for fixed-size array.");
70 boost::python::throw_error_already_set();
74 template <
typename ContainerType,
typename ValueType>
75 static void set_value(ContainerType& a, std::size_t i, ValueType
const& v)
84 template <
typename ContainerType>
85 static void reserve(ContainerType& a, std::size_t sz)
90 template <
typename ContainerType,
typename ValueType>
100 assert(a.size() == i);
107 template <
typename ContainerType>
108 static bool check_size(boost::type<ContainerType>, std::size_t sz)
110 return ContainerType::max_size() >= sz;
116 template <
typename ContainerType,
typename ValueType>
118 set_value(ContainerType& a, std::size_t , ValueType
const& v)
126 template <
typename ContainerType,
typename ValueType>
128 set_value(ContainerType& a, std::size_t , ValueType
const& v)
134 template <
typename ContainerType,
typename ConversionPolicy>
141 boost::python::converter::registry::push_back(
144 boost::python::type_id<ContainerType>());
149 if (!( PyList_Check(obj_ptr)
150 || PyTuple_Check(obj_ptr)
151 || PyIter_Check(obj_ptr)
152 || PyRange_Check(obj_ptr)
153 || ( !PyString_Check(obj_ptr)
154 && !PyUnicode_Check(obj_ptr)
155 && ( obj_ptr->ob_type == 0
156 || obj_ptr->ob_type->ob_type == 0
157 || obj_ptr->ob_type->ob_type->tp_name == 0
159 obj_ptr->ob_type->ob_type->tp_name,
160 "Boost.Python.class") != 0)
161 && PyObject_HasAttrString(obj_ptr,
"__len__")
162 && PyObject_HasAttrString(obj_ptr,
"__getitem__"))))
return 0;
163 boost::python::handle<> obj_iter(
164 boost::python::allow_null(PyObject_GetIter(obj_ptr)));
165 if (!obj_iter.get()) {
169 if (ConversionPolicy::check_convertibility_per_element()) {
170 int obj_size = PyObject_Length(obj_ptr);
175 if (!ConversionPolicy::check_size(
176 boost::type<ContainerType>(), obj_size))
return 0;
177 bool is_range = PyRange_Check(obj_ptr);
180 if (!is_range) assert(i == (std::size_t)obj_size);
189 boost::python::handle<>& obj_iter,
194 boost::python::handle<> py_elem_hdl(
195 boost::python::allow_null(PyIter_Next(obj_iter.get())));
196 if (PyErr_Occurred()) {
200 if (!py_elem_hdl.get())
break;
201 boost::python::object py_elem_obj(py_elem_hdl);
202 boost::python::extract<container_element_type>
203 elem_proxy(py_elem_obj);
204 if (!elem_proxy.check())
return false;
212 boost::python::converter::rvalue_from_python_stage1_data* data)
214 boost::python::handle<> obj_iter(PyObject_GetIter(obj_ptr));
216 (boost::python::converter::rvalue_from_python_storage<ContainerType>*)
217 data)->storage.bytes;
218 new (storage) ContainerType();
219 data->convertible = storage;
220 ContainerType& result = *((ContainerType*)storage);
223 boost::python::handle<> py_elem_hdl(
224 boost::python::allow_null(PyIter_Next(obj_iter.get())));
225 if (PyErr_Occurred()) boost::python::throw_error_already_set();
226 if (!py_elem_hdl.get())
break;
227 boost::python::object py_elem_obj(py_elem_hdl);
228 boost::python::extract<container_element_type> elem_proxy(py_elem_obj);
229 ConversionPolicy::set_value(result, i, elem_proxy());
231 ConversionPolicy::assert_size(boost::type<ContainerType>(), i);
235 template <
typename ContainerType>
239 boost::python::to_python_converter<
242 #ifdef BOOST_PYTHON_SUPPORTS_PY_SIGNATURES
249 template <
typename ContainerType,
typename ConversionPolicy>
259 template <
typename ContainerType>
269 template <
typename ContainerType>
279 template <
typename ContainerType>
289 template <
typename ContainerType>
301 #endif // SCITBX_BOOST_PYTHON_CONTAINER_CONVERSIONS_H