7#ifndef PXR_BASE_TF_PY_CONTAINER_CONVERSIONS_H
8#define PXR_BASE_TF_PY_CONTAINER_CONVERSIONS_H
30#include <boost/python/list.hpp>
31#include <boost/python/tuple.hpp>
32#include <boost/python/extract.hpp>
33#include <boost/python/to_python_converter.hpp>
40PXR_NAMESPACE_OPEN_SCOPE
43template <
typename ContainerType>
44struct TfPySequenceToPython
46 static PyObject* convert(ContainerType
const &c)
48 boost::python::list result;
52 return boost::python::incref(result.ptr());
57template <
typename ContainerType>
58struct TfPySequenceToPythonSet
60 static PyObject* convert(ContainerType
const &c)
62 PyObject* result = PySet_New(
nullptr);
63 for (
const auto &elem : c) {
64 PySet_Add(result, boost::python::object(elem).ptr());
70template <
typename ContainerType>
71struct TfPyMapToPythonDict
73 static PyObject* convert(ContainerType
const &c)
79namespace TfPyContainerConversions {
81 template <
typename ContainerType>
84 static PyObject* convert(ContainerType
const& a)
86 boost::python::list result;
87 typedef typename ContainerType::const_iterator const_iter;
88 for(const_iter p=a.begin();p!=a.end();p++) {
89 result.append(boost::python::object(*p));
91 return boost::python::incref(boost::python::tuple(result).ptr());
95 template <
typename First,
typename Second>
96 struct to_tuple<
std::pair<First, Second> > {
97 static PyObject* convert(std::pair<First, Second>
const& a)
99 boost::python::tuple result =
100 boost::python::make_tuple(a.first, a.second);
101 return boost::python::incref(result.ptr());
105 struct default_policy
107 static bool check_convertibility_per_element() {
return false; }
109 template <
typename ContainerType>
110 static bool check_size(boost::type<ContainerType>, std::size_t sz)
115 template <
typename ContainerType>
116 static void assert_size(boost::type<ContainerType>, std::size_t sz) {}
118 template <
typename ContainerType>
119 static void reserve(ContainerType& a, std::size_t sz) {}
122 struct fixed_size_policy
124 static bool check_convertibility_per_element() {
return true; }
126 template <
typename ContainerType>
127 static bool check_size(boost::type<ContainerType>, std::size_t sz)
129 return ContainerType::size() == sz;
132 template <
typename ContainerType>
133 static void assert_size(boost::type<ContainerType>, std::size_t sz)
135 if (!check_size(boost::type<ContainerType>(), sz)) {
136 PyErr_SetString(PyExc_RuntimeError,
137 "Insufficient elements for fixed-size array.");
138 boost::python::throw_error_already_set();
142 template <
typename ContainerType>
143 static void reserve(ContainerType& a, std::size_t sz)
145 if (sz > ContainerType::size()) {
146 PyErr_SetString(PyExc_RuntimeError,
147 "Too many elements for fixed-size array.");
148 boost::python::throw_error_already_set();
152 template <
typename ContainerType,
typename ValueType>
153 static void set_value(ContainerType& a, std::size_t i, ValueType
const& v)
160 struct variable_capacity_policy : default_policy
162 template <
typename ContainerType>
163 static void reserve(ContainerType& a, std::size_t sz)
168 template <
typename ContainerType,
typename ValueType>
169 static void set_value(ContainerType& a, std::size_t i, ValueType
const& v)
176 struct variable_capacity_all_items_convertible_policy : variable_capacity_policy
178 static bool check_convertibility_per_element() {
return true; }
181 struct fixed_capacity_policy : variable_capacity_policy
183 template <
typename ContainerType>
184 static bool check_size(boost::type<ContainerType>, std::size_t sz)
186 return ContainerType::max_size() >= sz;
190 struct linked_list_policy : default_policy
192 template <
typename ContainerType,
typename ValueType>
193 static void set_value(ContainerType& a, std::size_t i, ValueType
const& v)
199 struct set_policy : default_policy
201 template <
typename ContainerType,
typename ValueType>
202 static void set_value(ContainerType& a, std::size_t i, ValueType
const& v)
208 template <
typename ContainerType,
typename ConversionPolicy>
209 struct from_python_sequence
211 typedef typename ContainerType::value_type container_element_type;
213 from_python_sequence()
215 boost::python::converter::registry::push_back(
218 boost::python::type_id<ContainerType>());
221 static void* convertible(PyObject* obj_ptr)
223 if (!( PyList_Check(obj_ptr)
224 || PyTuple_Check(obj_ptr)
225 || PySet_Check(obj_ptr)
226 || PyFrozenSet_Check(obj_ptr)
227 || PyIter_Check(obj_ptr)
228 || PyRange_Check(obj_ptr)
229 || ( !PyBytes_Check(obj_ptr)
230 && !PyUnicode_Check(obj_ptr)
231 && ( Py_TYPE(obj_ptr) == 0
232 || Py_TYPE(Py_TYPE(obj_ptr)) == 0
233 || Py_TYPE(Py_TYPE(obj_ptr))->tp_name == 0
235 Py_TYPE(Py_TYPE(obj_ptr))->tp_name,
236 "Boost.Python.class") != 0)
237 && PyObject_HasAttrString(obj_ptr,
"__len__")
238 && PyObject_HasAttrString(obj_ptr,
"__getitem__"))))
return 0;
239 boost::python::handle<> obj_iter(
240 boost::python::allow_null(PyObject_GetIter(obj_ptr)));
241 if (!obj_iter.get()) {
245 if (ConversionPolicy::check_convertibility_per_element()) {
246 Py_ssize_t obj_size = PyObject_Length(obj_ptr);
251 if (!ConversionPolicy::check_size(
252 boost::type<ContainerType>(), obj_size))
return 0;
253 bool is_range = PyRange_Check(obj_ptr);
255 if (!all_elements_convertible(obj_iter, is_range, i))
return 0;
256 if (!is_range) assert(i == (std::size_t)obj_size);
264 all_elements_convertible(
265 boost::python::handle<>& obj_iter,
270 boost::python::handle<> py_elem_hdl(
271 boost::python::allow_null(PyIter_Next(obj_iter.get())));
272 if (PyErr_Occurred()) {
276 if (!py_elem_hdl.get())
break;
277 boost::python::object py_elem_obj(py_elem_hdl);
278 boost::python::extract<container_element_type>
279 elem_proxy(py_elem_obj);
280 if (!elem_proxy.check())
return false;
286 static void construct(
288 boost::python::converter::rvalue_from_python_stage1_data* data)
290 boost::python::handle<> obj_iter(PyObject_GetIter(obj_ptr));
292 (boost::python::converter::rvalue_from_python_storage<ContainerType>*)
293 data)->storage.bytes;
294 new (storage) ContainerType();
295 data->convertible = storage;
296 ContainerType& result = *((ContainerType*)storage);
299 boost::python::handle<> py_elem_hdl(
300 boost::python::allow_null(PyIter_Next(obj_iter.get())));
301 if (PyErr_Occurred()) boost::python::throw_error_already_set();
302 if (!py_elem_hdl.get())
break;
303 boost::python::object py_elem_obj(py_elem_hdl);
304 boost::python::extract<container_element_type> elem_proxy(py_elem_obj);
305 ConversionPolicy::set_value(result, i, elem_proxy());
307 ConversionPolicy::assert_size(boost::type<ContainerType>(), i);
311 template <
typename PairType>
312 struct from_python_tuple_pair {
313 typedef typename PairType::first_type first_type;
314 typedef typename PairType::second_type second_type;
316 from_python_tuple_pair()
318 boost::python::converter::registry::push_back(
321 boost::python::type_id<PairType>());
324 static void* convertible(PyObject* obj_ptr)
326 if (!PyTuple_Check(obj_ptr) || PyTuple_Size(obj_ptr) != 2) {
329 boost::python::extract<first_type> e1(PyTuple_GetItem(obj_ptr, 0));
330 boost::python::extract<second_type> e2(PyTuple_GetItem(obj_ptr, 1));
331 if (!e1.check() || !e2.check()) {
337 static void construct(
339 boost::python::converter::rvalue_from_python_stage1_data* data)
342 (boost::python::converter::rvalue_from_python_storage<PairType>*)
343 data)->storage.bytes;
344 boost::python::extract<first_type> e1(PyTuple_GetItem(obj_ptr, 0));
345 boost::python::extract<second_type> e2(PyTuple_GetItem(obj_ptr, 1));
346 new (storage) PairType(e1(), e2());
347 data->convertible = storage;
351 template <
typename ContainerType>
352 struct to_tuple_mapping
355 boost::python::to_python_converter<
357 to_tuple<ContainerType> >();
361 template <
typename ContainerType,
typename ConversionPolicy>
362 struct tuple_mapping : to_tuple_mapping<ContainerType>
365 from_python_sequence<
371 template <
typename ContainerType>
372 struct tuple_mapping_fixed_size
374 tuple_mapping_fixed_size() {
377 fixed_size_policy>();
381 template <
typename ContainerType>
382 struct tuple_mapping_fixed_capacity
384 tuple_mapping_fixed_capacity() {
387 fixed_capacity_policy>();
391 template <
typename ContainerType>
392 struct tuple_mapping_variable_capacity
394 tuple_mapping_variable_capacity() {
397 variable_capacity_policy>();
401 template <
typename ContainerType>
402 struct tuple_mapping_set
404 tuple_mapping_set() {
411 template <
typename ContainerType>
412 struct tuple_mapping_pair
414 tuple_mapping_pair() {
415 boost::python::to_python_converter<
417 to_tuple<ContainerType> >();
418 from_python_tuple_pair<ContainerType>();
425void TfPyRegisterStlSequencesFromPython()
427 using namespace TfPyContainerConversions;
428 from_python_sequence<
429 std::vector<T>, variable_capacity_all_items_convertible_policy>();
430 from_python_sequence<
431 std::list<T>, variable_capacity_all_items_convertible_policy>();
432 from_python_sequence<
433 std::deque<T>, variable_capacity_all_items_convertible_policy>();
436PXR_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.