7#ifndef PXR_BASE_TF_PY_CONTAINER_CONVERSIONS_H
8#define PXR_BASE_TF_PY_CONTAINER_CONVERSIONS_H
30#include "pxr/external/boost/python/list.hpp"
31#include "pxr/external/boost/python/tuple.hpp"
32#include "pxr/external/boost/python/extract.hpp"
33#include "pxr/external/boost/python/to_python_converter.hpp"
41PXR_NAMESPACE_OPEN_SCOPE
44template <
typename ContainerType>
45struct TfPySequenceToPython
47 static PyObject* convert(ContainerType
const &c)
49 pxr_boost::python::list result;
53 return pxr_boost::python::incref(result.ptr());
58template <
typename ContainerType>
59struct TfPySequenceToPythonSet
61 static PyObject* convert(ContainerType
const &c)
63 PyObject* result = PySet_New(
nullptr);
64 for (
const auto &elem : c) {
65 PySet_Add(result, pxr_boost::python::object(elem).ptr());
71template <
typename ContainerType>
72struct TfPyMapToPythonDict
74 static PyObject* convert(ContainerType
const &c)
80namespace TfPyContainerConversions {
82 template <
typename ContainerType>
85 static PyObject* convert(ContainerType
const& a)
87 pxr_boost::python::list result;
88 typedef typename ContainerType::const_iterator const_iter;
89 for(const_iter p=a.begin();p!=a.end();p++) {
90 result.append(pxr_boost::python::object(*p));
92 return pxr_boost::python::incref(pxr_boost::python::tuple(result).ptr());
96 template <
typename First,
typename Second>
97 struct to_tuple<
std::pair<First, Second> > {
98 static PyObject* convert(std::pair<First, Second>
const& a)
100 pxr_boost::python::tuple result =
101 pxr_boost::python::make_tuple(a.first, a.second);
102 return pxr_boost::python::incref(result.ptr());
106 template <
typename... T>
107 struct to_tuple<
std::tuple<T...>> {
108 static PyObject* convert(std::tuple<T...>
const& a)
112 pxr_boost::python::tuple result =
113 pxr_boost::python::make_tuple(v...);
114 return pxr_boost::python::incref(result.ptr());
119 struct default_policy
121 static bool check_convertibility_per_element() {
return false; }
123 template <
typename ContainerType>
124 static bool check_size(ContainerType*, std::size_t sz)
129 template <
typename ContainerType>
130 static void assert_size(ContainerType*, std::size_t sz) {}
132 template <
typename ContainerType>
133 static void reserve(ContainerType& a, std::size_t sz) {}
136 struct fixed_size_policy
138 static bool check_convertibility_per_element() {
return true; }
140 template <
typename ContainerType>
141 static bool check_size(ContainerType*, std::size_t sz)
143 return ContainerType::size() == sz;
146 template <
typename ContainerType>
147 static void assert_size(ContainerType* c, std::size_t sz)
149 if (!check_size(c, sz)) {
150 PyErr_SetString(PyExc_RuntimeError,
151 "Insufficient elements for fixed-size array.");
152 pxr_boost::python::throw_error_already_set();
156 template <
typename ContainerType>
157 static void reserve(ContainerType& a, std::size_t sz)
159 if (sz > ContainerType::size()) {
160 PyErr_SetString(PyExc_RuntimeError,
161 "Too many elements for fixed-size array.");
162 pxr_boost::python::throw_error_already_set();
166 template <
typename ContainerType,
typename ValueType>
167 static void set_value(ContainerType& a, std::size_t i, ValueType
const& v)
174 struct variable_capacity_policy : default_policy
176 template <
typename ContainerType>
177 static void reserve(ContainerType& a, std::size_t sz)
182 template <
typename ContainerType,
typename ValueType>
183 static void set_value(ContainerType& a, std::size_t i, ValueType
const& v)
190 struct variable_capacity_all_items_convertible_policy : variable_capacity_policy
192 static bool check_convertibility_per_element() {
return true; }
195 struct fixed_capacity_policy : variable_capacity_policy
197 template <
typename ContainerType>
198 static bool check_size(ContainerType*, std::size_t sz)
200 return ContainerType::max_size() >= sz;
204 struct linked_list_policy : default_policy
206 template <
typename ContainerType,
typename ValueType>
207 static void set_value(ContainerType& a, std::size_t i, ValueType
const& v)
213 struct set_policy : default_policy
215 template <
typename ContainerType,
typename ValueType>
216 static void set_value(ContainerType& a, std::size_t i, ValueType
const& v)
222 template <
typename ContainerType,
typename ConversionPolicy>
223 struct from_python_sequence
225 typedef typename ContainerType::value_type container_element_type;
227 from_python_sequence()
229 pxr_boost::python::converter::registry::push_back(
232 pxr_boost::python::type_id<ContainerType>());
235 static void* convertible(PyObject* obj_ptr)
237 if (!( PyList_Check(obj_ptr)
238 || PyTuple_Check(obj_ptr)
239 || PySet_Check(obj_ptr)
240 || PyFrozenSet_Check(obj_ptr)
241 || PyIter_Check(obj_ptr)
242 || PyRange_Check(obj_ptr)
243 || ( !PyBytes_Check(obj_ptr)
244 && !PyUnicode_Check(obj_ptr)
245 && ( Py_TYPE(obj_ptr) == 0
246 || Py_TYPE(Py_TYPE(obj_ptr)) == 0
247 || Py_TYPE(Py_TYPE(obj_ptr))->tp_name == 0
249 Py_TYPE(Py_TYPE(obj_ptr))->tp_name,
250 "Boost.Python.class") != 0)
251 && PyObject_HasAttrString(obj_ptr,
"__len__")
252 && PyObject_HasAttrString(obj_ptr,
"__getitem__"))))
return 0;
253 pxr_boost::python::handle<> obj_iter(
254 pxr_boost::python::allow_null(PyObject_GetIter(obj_ptr)));
255 if (!obj_iter.get()) {
259 if (ConversionPolicy::check_convertibility_per_element()) {
260 Py_ssize_t obj_size = PyObject_Length(obj_ptr);
265 if (!ConversionPolicy::check_size(
266 (ContainerType*)
nullptr, obj_size))
return 0;
267 bool is_range = PyRange_Check(obj_ptr);
269 if (!all_elements_convertible(obj_iter, is_range, i))
return 0;
270 if (!is_range) assert(i == (std::size_t)obj_size);
278 all_elements_convertible(
279 pxr_boost::python::handle<>& obj_iter,
284 pxr_boost::python::handle<> py_elem_hdl(
285 pxr_boost::python::allow_null(PyIter_Next(obj_iter.get())));
286 if (PyErr_Occurred()) {
290 if (!py_elem_hdl.get())
break;
291 pxr_boost::python::object py_elem_obj(py_elem_hdl);
292 pxr_boost::python::extract<container_element_type>
293 elem_proxy(py_elem_obj);
294 if (!elem_proxy.check())
return false;
300 static void construct(
302 pxr_boost::python::converter::rvalue_from_python_stage1_data* data)
304 pxr_boost::python::handle<> obj_iter(PyObject_GetIter(obj_ptr));
306 (pxr_boost::python::converter::rvalue_from_python_storage<ContainerType>*)
307 data)->storage.bytes;
308 new (storage) ContainerType();
309 data->convertible = storage;
310 ContainerType& result = *((ContainerType*)storage);
313 pxr_boost::python::handle<> py_elem_hdl(
314 pxr_boost::python::allow_null(PyIter_Next(obj_iter.get())));
315 if (PyErr_Occurred()) pxr_boost::python::throw_error_already_set();
316 if (!py_elem_hdl.get())
break;
317 pxr_boost::python::object py_elem_obj(py_elem_hdl);
318 pxr_boost::python::extract<container_element_type> elem_proxy(py_elem_obj);
319 ConversionPolicy::set_value(result, i, elem_proxy());
321 ConversionPolicy::assert_size((ContainerType*)
nullptr, i);
325 template <
typename Indexes,
typename TupleType,
typename... T>
326 struct from_python_tuple_impl;
328 template <
size_t... I,
typename TupleType,
typename... T>
329 struct from_python_tuple_impl<
std::index_sequence<I...>, TupleType, T...>
331 from_python_tuple_impl()
333 pxr_boost::python::converter::registry::push_back(
336 pxr_boost::python::type_id<TupleType>());
339 static void* convertible(PyObject* obj_ptr)
341 if (!PyTuple_Check(obj_ptr) || PyTuple_Size(obj_ptr) !=
sizeof...(T)) {
344 if ((!pxr_boost::python::extract<T>(
345 PyTuple_GetItem(obj_ptr, I)).check() || ...)) {
351 static void construct(
353 pxr_boost::python::converter::rvalue_from_python_stage1_data* data)
356 (pxr_boost::python::converter::rvalue_from_python_storage<TupleType>*)
357 data)->storage.bytes;
358 new (storage) TupleType(
359 pxr_boost::python::extract<T>(PyTuple_GetItem(obj_ptr, I))()...);
360 data->convertible = storage;
364 template <
typename PairType>
365 struct from_python_tuple_pair
366 : from_python_tuple_impl<
367 std::make_index_sequence<2>, PairType,
368 typename PairType::first_type, typename PairType::second_type
373 template <
typename TupleType>
374 struct from_python_tuple;
376 template <
typename... T>
377 struct from_python_tuple<
std::tuple<T...>>
378 : from_python_tuple_impl<
379 std::index_sequence_for<T...>, std::tuple<T...>, T...
384 template <
typename ContainerType>
385 struct to_tuple_mapping
388 pxr_boost::python::to_python_converter<
390 to_tuple<ContainerType> >();
394 template <
typename ContainerType,
typename ConversionPolicy>
395 struct tuple_mapping : to_tuple_mapping<ContainerType>
398 from_python_sequence<
404 template <
typename ContainerType>
405 struct tuple_mapping_fixed_size
407 tuple_mapping_fixed_size() {
410 fixed_size_policy>();
414 template <
typename ContainerType>
415 struct tuple_mapping_fixed_capacity
417 tuple_mapping_fixed_capacity() {
420 fixed_capacity_policy>();
424 template <
typename ContainerType>
425 struct tuple_mapping_variable_capacity
427 tuple_mapping_variable_capacity() {
430 variable_capacity_policy>();
434 template <
typename ContainerType>
435 struct tuple_mapping_set
437 tuple_mapping_set() {
444 template <
typename ContainerType>
445 struct tuple_mapping_pair
447 tuple_mapping_pair() {
448 pxr_boost::python::to_python_converter<
450 to_tuple<ContainerType> >();
451 from_python_tuple_pair<ContainerType>();
458void TfPyRegisterStlSequencesFromPython()
460 using namespace TfPyContainerConversions;
461 from_python_sequence<
462 std::vector<T>, variable_capacity_all_items_convertible_policy>();
463 from_python_sequence<
464 std::list<T>, variable_capacity_all_items_convertible_policy>();
465 from_python_sequence<
466 std::deque<T>, variable_capacity_all_items_convertible_policy>();
469PXR_NAMESPACE_CLOSE_SCOPE
Low-level utilities for informing users of various internal and external diagnostic conditions.
A simple iterator adapter for STL containers.
Miscellaneous Utilities for dealing with script.
pxr_boost::python::dict TfPyCopyMapToDictionary(Map const &map)
Creates a python dictionary from a std::map.
#define TF_FOR_ALL(iter, c)
Macro for iterating over a container.
#define TF_AXIOM(cond)
Aborts if the condition cond is not met.
Pointer storage with deletion detection.