librcsb-core-wrapper 1.005
container_conversions.h
Go to the documentation of this file.
1#ifndef SCITBX_BOOST_PYTHON_CONTAINER_CONVERSIONS_H
2#define SCITBX_BOOST_PYTHON_CONTAINER_CONVERSIONS_H
3
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>
8
9namespace scitbx { namespace boost_python { namespace container_conversions {
10
11 template <typename ContainerType>
12 struct to_tuple
13 {
14 static PyObject* convert(ContainerType const& a)
15 {
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));
20 }
21 return boost::python::incref(boost::python::tuple(result).ptr());
22 }
23
24 static const PyTypeObject* get_pytype() { return &PyTuple_Type; }
25 };
26
28 {
29 static bool check_convertibility_per_element() { return false; }
30
31 template <typename ContainerType>
32 static bool check_size(boost::type<ContainerType>, std::size_t /*sz*/)
33 {
34 return true;
35 }
36
37 template <typename ContainerType>
38 static void assert_size(boost::type<ContainerType>, std::size_t /*sz*/) {}
39
40 template <typename ContainerType>
41 static void reserve(ContainerType& a, std::size_t sz) {}
42 };
43
45 {
46 static bool check_convertibility_per_element() { return true; }
47
48 template <typename ContainerType>
49 static bool check_size(boost::type<ContainerType>, std::size_t sz)
50 {
51 return ContainerType::size() == sz;
52 }
53
54 template <typename ContainerType>
55 static void assert_size(boost::type<ContainerType>, std::size_t sz)
56 {
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();
61 }
62 }
63
64 template <typename ContainerType>
65 static void reserve(ContainerType& /*a*/, std::size_t sz)
66 {
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();
71 }
72 }
73
74 template <typename ContainerType, typename ValueType>
75 static void set_value(ContainerType& a, std::size_t i, ValueType const& v)
76 {
77 reserve(a, i+1);
78 a[i] = v;
79 }
80 };
81
83 {
84 template <typename ContainerType>
85 static void reserve(ContainerType& a, std::size_t sz)
86 {
87 a.reserve(sz);
88 }
89
90 template <typename ContainerType, typename ValueType>
91 static void set_value(
92 ContainerType& a,
93 std::size_t
94#if !defined(NDEBUG)
95 i
96#endif
97 ,
98 ValueType const& v)
99 {
100 assert(a.size() == i);
101 a.push_back(v);
102 }
103 };
104
106 {
107 template <typename ContainerType>
108 static bool check_size(boost::type<ContainerType>, std::size_t sz)
109 {
110 return ContainerType::max_size() >= sz;
111 }
112 };
113
115 {
116 template <typename ContainerType, typename ValueType>
117 static void
118 set_value(ContainerType& a, std::size_t /*i*/, ValueType const& v)
119 {
120 a.push_back(v);
121 }
122 };
123
125 {
126 template <typename ContainerType, typename ValueType>
127 static void
128 set_value(ContainerType& a, std::size_t /*i*/, ValueType const& v)
129 {
130 a.insert(v);
131 }
132 };
133
134 template <typename ContainerType, typename ConversionPolicy>
136 {
137 typedef typename ContainerType::value_type container_element_type;
138
140 {
141 boost::python::converter::registry::push_back(
143 &construct,
144 boost::python::type_id<ContainerType>());
145 }
146
147 static void* convertible(PyObject* obj_ptr)
148 {
149 if (!( PyList_Check(obj_ptr)
150 || PyTuple_Check(obj_ptr)
151 || PyIter_Check(obj_ptr)
152 || PyRange_Check(obj_ptr)
153 || ( !PyUnicode_Check(obj_ptr)
154 && ( Py_TYPE(obj_ptr) == 0
155 || Py_TYPE(Py_TYPE(obj_ptr)) == 0
156 || Py_TYPE(Py_TYPE(obj_ptr))->tp_name == 0
157 || std::strcmp(
158 Py_TYPE(Py_TYPE(obj_ptr))->tp_name,
159 "Boost.Python.class") != 0)
160 && PyObject_HasAttrString(obj_ptr, "__len__")
161 && PyObject_HasAttrString(obj_ptr, "__getitem__")))) return 0;
162 boost::python::handle<> obj_iter(
163 boost::python::allow_null(PyObject_GetIter(obj_ptr)));
164 if (!obj_iter.get()) { // must be convertible to an iterator
165 PyErr_Clear();
166 return 0;
167 }
168 if (ConversionPolicy::check_convertibility_per_element()) {
169 int obj_size = PyObject_Length(obj_ptr);
170 if (obj_size < 0) { // must be a measurable sequence
171 PyErr_Clear();
172 return 0;
173 }
174 if (!ConversionPolicy::check_size(
175 boost::type<ContainerType>(), obj_size)) return 0;
176 bool is_range = PyRange_Check(obj_ptr);
177 std::size_t i=0;
178 if (!all_elements_convertible(obj_iter, is_range, i)) return 0;
179 if (!is_range) assert(i == (std::size_t)obj_size);
180 }
181 return obj_ptr;
182 }
183
184 // This loop factored out by Achim Domma to avoid Visual C++
185 // Internal Compiler Error.
186 static bool
188 boost::python::handle<>& obj_iter,
189 bool is_range,
190 std::size_t& i)
191 {
192 for(;;i++) {
193 boost::python::handle<> py_elem_hdl(
194 boost::python::allow_null(PyIter_Next(obj_iter.get())));
195 if (PyErr_Occurred()) {
196 PyErr_Clear();
197 return false;
198 }
199 if (!py_elem_hdl.get()) break; // end of iteration
200 boost::python::object py_elem_obj(py_elem_hdl);
201 boost::python::extract<container_element_type>
202 elem_proxy(py_elem_obj);
203 if (!elem_proxy.check()) return false;
204 if (is_range) break; // in a range all elements are of the same type
205 }
206 return true;
207 }
208
209 static void construct(
210 PyObject* obj_ptr,
211 boost::python::converter::rvalue_from_python_stage1_data* data)
212 {
213 boost::python::handle<> obj_iter(PyObject_GetIter(obj_ptr));
214 void* storage = (
215 (boost::python::converter::rvalue_from_python_storage<ContainerType>*)
216 data)->storage.bytes;
217 new (storage) ContainerType();
218 data->convertible = storage;
219 ContainerType& result = *((ContainerType*)storage);
220 std::size_t i=0;
221 for(;;i++) {
222 boost::python::handle<> py_elem_hdl(
223 boost::python::allow_null(PyIter_Next(obj_iter.get())));
224 if (PyErr_Occurred()) boost::python::throw_error_already_set();
225 if (!py_elem_hdl.get()) break; // end of iteration
226 boost::python::object py_elem_obj(py_elem_hdl);
227 boost::python::extract<container_element_type> elem_proxy(py_elem_obj);
228 ConversionPolicy::set_value(result, i, elem_proxy());
229 }
230 ConversionPolicy::assert_size(boost::type<ContainerType>(), i);
231 }
232 };
233
234 template <typename ContainerType>
236 {
238 boost::python::to_python_converter<
239 ContainerType,
241#ifdef BOOST_PYTHON_SUPPORTS_PY_SIGNATURES
242 , true
243#endif
244 >();
245 }
246 };
247
248 template <typename ContainerType, typename ConversionPolicy>
249 struct tuple_mapping : to_tuple_mapping<ContainerType>
250 {
253 ContainerType,
254 ConversionPolicy>();
255 }
256 };
257
258 template <typename ContainerType>
260 {
263 ContainerType,
265 }
266 };
267
268 template <typename ContainerType>
270 {
273 ContainerType,
275 }
276 };
277
278 template <typename ContainerType>
287
288 template <typename ContainerType>
290 {
293 ContainerType,
294 set_policy>();
295 }
296 };
297
298}}} // namespace scitbx::boost_python::container_conversions
299
300#endif // SCITBX_BOOST_PYTHON_CONTAINER_CONVERSIONS_H
Definition container_conversions.h:9
static void assert_size(boost::type< ContainerType >, std::size_t)
Definition container_conversions.h:38
static void reserve(ContainerType &a, std::size_t sz)
Definition container_conversions.h:41
static bool check_convertibility_per_element()
Definition container_conversions.h:29
static bool check_size(boost::type< ContainerType >, std::size_t)
Definition container_conversions.h:32
static bool check_size(boost::type< ContainerType >, std::size_t sz)
Definition container_conversions.h:108
static void assert_size(boost::type< ContainerType >, std::size_t sz)
Definition container_conversions.h:55
static void set_value(ContainerType &a, std::size_t i, ValueType const &v)
Definition container_conversions.h:75
static void reserve(ContainerType &, std::size_t sz)
Definition container_conversions.h:65
static bool check_size(boost::type< ContainerType >, std::size_t sz)
Definition container_conversions.h:49
static bool check_convertibility_per_element()
Definition container_conversions.h:46
from_python_sequence()
Definition container_conversions.h:139
static bool all_elements_convertible(boost::python::handle<> &obj_iter, bool is_range, std::size_t &i)
Definition container_conversions.h:187
static void * convertible(PyObject *obj_ptr)
Definition container_conversions.h:147
static void construct(PyObject *obj_ptr, boost::python::converter::rvalue_from_python_stage1_data *data)
Definition container_conversions.h:209
ContainerType::value_type container_element_type
Definition container_conversions.h:137
static void set_value(ContainerType &a, std::size_t, ValueType const &v)
Definition container_conversions.h:118
Definition container_conversions.h:125
static void set_value(ContainerType &a, std::size_t, ValueType const &v)
Definition container_conversions.h:128
to_tuple_mapping()
Definition container_conversions.h:237
Definition container_conversions.h:13
static const PyTypeObject * get_pytype()
Definition container_conversions.h:24
static PyObject * convert(ContainerType const &a)
Definition container_conversions.h:14
tuple_mapping_fixed_size()
Definition container_conversions.h:261
tuple_mapping_set()
Definition container_conversions.h:291
tuple_mapping()
Definition container_conversions.h:251
static void reserve(ContainerType &a, std::size_t sz)
Definition container_conversions.h:85
static void set_value(ContainerType &a, std::size_t i, ValueType const &v)
Definition container_conversions.h:91