24#ifndef PXR_BASE_TF_PY_CONTAINER_CONVERSIONS_H
25#define PXR_BASE_TF_PY_CONTAINER_CONVERSIONS_H
47#include <boost/python/list.hpp>
48#include <boost/python/tuple.hpp>
49#include <boost/python/extract.hpp>
50#include <boost/python/to_python_converter.hpp>
57PXR_NAMESPACE_OPEN_SCOPE
60template <
typename ContainerType>
61struct TfPySequenceToPython
63 static PyObject* convert(ContainerType
const &c)
65 boost::python::list result;
69 return boost::python::incref(result.ptr());
74template <
typename ContainerType>
75struct TfPySequenceToPythonSet
77 static PyObject* convert(ContainerType
const &c)
79 PyObject* result = PySet_New(
nullptr);
80 for (
const auto &elem : c) {
81 PySet_Add(result, boost::python::object(elem).ptr());
87template <
typename ContainerType>
88struct TfPyMapToPythonDict
90 static PyObject* convert(ContainerType
const &c)
96namespace TfPyContainerConversions {
98 template <
typename ContainerType>
101 static PyObject* convert(ContainerType
const& a)
103 boost::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(boost::python::object(*p));
108 return boost::python::incref(boost::python::tuple(result).ptr());
112 template <
typename First,
typename Second>
113 struct to_tuple<
std::pair<First, Second> > {
114 static PyObject* convert(std::pair<First, Second>
const& a)
116 boost::python::tuple result =
117 boost::python::make_tuple(a.first, a.second);
118 return boost::python::incref(result.ptr());
122 struct default_policy
124 static bool check_convertibility_per_element() {
return false; }
126 template <
typename ContainerType>
127 static bool check_size(boost::type<ContainerType>, std::size_t sz)
132 template <
typename ContainerType>
133 static void assert_size(boost::type<ContainerType>, std::size_t sz) {}
135 template <
typename ContainerType>
136 static void reserve(ContainerType& a, std::size_t sz) {}
139 struct fixed_size_policy
141 static bool check_convertibility_per_element() {
return true; }
143 template <
typename ContainerType>
144 static bool check_size(boost::type<ContainerType>, std::size_t sz)
146 return ContainerType::size() == sz;
149 template <
typename ContainerType>
150 static void assert_size(boost::type<ContainerType>, std::size_t sz)
152 if (!check_size(boost::type<ContainerType>(), sz)) {
153 PyErr_SetString(PyExc_RuntimeError,
154 "Insufficient elements for fixed-size array.");
155 boost::python::throw_error_already_set();
159 template <
typename ContainerType>
160 static void reserve(ContainerType& a, std::size_t sz)
162 if (sz > ContainerType::size()) {
163 PyErr_SetString(PyExc_RuntimeError,
164 "Too many elements for fixed-size array.");
165 boost::python::throw_error_already_set();
169 template <
typename ContainerType,
typename ValueType>
170 static void set_value(ContainerType& a, std::size_t i, ValueType
const& v)
177 struct variable_capacity_policy : default_policy
179 template <
typename ContainerType>
180 static void reserve(ContainerType& a, std::size_t sz)
185 template <
typename ContainerType,
typename ValueType>
186 static void set_value(ContainerType& a, std::size_t i, ValueType
const& v)
193 struct variable_capacity_all_items_convertible_policy : variable_capacity_policy
195 static bool check_convertibility_per_element() {
return true; }
198 struct fixed_capacity_policy : variable_capacity_policy
200 template <
typename ContainerType>
201 static bool check_size(boost::type<ContainerType>, std::size_t sz)
203 return ContainerType::max_size() >= sz;
207 struct linked_list_policy : default_policy
209 template <
typename ContainerType,
typename ValueType>
210 static void set_value(ContainerType& a, std::size_t i, ValueType
const& v)
216 struct set_policy : default_policy
218 template <
typename ContainerType,
typename ValueType>
219 static void set_value(ContainerType& a, std::size_t i, ValueType
const& v)
225 template <
typename ContainerType,
typename ConversionPolicy>
226 struct from_python_sequence
228 typedef typename ContainerType::value_type container_element_type;
230 from_python_sequence()
232 boost::python::converter::registry::push_back(
235 boost::python::type_id<ContainerType>());
238 static void* convertible(PyObject* obj_ptr)
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
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 boost::python::handle<> obj_iter(
257 boost::python::allow_null(PyObject_GetIter(obj_ptr)));
258 if (!obj_iter.get()) {
262 if (ConversionPolicy::check_convertibility_per_element()) {
263 Py_ssize_t obj_size = PyObject_Length(obj_ptr);
268 if (!ConversionPolicy::check_size(
269 boost::type<ContainerType>(), obj_size))
return 0;
270 bool is_range = PyRange_Check(obj_ptr);
272 if (!all_elements_convertible(obj_iter, is_range, i))
return 0;
273 if (!is_range) assert(i == (std::size_t)obj_size);
281 all_elements_convertible(
282 boost::python::handle<>& obj_iter,
287 boost::python::handle<> py_elem_hdl(
288 boost::python::allow_null(PyIter_Next(obj_iter.get())));
289 if (PyErr_Occurred()) {
293 if (!py_elem_hdl.get())
break;
294 boost::python::object py_elem_obj(py_elem_hdl);
295 boost::python::extract<container_element_type>
296 elem_proxy(py_elem_obj);
297 if (!elem_proxy.check())
return false;
303 static void construct(
305 boost::python::converter::rvalue_from_python_stage1_data* data)
307 boost::python::handle<> obj_iter(PyObject_GetIter(obj_ptr));
309 (boost::python::converter::rvalue_from_python_storage<ContainerType>*)
310 data)->storage.bytes;
311 new (storage) ContainerType();
312 data->convertible = storage;
313 ContainerType& result = *((ContainerType*)storage);
316 boost::python::handle<> py_elem_hdl(
317 boost::python::allow_null(PyIter_Next(obj_iter.get())));
318 if (PyErr_Occurred()) boost::python::throw_error_already_set();
319 if (!py_elem_hdl.get())
break;
320 boost::python::object py_elem_obj(py_elem_hdl);
321 boost::python::extract<container_element_type> elem_proxy(py_elem_obj);
322 ConversionPolicy::set_value(result, i, elem_proxy());
324 ConversionPolicy::assert_size(boost::type<ContainerType>(), i);
328 template <
typename PairType>
329 struct from_python_tuple_pair {
330 typedef typename PairType::first_type first_type;
331 typedef typename PairType::second_type second_type;
333 from_python_tuple_pair()
335 boost::python::converter::registry::push_back(
338 boost::python::type_id<PairType>());
341 static void* convertible(PyObject* obj_ptr)
343 if (!PyTuple_Check(obj_ptr) || PyTuple_Size(obj_ptr) != 2) {
346 boost::python::extract<first_type> e1(PyTuple_GetItem(obj_ptr, 0));
347 boost::python::extract<second_type> e2(PyTuple_GetItem(obj_ptr, 1));
348 if (!e1.check() || !e2.check()) {
354 static void construct(
356 boost::python::converter::rvalue_from_python_stage1_data* data)
359 (boost::python::converter::rvalue_from_python_storage<PairType>*)
360 data)->storage.bytes;
361 boost::python::extract<first_type> e1(PyTuple_GetItem(obj_ptr, 0));
362 boost::python::extract<second_type> e2(PyTuple_GetItem(obj_ptr, 1));
363 new (storage) PairType(e1(), e2());
364 data->convertible = storage;
368 template <
typename ContainerType>
369 struct to_tuple_mapping
372 boost::python::to_python_converter<
374 to_tuple<ContainerType> >();
378 template <
typename ContainerType,
typename ConversionPolicy>
379 struct tuple_mapping : to_tuple_mapping<ContainerType>
382 from_python_sequence<
388 template <
typename ContainerType>
389 struct tuple_mapping_fixed_size
391 tuple_mapping_fixed_size() {
394 fixed_size_policy>();
398 template <
typename ContainerType>
399 struct tuple_mapping_fixed_capacity
401 tuple_mapping_fixed_capacity() {
404 fixed_capacity_policy>();
408 template <
typename ContainerType>
409 struct tuple_mapping_variable_capacity
411 tuple_mapping_variable_capacity() {
414 variable_capacity_policy>();
418 template <
typename ContainerType>
419 struct tuple_mapping_set
421 tuple_mapping_set() {
428 template <
typename ContainerType>
429 struct tuple_mapping_pair
431 tuple_mapping_pair() {
432 boost::python::to_python_converter<
434 to_tuple<ContainerType> >();
435 from_python_tuple_pair<ContainerType>();
442void TfPyRegisterStlSequencesFromPython()
444 using namespace TfPyContainerConversions;
445 from_python_sequence<
446 std::vector<T>, variable_capacity_all_items_convertible_policy>();
447 from_python_sequence<
448 std::list<T>, variable_capacity_all_items_convertible_policy>();
449 from_python_sequence<
450 std::deque<T>, variable_capacity_all_items_convertible_policy>();
453PXR_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.
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.