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>
57 PXR_NAMESPACE_OPEN_SCOPE
60 template <
typename ContainerType>
61 struct TfPySequenceToPython
63 static PyObject* convert(ContainerType
const &c)
65 boost::python::list result;
69 return boost::python::incref(result.ptr());
73 template <
typename ContainerType>
74 struct TfPyMapToPythonDict
76 static PyObject* convert(ContainerType
const &c)
82 namespace TfPyContainerConversions {
84 template <
typename ContainerType>
87 static PyObject* convert(ContainerType
const& a)
89 boost::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(boost::python::object(*p));
94 return boost::python::incref(boost::python::tuple(result).ptr());
98 template <
typename First,
typename Second>
99 struct to_tuple<std::pair<First, Second> > {
100 static PyObject* convert(std::pair<First, Second>
const& a)
102 boost::python::tuple result =
103 boost::python::make_tuple(a.first, a.second);
104 return boost::python::incref(result.ptr());
108 struct default_policy
110 static bool check_convertibility_per_element() {
return false; }
112 template <
typename ContainerType>
113 static bool check_size(boost::type<ContainerType>, std::size_t sz)
118 template <
typename ContainerType>
119 static void assert_size(boost::type<ContainerType>, std::size_t sz) {}
121 template <
typename ContainerType>
122 static void reserve(ContainerType& a, std::size_t sz) {}
125 struct fixed_size_policy
127 static bool check_convertibility_per_element() {
return true; }
129 template <
typename ContainerType>
130 static bool check_size(boost::type<ContainerType>, std::size_t sz)
132 return ContainerType::size() == sz;
135 template <
typename ContainerType>
136 static void assert_size(boost::type<ContainerType>, std::size_t sz)
138 if (!check_size(boost::type<ContainerType>(), sz)) {
139 PyErr_SetString(PyExc_RuntimeError,
140 "Insufficient elements for fixed-size array.");
141 boost::python::throw_error_already_set();
145 template <
typename ContainerType>
146 static void reserve(ContainerType& a, std::size_t sz)
148 if (sz > ContainerType::size()) {
149 PyErr_SetString(PyExc_RuntimeError,
150 "Too many elements for fixed-size array.");
151 boost::python::throw_error_already_set();
155 template <
typename ContainerType,
typename ValueType>
156 static void set_value(ContainerType& a, std::size_t i, ValueType
const& v)
163 struct variable_capacity_policy : default_policy
165 template <
typename ContainerType>
166 static void reserve(ContainerType& a, std::size_t sz)
171 template <
typename ContainerType,
typename ValueType>
172 static void set_value(ContainerType& a, std::size_t i, ValueType
const& v)
179 struct variable_capacity_all_items_convertible_policy : variable_capacity_policy
181 static bool check_convertibility_per_element() {
return true; }
184 struct fixed_capacity_policy : variable_capacity_policy
186 template <
typename ContainerType>
187 static bool check_size(boost::type<ContainerType>, std::size_t sz)
189 return ContainerType::max_size() >= sz;
193 struct linked_list_policy : default_policy
195 template <
typename ContainerType,
typename ValueType>
196 static void set_value(ContainerType& a, std::size_t i, ValueType
const& v)
202 struct set_policy : default_policy
204 template <
typename ContainerType,
typename ValueType>
205 static void set_value(ContainerType& a, std::size_t i, ValueType
const& v)
211 template <
typename ContainerType,
typename ConversionPolicy>
212 struct from_python_sequence
214 typedef typename ContainerType::value_type container_element_type;
216 from_python_sequence()
218 boost::python::converter::registry::push_back(
221 boost::python::type_id<ContainerType>());
224 static void* convertible(PyObject* obj_ptr)
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
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 boost::python::handle<> obj_iter(
243 boost::python::allow_null(PyObject_GetIter(obj_ptr)));
244 if (!obj_iter.get()) {
248 if (ConversionPolicy::check_convertibility_per_element()) {
249 Py_ssize_t obj_size = PyObject_Length(obj_ptr);
254 if (!ConversionPolicy::check_size(
255 boost::type<ContainerType>(), obj_size))
return 0;
256 bool is_range = PyRange_Check(obj_ptr);
258 if (!all_elements_convertible(obj_iter, is_range, i))
return 0;
259 if (!is_range) assert(i == (std::size_t)obj_size);
267 all_elements_convertible(
268 boost::python::handle<>& obj_iter,
273 boost::python::handle<> py_elem_hdl(
274 boost::python::allow_null(PyIter_Next(obj_iter.get())));
275 if (PyErr_Occurred()) {
279 if (!py_elem_hdl.get())
break;
280 boost::python::object py_elem_obj(py_elem_hdl);
281 boost::python::extract<container_element_type>
282 elem_proxy(py_elem_obj);
283 if (!elem_proxy.check())
return false;
289 static void construct(
291 boost::python::converter::rvalue_from_python_stage1_data* data)
293 boost::python::handle<> obj_iter(PyObject_GetIter(obj_ptr));
295 (boost::python::converter::rvalue_from_python_storage<ContainerType>*)
296 data)->storage.bytes;
297 new (storage) ContainerType();
298 data->convertible = storage;
299 ContainerType& result = *((ContainerType*)storage);
302 boost::python::handle<> py_elem_hdl(
303 boost::python::allow_null(PyIter_Next(obj_iter.get())));
304 if (PyErr_Occurred()) boost::python::throw_error_already_set();
305 if (!py_elem_hdl.get())
break;
306 boost::python::object py_elem_obj(py_elem_hdl);
307 boost::python::extract<container_element_type> elem_proxy(py_elem_obj);
308 ConversionPolicy::set_value(result, i, elem_proxy());
310 ConversionPolicy::assert_size(boost::type<ContainerType>(), i);
314 template <
typename PairType>
315 struct from_python_tuple_pair {
316 typedef typename PairType::first_type first_type;
317 typedef typename PairType::second_type second_type;
319 from_python_tuple_pair()
321 boost::python::converter::registry::push_back(
324 boost::python::type_id<PairType>());
327 static void* convertible(PyObject* obj_ptr)
329 if (!PyTuple_Check(obj_ptr) || PyTuple_Size(obj_ptr) != 2) {
332 boost::python::extract<first_type> e1(PyTuple_GetItem(obj_ptr, 0));
333 boost::python::extract<second_type> e2(PyTuple_GetItem(obj_ptr, 1));
334 if (!e1.check() || !e2.check()) {
340 static void construct(
342 boost::python::converter::rvalue_from_python_stage1_data* data)
345 (boost::python::converter::rvalue_from_python_storage<PairType>*)
346 data)->storage.bytes;
347 boost::python::extract<first_type> e1(PyTuple_GetItem(obj_ptr, 0));
348 boost::python::extract<second_type> e2(PyTuple_GetItem(obj_ptr, 1));
349 new (storage) PairType(e1(), e2());
350 data->convertible = storage;
354 template <
typename ContainerType>
355 struct to_tuple_mapping
358 boost::python::to_python_converter<
360 to_tuple<ContainerType> >();
364 template <
typename ContainerType,
typename ConversionPolicy>
365 struct tuple_mapping : to_tuple_mapping<ContainerType>
368 from_python_sequence<
374 template <
typename ContainerType>
375 struct tuple_mapping_fixed_size
377 tuple_mapping_fixed_size() {
380 fixed_size_policy>();
384 template <
typename ContainerType>
385 struct tuple_mapping_fixed_capacity
387 tuple_mapping_fixed_capacity() {
390 fixed_capacity_policy>();
394 template <
typename ContainerType>
395 struct tuple_mapping_variable_capacity
397 tuple_mapping_variable_capacity() {
400 variable_capacity_policy>();
404 template <
typename ContainerType>
405 struct tuple_mapping_set
407 tuple_mapping_set() {
414 template <
typename ContainerType>
415 struct tuple_mapping_pair
417 tuple_mapping_pair() {
418 boost::python::to_python_converter<
420 to_tuple<ContainerType> >();
421 from_python_tuple_pair<ContainerType>();
428 void TfPyRegisterStlSequencesFromPython()
430 using namespace TfPyContainerConversions;
431 from_python_sequence<
432 std::vector<T>, variable_capacity_all_items_convertible_policy>();
433 from_python_sequence<
434 std::list<T>, variable_capacity_all_items_convertible_policy>();
435 from_python_sequence<
436 std::deque<T>, variable_capacity_all_items_convertible_policy>();
439 PXR_NAMESPACE_CLOSE_SCOPE
441 #endif // PXR_BASE_TF_PY_CONTAINER_CONVERSIONS_H
A simple iterator adapter for STL containers.
Low-level utilities for informing users of various internal and external diagnostic conditions...
Miscellaneous Utilities for dealing with script.
Pointer storage with deletion detection.
#define TF_FOR_ALL(iter, c)
Macro for iterating over a container.
#define TF_AXIOM(cond)
Aborts if the condition cond is not met.
boost::python::dict TfPyCopyMapToDictionary(Map const &map)
Creates a python dictionary from a std::map.