HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pyContainerConversions.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_BASE_TF_PY_CONTAINER_CONVERSIONS_H
25 #define PXR_BASE_TF_PY_CONTAINER_CONVERSIONS_H
26 
27 /// \file tf/pyContainerConversions.h
28 /// Utilities for providing C++ <-> Python container support.
29 
30 /*
31  * Adapted (modified) from original at http://cctbx.sourceforge.net
32  * Original file:
33  * cctbx/scitbx/include/scitbx/boost_python/container_conversions.h
34  * License:
35  * http://cvs.sourceforge.net/viewcvs.py/cctbx/cctbx/
36  * LICENSE.txt?rev=1.2&view=markup
37  */
38 
39 #include "pxr/pxr.h"
40 
41 #include "pxr/base/tf/refPtr.h"
42 #include "pxr/base/tf/weakPtr.h"
43 #include "pxr/base/tf/diagnostic.h"
44 #include "pxr/base/tf/iterator.h"
45 #include "pxr/base/tf/pyUtils.h"
46 
47 #include <hboost/python/list.hpp>
48 #include <hboost/python/tuple.hpp>
49 #include <hboost/python/extract.hpp>
50 #include <hboost/python/to_python_converter.hpp>
51 
52 #include <deque>
53 #include <list>
54 #include <set>
55 #include <vector>
56 
58 
59 // Converter from vector<string> to python list.
60 template <typename ContainerType>
62 {
63  static PyObject* convert(ContainerType const &c)
64  {
65  hboost::python::list result;
66  TF_FOR_ALL(i, c) {
67  result.append(*i);
68  }
69  return hboost::python::incref(result.ptr());
70  }
71 };
72 
73 template <typename ContainerType>
75 {
76  static PyObject* convert(ContainerType const &c)
77  {
78  return hboost::python::incref(TfPyCopyMapToDictionary(c).ptr());
79  }
80 };
81 
82 namespace TfPyContainerConversions {
83 
84  template <typename ContainerType>
85  struct to_tuple
86  {
87  static PyObject* convert(ContainerType const& a)
88  {
89  hboost::python::list result;
90  typedef typename ContainerType::const_iterator const_iter;
91  for(const_iter p=a.begin();p!=a.end();p++) {
92  result.append(hboost::python::object(*p));
93  }
94  return hboost::python::incref(hboost::python::tuple(result).ptr());
95  }
96  };
97 
98  template <typename First, typename Second>
99  struct to_tuple<std::pair<First, Second> > {
100  static PyObject* convert(std::pair<First, Second> const& a)
101  {
102  hboost::python::tuple result =
103  hboost::python::make_tuple(a.first, a.second);
104  return hboost::python::incref(result.ptr());
105  }
106  };
107 
109  {
110  static bool check_convertibility_per_element() { return false; }
111 
112  template <typename ContainerType>
113  static bool check_size(hboost::type<ContainerType>, std::size_t sz)
114  {
115  return true;
116  }
117 
118  template <typename ContainerType>
119  static void assert_size(hboost::type<ContainerType>, std::size_t sz) {}
120 
121  template <typename ContainerType>
122  static void reserve(ContainerType& a, std::size_t sz) {}
123  };
124 
126  {
127  static bool check_convertibility_per_element() { return true; }
128 
129  template <typename ContainerType>
130  static bool check_size(hboost::type<ContainerType>, std::size_t sz)
131  {
132  return ContainerType::size() == sz;
133  }
134 
135  template <typename ContainerType>
136  static void assert_size(hboost::type<ContainerType>, std::size_t sz)
137  {
138  if (!check_size(hboost::type<ContainerType>(), sz)) {
139  PyErr_SetString(PyExc_RuntimeError,
140  "Insufficient elements for fixed-size array.");
141  hboost::python::throw_error_already_set();
142  }
143  }
144 
145  template <typename ContainerType>
146  static void reserve(ContainerType& a, std::size_t sz)
147  {
148  if (sz > ContainerType::size()) {
149  PyErr_SetString(PyExc_RuntimeError,
150  "Too many elements for fixed-size array.");
151  hboost::python::throw_error_already_set();
152  }
153  }
154 
155  template <typename ContainerType, typename ValueType>
156  static void set_value(ContainerType& a, std::size_t i, ValueType const& v)
157  {
158  reserve(a, i+1);
159  a[i] = v;
160  }
161  };
162 
164  {
165  template <typename ContainerType>
166  static void reserve(ContainerType& a, std::size_t sz)
167  {
168  a.reserve(sz);
169  }
170 
171  template <typename ContainerType, typename ValueType>
172  static void set_value(ContainerType& a, std::size_t i, ValueType const& v)
173  {
174  TF_AXIOM(a.size() == i);
175  a.push_back(v);
176  }
177  };
178 
180  {
181  static bool check_convertibility_per_element() { return true; }
182  };
183 
185  {
186  template <typename ContainerType>
187  static bool check_size(hboost::type<ContainerType>, std::size_t sz)
188  {
189  return ContainerType::max_size() >= sz;
190  }
191  };
192 
194  {
195  template <typename ContainerType, typename ValueType>
196  static void set_value(ContainerType& a, std::size_t i, ValueType const& v)
197  {
198  a.push_back(v);
199  }
200  };
201 
203  {
204  template <typename ContainerType, typename ValueType>
205  static void set_value(ContainerType& a, std::size_t i, ValueType const& v)
206  {
207  a.insert(v);
208  }
209  };
210 
211  template <typename ContainerType, typename ConversionPolicy>
213  {
215 
217  {
218  hboost::python::converter::registry::push_back(
219  &convertible,
220  &construct,
221  hboost::python::type_id<ContainerType>());
222  }
223 
224  static void* convertible(PyObject* obj_ptr)
225  {
226  if (!( PyList_Check(obj_ptr)
227  || PyTuple_Check(obj_ptr)
228  || PySet_Check(obj_ptr)
229  || PyFrozenSet_Check(obj_ptr)
230  || PyIter_Check(obj_ptr)
231  || PyRange_Check(obj_ptr)
232  || ( !PyBytes_Check(obj_ptr)
233  && !PyUnicode_Check(obj_ptr)
234  && ( Py_TYPE(obj_ptr) == 0
235  || Py_TYPE(Py_TYPE(obj_ptr)) == 0
236  || Py_TYPE(Py_TYPE(obj_ptr))->tp_name == 0
237  || std::strcmp(
238  Py_TYPE(Py_TYPE(obj_ptr))->tp_name,
239  "Boost.Python.class") != 0)
240  && PyObject_HasAttrString(obj_ptr, "__len__")
241  && PyObject_HasAttrString(obj_ptr, "__getitem__")))) return 0;
242  hboost::python::handle<> obj_iter(
243  hboost::python::allow_null(PyObject_GetIter(obj_ptr)));
244  if (!obj_iter.get()) { // must be convertible to an iterator
245  PyErr_Clear();
246  return 0;
247  }
248  if (ConversionPolicy::check_convertibility_per_element()) {
249  Py_ssize_t obj_size = PyObject_Length(obj_ptr);
250  if (obj_size < 0) { // must be a measurable sequence
251  PyErr_Clear();
252  return 0;
253  }
254  if (!ConversionPolicy::check_size(
255  hboost::type<ContainerType>(), obj_size)) return 0;
256  bool is_range = PyRange_Check(obj_ptr);
257  std::size_t i=0;
258  if (!all_elements_convertible(obj_iter, is_range, i)) return 0;
259  if (!is_range) assert(i == (std::size_t)obj_size);
260  }
261  return obj_ptr;
262  }
263 
264  // This loop factored out by Achim Domma to avoid Visual C++
265  // Internal Compiler Error.
266  static bool
268  hboost::python::handle<>& obj_iter,
269  bool is_range,
270  std::size_t& i)
271  {
272  for(;;i++) {
273  hboost::python::handle<> py_elem_hdl(
274  hboost::python::allow_null(PyIter_Next(obj_iter.get())));
275  if (PyErr_Occurred()) {
276  PyErr_Clear();
277  return false;
278  }
279  if (!py_elem_hdl.get()) break; // end of iteration
280  hboost::python::object py_elem_obj(py_elem_hdl);
281  hboost::python::extract<container_element_type>
282  elem_proxy(py_elem_obj);
283  if (!elem_proxy.check()) return false;
284  if (is_range) break; // in a range all elements are of the same type
285  }
286  return true;
287  }
288 
289  static void construct(
290  PyObject* obj_ptr,
291  hboost::python::converter::rvalue_from_python_stage1_data* data)
292  {
293  hboost::python::handle<> obj_iter(PyObject_GetIter(obj_ptr));
294  void* storage = (
295  (hboost::python::converter::rvalue_from_python_storage<ContainerType>*)
296  data)->storage.bytes;
297  new (storage) ContainerType();
298  data->convertible = storage;
299  ContainerType& result = *((ContainerType*)storage);
300  std::size_t i=0;
301  for(;;i++) {
302  hboost::python::handle<> py_elem_hdl(
303  hboost::python::allow_null(PyIter_Next(obj_iter.get())));
304  if (PyErr_Occurred()) hboost::python::throw_error_already_set();
305  if (!py_elem_hdl.get()) break; // end of iteration
306  hboost::python::object py_elem_obj(py_elem_hdl);
307  hboost::python::extract<container_element_type> elem_proxy(py_elem_obj);
308  ConversionPolicy::set_value(result, i, elem_proxy());
309  }
310  ConversionPolicy::assert_size(hboost::type<ContainerType>(), i);
311  }
312  };
313 
314  template <typename PairType>
316  typedef typename PairType::first_type first_type;
317  typedef typename PairType::second_type second_type;
318 
320  {
321  hboost::python::converter::registry::push_back(
322  &convertible,
323  &construct,
324  hboost::python::type_id<PairType>());
325  }
326 
327  static void* convertible(PyObject* obj_ptr)
328  {
329  if (!PyTuple_Check(obj_ptr) || PyTuple_Size(obj_ptr) != 2) {
330  return 0;
331  }
332  hboost::python::extract<first_type> e1(PyTuple_GetItem(obj_ptr, 0));
333  hboost::python::extract<second_type> e2(PyTuple_GetItem(obj_ptr, 1));
334  if (!e1.check() || !e2.check()) {
335  return 0;
336  }
337  return obj_ptr;
338  }
339 
340  static void construct(
341  PyObject* obj_ptr,
342  hboost::python::converter::rvalue_from_python_stage1_data* data)
343  {
344  void* storage = (
345  (hboost::python::converter::rvalue_from_python_storage<PairType>*)
346  data)->storage.bytes;
347  hboost::python::extract<first_type> e1(PyTuple_GetItem(obj_ptr, 0));
348  hboost::python::extract<second_type> e2(PyTuple_GetItem(obj_ptr, 1));
349  new (storage) PairType(e1(), e2());
350  data->convertible = storage;
351  }
352  };
353 
354  template <typename ContainerType>
356  {
358  hboost::python::to_python_converter<
359  ContainerType,
361  }
362  };
363 
364  template <typename ContainerType, typename ConversionPolicy>
365  struct tuple_mapping : to_tuple_mapping<ContainerType>
366  {
369  ContainerType,
370  ConversionPolicy>();
371  }
372  };
373 
374  template <typename ContainerType>
376  {
379  ContainerType,
381  }
382  };
383 
384  template <typename ContainerType>
386  {
389  ContainerType,
391  }
392  };
393 
394  template <typename ContainerType>
396  {
399  ContainerType,
401  }
402  };
403 
404  template <typename ContainerType>
406  {
409  ContainerType,
410  set_policy>();
411  }
412  };
413 
414  template <typename ContainerType>
416  {
418  hboost::python::to_python_converter<
419  ContainerType,
422  }
423  };
424 
425 } // namespace TfPyContainerConversions
426 
427 template <class T>
429 {
430  using namespace TfPyContainerConversions;
437 }
438 
440 
441 #endif // PXR_BASE_TF_PY_CONTAINER_CONVERSIONS_H
GLsizeiptr size
Definition: glew.h:1681
static void set_value(ContainerType &a, std::size_t i, ValueType const &v)
static void assert_size(hboost::type< ContainerType >, std::size_t sz)
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:9477
static void construct(PyObject *obj_ptr, hboost::python::converter::rvalue_from_python_stage1_data *data)
static void set_value(ContainerType &a, std::size_t i, ValueType const &v)
const GLdouble * v
Definition: glew.h:1391
static void set_value(ContainerType &a, std::size_t i, ValueType const &v)
static void construct(PyObject *obj_ptr, hboost::python::converter::rvalue_from_python_stage1_data *data)
uint64 value_type
Definition: GA_PrimCompat.h:29
static PyObject * convert(ContainerType const &a)
static bool check_size(hboost::type< ContainerType >, std::size_t sz)
void TfPyRegisterStlSequencesFromPython()
GLint GLenum GLsizei GLint GLsizei const void * data
Definition: glew.h:1379
hboost::python::dict TfPyCopyMapToDictionary(Map const &map)
Creates a python dictionary from a std::map.
Definition: pyUtils.h:233
GLuint object
Definition: glew.h:8986
const GLfloat * c
Definition: glew.h:16296
static bool check_size(hboost::type< ContainerType >, std::size_t sz)
static void assert_size(hboost::type< ContainerType >, std::size_t sz)
static void reserve(ContainerType &a, std::size_t sz)
GLfloat GLfloat p
Definition: glew.h:16321
static bool check_size(hboost::type< ContainerType >, std::size_t sz)
#define TF_AXIOM(cond)
static PyObject * convert(ContainerType const &c)
static bool all_elements_convertible(hboost::python::handle<> &obj_iter, bool is_range, std::size_t &i)
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1346
const void * ptr(const T *p)
Definition: format.h:3292
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91
static void set_value(ContainerType &a, std::size_t i, ValueType const &v)
GLuint64EXT * result
Definition: glew.h:14007
getOption("OpenEXR.storage") storage
Definition: HDK_Image.dox:276
#define TF_FOR_ALL(iter, c)
Definition: iterator.h:390
static void reserve(ContainerType &a, std::size_t sz)
static PyObject * convert(std::pair< First, Second > const &a)
static PyObject * convert(ContainerType const &c)
static void reserve(ContainerType &a, std::size_t sz)