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 
9 namespace 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(
142  &convertible,
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>
280  {
283  ContainerType,
285  }
286  };
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
scitbx::boost_python::container_conversions::from_python_sequence::construct
static void construct(PyObject *obj_ptr, boost::python::converter::rvalue_from_python_stage1_data *data)
Definition: container_conversions.h:209
scitbx::boost_python::container_conversions::default_policy::check_size
static bool check_size(boost::type< ContainerType >, std::size_t)
Definition: container_conversions.h:32
scitbx::boost_python::container_conversions::to_tuple::convert
static PyObject * convert(ContainerType const &a)
Definition: container_conversions.h:14
scitbx::boost_python::container_conversions::tuple_mapping_fixed_size::tuple_mapping_fixed_size
tuple_mapping_fixed_size()
Definition: container_conversions.h:261
scitbx::boost_python::container_conversions::to_tuple
Definition: container_conversions.h:12
scitbx::boost_python::container_conversions::tuple_mapping_fixed_capacity
Definition: container_conversions.h:269
scitbx::boost_python::container_conversions::linked_list_policy::set_value
static void set_value(ContainerType &a, std::size_t, ValueType const &v)
Definition: container_conversions.h:118
scitbx::boost_python::container_conversions::variable_capacity_policy::reserve
static void reserve(ContainerType &a, std::size_t sz)
Definition: container_conversions.h:85
scitbx::boost_python::container_conversions::fixed_size_policy::check_convertibility_per_element
static bool check_convertibility_per_element()
Definition: container_conversions.h:46
scitbx::boost_python::container_conversions::from_python_sequence::container_element_type
ContainerType::value_type container_element_type
Definition: container_conversions.h:137
scitbx::boost_python::container_conversions::default_policy::check_convertibility_per_element
static bool check_convertibility_per_element()
Definition: container_conversions.h:29
scitbx::boost_python::container_conversions::set_policy::set_value
static void set_value(ContainerType &a, std::size_t, ValueType const &v)
Definition: container_conversions.h:128
scitbx::boost_python::container_conversions::to_tuple_mapping
Definition: container_conversions.h:235
scitbx::boost_python::container_conversions::fixed_capacity_policy
Definition: container_conversions.h:105
scitbx::boost_python::container_conversions::from_python_sequence
Definition: container_conversions.h:135
scitbx::boost_python::container_conversions::to_tuple::get_pytype
static const PyTypeObject * get_pytype()
Definition: container_conversions.h:24
scitbx::boost_python::container_conversions::fixed_size_policy
Definition: container_conversions.h:44
scitbx::boost_python::container_conversions::tuple_mapping_set::tuple_mapping_set
tuple_mapping_set()
Definition: container_conversions.h:291
scitbx::boost_python::container_conversions::default_policy::assert_size
static void assert_size(boost::type< ContainerType >, std::size_t)
Definition: container_conversions.h:38
scitbx::boost_python::container_conversions::fixed_size_policy::assert_size
static void assert_size(boost::type< ContainerType >, std::size_t sz)
Definition: container_conversions.h:55
scitbx
Definition: container_conversions.h:9
scitbx::boost_python::container_conversions::default_policy::reserve
static void reserve(ContainerType &a, std::size_t sz)
Definition: container_conversions.h:41
scitbx::boost_python::container_conversions::tuple_mapping_fixed_capacity::tuple_mapping_fixed_capacity
tuple_mapping_fixed_capacity()
Definition: container_conversions.h:271
scitbx::boost_python::container_conversions::fixed_capacity_policy::check_size
static bool check_size(boost::type< ContainerType >, std::size_t sz)
Definition: container_conversions.h:108
scitbx::boost_python::container_conversions::fixed_size_policy::reserve
static void reserve(ContainerType &, std::size_t sz)
Definition: container_conversions.h:65
scitbx::boost_python::container_conversions::tuple_mapping::tuple_mapping
tuple_mapping()
Definition: container_conversions.h:251
scitbx::boost_python::container_conversions::fixed_size_policy::check_size
static bool check_size(boost::type< ContainerType >, std::size_t sz)
Definition: container_conversions.h:49
scitbx::boost_python::container_conversions::tuple_mapping_fixed_size
Definition: container_conversions.h:259
scitbx::boost_python::container_conversions::tuple_mapping
Definition: container_conversions.h:249
scitbx::boost_python::container_conversions::from_python_sequence::all_elements_convertible
static bool all_elements_convertible(boost::python::handle<> &obj_iter, bool is_range, std::size_t &i)
Definition: container_conversions.h:187
scitbx::boost_python::container_conversions::variable_capacity_policy::set_value
static void set_value(ContainerType &a, std::size_t i, ValueType const &v)
Definition: container_conversions.h:91
scitbx::boost_python::container_conversions::from_python_sequence::from_python_sequence
from_python_sequence()
Definition: container_conversions.h:139
scitbx::boost_python::container_conversions::linked_list_policy
Definition: container_conversions.h:114
scitbx::boost_python::container_conversions::set_policy
Definition: container_conversions.h:124
scitbx::boost_python::container_conversions::variable_capacity_policy
Definition: container_conversions.h:82
scitbx::boost_python::container_conversions::tuple_mapping_set
Definition: container_conversions.h:289
scitbx::boost_python::container_conversions::to_tuple_mapping::to_tuple_mapping
to_tuple_mapping()
Definition: container_conversions.h:237
scitbx::boost_python::container_conversions::tuple_mapping_variable_capacity::tuple_mapping_variable_capacity
tuple_mapping_variable_capacity()
Definition: container_conversions.h:281
scitbx::boost_python::container_conversions::from_python_sequence::convertible
static void * convertible(PyObject *obj_ptr)
Definition: container_conversions.h:147
scitbx::boost_python::container_conversions::tuple_mapping_variable_capacity
Definition: container_conversions.h:279
scitbx::boost_python::container_conversions::default_policy
Definition: container_conversions.h:27
scitbx::boost_python::container_conversions::fixed_size_policy::set_value
static void set_value(ContainerType &a, std::size_t i, ValueType const &v)
Definition: container_conversions.h:75