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 // Converts any iterable C++ container to a 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 // Converts any iterable C++ container to a Python set.
74 template <typename ContainerType>
76 {
77  static PyObject* convert(ContainerType const &c)
78  {
79  PyObject* result = PySet_New(nullptr);
80  for (const auto &elem : c) {
81  PySet_Add(result, hboost::python::object(elem).ptr());
82  }
83  return result;
84  }
85 };
86 
87 template <typename ContainerType>
89 {
90  static PyObject* convert(ContainerType const &c)
91  {
92  return hboost::python::incref(TfPyCopyMapToDictionary(c).ptr());
93  }
94 };
95 
96 namespace TfPyContainerConversions {
97 
98  template <typename ContainerType>
99  struct to_tuple
100  {
101  static PyObject* convert(ContainerType const& a)
102  {
103  hboost::python::list result;
104  typedef typename ContainerType::const_iterator const_iter;
105  for(const_iter p=a.begin();p!=a.end();p++) {
106  result.append(hboost::python::object(*p));
107  }
108  return hboost::python::incref(hboost::python::tuple(result).ptr());
109  }
110  };
111 
112  template <typename First, typename Second>
113  struct to_tuple<std::pair<First, Second> > {
114  static PyObject* convert(std::pair<First, Second> const& a)
115  {
116  hboost::python::tuple result =
117  hboost::python::make_tuple(a.first, a.second);
118  return hboost::python::incref(result.ptr());
119  }
120  };
121 
123  {
124  static bool check_convertibility_per_element() { return false; }
125 
126  template <typename ContainerType>
127  static bool check_size(hboost::type<ContainerType>, std::size_t sz)
128  {
129  return true;
130  }
131 
132  template <typename ContainerType>
133  static void assert_size(hboost::type<ContainerType>, std::size_t sz) {}
134 
135  template <typename ContainerType>
136  static void reserve(ContainerType& a, std::size_t sz) {}
137  };
138 
140  {
141  static bool check_convertibility_per_element() { return true; }
142 
143  template <typename ContainerType>
144  static bool check_size(hboost::type<ContainerType>, std::size_t sz)
145  {
146  return ContainerType::size() == sz;
147  }
148 
149  template <typename ContainerType>
150  static void assert_size(hboost::type<ContainerType>, std::size_t sz)
151  {
152  if (!check_size(hboost::type<ContainerType>(), sz)) {
153  PyErr_SetString(PyExc_RuntimeError,
154  "Insufficient elements for fixed-size array.");
155  hboost::python::throw_error_already_set();
156  }
157  }
158 
159  template <typename ContainerType>
160  static void reserve(ContainerType& a, std::size_t sz)
161  {
162  if (sz > ContainerType::size()) {
163  PyErr_SetString(PyExc_RuntimeError,
164  "Too many elements for fixed-size array.");
165  hboost::python::throw_error_already_set();
166  }
167  }
168 
169  template <typename ContainerType, typename ValueType>
170  static void set_value(ContainerType& a, std::size_t i, ValueType const& v)
171  {
172  reserve(a, i+1);
173  a[i] = v;
174  }
175  };
176 
178  {
179  template <typename ContainerType>
180  static void reserve(ContainerType& a, std::size_t sz)
181  {
182  a.reserve(sz);
183  }
184 
185  template <typename ContainerType, typename ValueType>
186  static void set_value(ContainerType& a, std::size_t i, ValueType const& v)
187  {
188  TF_AXIOM(a.size() == i);
189  a.push_back(v);
190  }
191  };
192 
194  {
195  static bool check_convertibility_per_element() { return true; }
196  };
197 
199  {
200  template <typename ContainerType>
201  static bool check_size(hboost::type<ContainerType>, std::size_t sz)
202  {
203  return ContainerType::max_size() >= sz;
204  }
205  };
206 
208  {
209  template <typename ContainerType, typename ValueType>
210  static void set_value(ContainerType& a, std::size_t i, ValueType const& v)
211  {
212  a.push_back(v);
213  }
214  };
215 
217  {
218  template <typename ContainerType, typename ValueType>
219  static void set_value(ContainerType& a, std::size_t i, ValueType const& v)
220  {
221  a.insert(v);
222  }
223  };
224 
225  template <typename ContainerType, typename ConversionPolicy>
227  {
229 
231  {
232  hboost::python::converter::registry::push_back(
233  &convertible,
234  &construct,
235  hboost::python::type_id<ContainerType>());
236  }
237 
238  static void* convertible(PyObject* obj_ptr)
239  {
240  if (!( PyList_Check(obj_ptr)
241  || PyTuple_Check(obj_ptr)
242  || PySet_Check(obj_ptr)
243  || PyFrozenSet_Check(obj_ptr)
244  || PyIter_Check(obj_ptr)
245  || PyRange_Check(obj_ptr)
246  || ( !PyBytes_Check(obj_ptr)
247  && !PyUnicode_Check(obj_ptr)
248  && ( Py_TYPE(obj_ptr) == 0
249  || Py_TYPE(Py_TYPE(obj_ptr)) == 0
250  || Py_TYPE(Py_TYPE(obj_ptr))->tp_name == 0
251  || std::strcmp(
252  Py_TYPE(Py_TYPE(obj_ptr))->tp_name,
253  "Boost.Python.class") != 0)
254  && PyObject_HasAttrString(obj_ptr, "__len__")
255  && PyObject_HasAttrString(obj_ptr, "__getitem__")))) return 0;
256  hboost::python::handle<> obj_iter(
257  hboost::python::allow_null(PyObject_GetIter(obj_ptr)));
258  if (!obj_iter.get()) { // must be convertible to an iterator
259  PyErr_Clear();
260  return 0;
261  }
262  if (ConversionPolicy::check_convertibility_per_element()) {
263  Py_ssize_t obj_size = PyObject_Length(obj_ptr);
264  if (obj_size < 0) { // must be a measurable sequence
265  PyErr_Clear();
266  return 0;
267  }
268  if (!ConversionPolicy::check_size(
269  hboost::type<ContainerType>(), obj_size)) return 0;
270  bool is_range = PyRange_Check(obj_ptr);
271  std::size_t i=0;
272  if (!all_elements_convertible(obj_iter, is_range, i)) return 0;
273  if (!is_range) assert(i == (std::size_t)obj_size);
274  }
275  return obj_ptr;
276  }
277 
278  // This loop factored out by Achim Domma to avoid Visual C++
279  // Internal Compiler Error.
280  static bool
282  hboost::python::handle<>& obj_iter,
283  bool is_range,
284  std::size_t& i)
285  {
286  for(;;i++) {
287  hboost::python::handle<> py_elem_hdl(
288  hboost::python::allow_null(PyIter_Next(obj_iter.get())));
289  if (PyErr_Occurred()) {
290  PyErr_Clear();
291  return false;
292  }
293  if (!py_elem_hdl.get()) break; // end of iteration
294  hboost::python::object py_elem_obj(py_elem_hdl);
295  hboost::python::extract<container_element_type>
296  elem_proxy(py_elem_obj);
297  if (!elem_proxy.check()) return false;
298  if (is_range) break; // in a range all elements are of the same type
299  }
300  return true;
301  }
302 
303  static void construct(
304  PyObject* obj_ptr,
305  hboost::python::converter::rvalue_from_python_stage1_data* data)
306  {
307  hboost::python::handle<> obj_iter(PyObject_GetIter(obj_ptr));
308  void* storage = (
309  (hboost::python::converter::rvalue_from_python_storage<ContainerType>*)
310  data)->storage.bytes;
311  new (storage) ContainerType();
312  data->convertible = storage;
313  ContainerType& result = *((ContainerType*)storage);
314  std::size_t i=0;
315  for(;;i++) {
316  hboost::python::handle<> py_elem_hdl(
317  hboost::python::allow_null(PyIter_Next(obj_iter.get())));
318  if (PyErr_Occurred()) hboost::python::throw_error_already_set();
319  if (!py_elem_hdl.get()) break; // end of iteration
320  hboost::python::object py_elem_obj(py_elem_hdl);
321  hboost::python::extract<container_element_type> elem_proxy(py_elem_obj);
322  ConversionPolicy::set_value(result, i, elem_proxy());
323  }
324  ConversionPolicy::assert_size(hboost::type<ContainerType>(), i);
325  }
326  };
327 
328  template <typename PairType>
330  typedef typename PairType::first_type first_type;
331  typedef typename PairType::second_type second_type;
332 
334  {
335  hboost::python::converter::registry::push_back(
336  &convertible,
337  &construct,
338  hboost::python::type_id<PairType>());
339  }
340 
341  static void* convertible(PyObject* obj_ptr)
342  {
343  if (!PyTuple_Check(obj_ptr) || PyTuple_Size(obj_ptr) != 2) {
344  return 0;
345  }
346  hboost::python::extract<first_type> e1(PyTuple_GetItem(obj_ptr, 0));
347  hboost::python::extract<second_type> e2(PyTuple_GetItem(obj_ptr, 1));
348  if (!e1.check() || !e2.check()) {
349  return 0;
350  }
351  return obj_ptr;
352  }
353 
354  static void construct(
355  PyObject* obj_ptr,
356  hboost::python::converter::rvalue_from_python_stage1_data* data)
357  {
358  void* storage = (
359  (hboost::python::converter::rvalue_from_python_storage<PairType>*)
360  data)->storage.bytes;
361  hboost::python::extract<first_type> e1(PyTuple_GetItem(obj_ptr, 0));
362  hboost::python::extract<second_type> e2(PyTuple_GetItem(obj_ptr, 1));
363  new (storage) PairType(e1(), e2());
364  data->convertible = storage;
365  }
366  };
367 
368  template <typename ContainerType>
370  {
372  hboost::python::to_python_converter<
375  }
376  };
377 
378  template <typename ContainerType, typename ConversionPolicy>
379  struct tuple_mapping : to_tuple_mapping<ContainerType>
380  {
384  ConversionPolicy>();
385  }
386  };
387 
388  template <typename ContainerType>
390  {
395  }
396  };
397 
398  template <typename ContainerType>
400  {
405  }
406  };
407 
408  template <typename ContainerType>
410  {
415  }
416  };
417 
418  template <typename ContainerType>
420  {
424  set_policy>();
425  }
426  };
427 
428  template <typename ContainerType>
430  {
432  hboost::python::to_python_converter<
436  }
437  };
438 
439 } // namespace TfPyContainerConversions
440 
441 template <class T>
443 {
444  using namespace TfPyContainerConversions;
451 }
452 
454 
455 #endif // PXR_BASE_TF_PY_CONTAINER_CONVERSIONS_H
static void set_value(ContainerType &a, std::size_t i, ValueType const &v)
getFileOption("OpenEXR:storage") storage
Definition: HDK_Image.dox:276
static void assert_size(hboost::type< ContainerType >, std::size_t sz)
const GLdouble * v
Definition: glcorearb.h:837
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
static void construct(PyObject *obj_ptr, hboost::python::converter::rvalue_from_python_stage1_data *data)
static PyObject * convert(ContainerType const &c)
static void set_value(ContainerType &a, std::size_t i, ValueType const &v)
**But if you need a result
Definition: thread.h:613
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()
hboost::python::dict TfPyCopyMapToDictionary(Map const &map)
Creates a python dictionary from a std::map.
Definition: pyUtils.h:275
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)
GLsizeiptr size
Definition: glcorearb.h:664
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:1441
auto ptr(T p) -> const void *
Definition: format.h:2448
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91
static void set_value(ContainerType &a, std::size_t i, ValueType const &v)
#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)
Definition: format.h:895
static void reserve(ContainerType &a, std::size_t sz)