pyconversions.h
Go to the documentation of this file.
1 /* -*- mode:c++ -*- */
2 
12 #ifndef PY_CONVERSIONS_H
13 #define PY_CONVERSIONS_H
14 
15 // include first to avoid _POSIX_C_SOURCE redefined warnings
16 #include <boost/python.hpp>
17 
18 #include <vector>
19 
20 
21 using namespace boost::python;
22 
36  template < typename ContainerType >
37  struct to_tuple
38  {
43  static PyObject* convert (ContainerType const& c)
44  {
45  using boost::python::incref; // works around gcc 2.96 bug
46  using boost::python::list; // ditto
47  list result;
48  typename ContainerType::const_iterator i = c.begin();
49  for( ; i != c.end(); ++i)
50  {
51  result.append(*i);
52  }
53  return incref(tuple(result).ptr());
54  }
55  };
56 
68  template < typename T >
70  {
72  {
73  to_python_converter < std::vector < T >,
75  }
76  };
77 
91  {
92  static bool check_convertibility_per_element() { return false; }
93 
94  template <typename ContainerType>
95  static bool check_size(boost::type<ContainerType>, std::size_t /* sz */ )
96  {
97  return true;
98  }
99 
100  template <typename ContainerType>
101  static void
102  assert_size(boost::type<ContainerType>, std::size_t /* sz */) {}
103 
104  template <typename ContainerType>
105  static void reserve(ContainerType& a, std::size_t /* sz */ ) {}
106  };
107 
121  {
122  template <typename ContainerType>
123  static void reserve(ContainerType& a, std::size_t sz)
124  {
125  a.reserve(sz);
126  }
127 
128  template <typename ContainerType, typename ValueType>
129  static void set_value(ContainerType& a, std::size_t i, ValueType const& v)
130  {
131  assert(a.size() == i);
132  a.push_back(v);
133  }
134  };
135 
147  template <typename ContainerType, typename ConversionPolicy>
149  {
150  typedef typename ContainerType::value_type container_element_type;
151 
153  {
154  boost::python::converter::registry::push_back(
155  &convertible,
156  &construct,
157  boost::python::type_id<ContainerType>());
158  }
159 
162  static void* convertible(PyObject* obj_ptr)
163  {
164  using namespace boost::python;
165  using boost::python::allow_null; // works around gcc 2.96 bug
166  {
167  // Restriction to list, tuple, iter, xrange until
168  // Boost.Python overload resolution is enhanced.
169  //
170  // add PySequence_Check() for numarray.
171  //
172  if (!( PyList_Check(obj_ptr)
173  || PyTuple_Check(obj_ptr)
174  || PyIter_Check(obj_ptr)
175  || PyRange_Check(obj_ptr)
176  || PySequence_Check(obj_ptr) )) return 0;
177  }
178  handle<> obj_iter(allow_null(PyObject_GetIter(obj_ptr)));
179  if (!obj_iter.get()) { // must be convertible to an iterator
180  PyErr_Clear();
181  return 0;
182  }
183  if (ConversionPolicy::check_convertibility_per_element()) {
184  int obj_size = PyObject_Length(obj_ptr);
185  if (obj_size < 0) { // must be a measurable sequence
186  PyErr_Clear();
187  return 0;
188  }
190  boost::type<ContainerType>(), obj_size)) return 0;
191  bool is_range = PyRange_Check(obj_ptr);
192  //std::size_t i=0;
193  int i = 0;
194 #ifndef _MSC_VER // because it causes c1001: internal compiler error
195  for(;;i++) {
196  handle<> py_elem_hdl(allow_null(PyIter_Next(obj_iter.get())));
197  if (PyErr_Occurred()) {
198  PyErr_Clear();
199  return 0;
200  }
201  if (!py_elem_hdl.get()) break; // end of iteration
202  object py_elem_obj(py_elem_hdl);
203  extract<container_element_type> elem_proxy(py_elem_obj);
204  if (!elem_proxy.check()) return 0;
205  if (is_range) break; // in a range all elements are of the same type
206  }
207  if (!is_range) assert(i == obj_size );
208 #endif
209  }
210  return obj_ptr;
211  }
212 
214  static void construct(
215  PyObject* obj_ptr,
216  boost::python::converter::rvalue_from_python_stage1_data* data)
217  {
218  using namespace boost::python;
219  using boost::python::allow_null; // works around gcc 2.96 bug
220  using boost::python::converter::rvalue_from_python_storage; // dito
221  using boost::python::throw_error_already_set; // dito
222  handle<> obj_iter(PyObject_GetIter(obj_ptr));
223  void* storage = (
224  (rvalue_from_python_storage<ContainerType>*)
225  data)->storage.bytes;
226  new (storage) ContainerType();
227  data->convertible = storage;
228  ContainerType& result = *((ContainerType*)storage);
229  std::size_t i=0;
230  for(;;i++) {
231  handle<> py_elem_hdl(allow_null(PyIter_Next(obj_iter.get())));
232  if (PyErr_Occurred()) throw_error_already_set();
233  if (!py_elem_hdl.get()) break; // end of iteration
234  object py_elem_obj(py_elem_hdl);
235  extract<container_element_type> elem_proxy(py_elem_obj);
236  ConversionPolicy::set_value(result, i, elem_proxy());
237  }
238  ConversionPolicy::assert_size(boost::type<ContainerType>(), i);
239  }
240 
241  };
242 
243 #endif // PY_CONVERSIONS_H

Generated for HippoDraw Class Library by doxygen