24 #ifndef PXR_BASE_VT_WRAP_ARRAY_H 25 #define PXR_BASE_VT_WRAP_ARRAY_H 28 #include "pxr/base/vt/api.h" 31 #include "pxr/base/vt/value.h" 32 #include "pxr/base/vt/pyOperators.h" 40 #include "pxr/base/tf/pyFunction.h" 41 #include "pxr/base/tf/pyLock.h" 42 #include "pxr/base/tf/pyObjWrapper.h" 43 #include "pxr/base/tf/pyResultConversions.h" 49 #include "pxr/base/tf/wrapTypeHelpers.h" 51 #include <boost/preprocessor/facilities/empty.hpp> 52 #include <boost/preprocessor/punctuation/comma_if.hpp> 53 #include <boost/preprocessor/repetition/repeat.hpp> 54 #include <boost/preprocessor/seq/for_each.hpp> 56 #include <boost/python/class.hpp> 57 #include <boost/python/copy_const_reference.hpp> 58 #include <boost/python/def.hpp> 59 #include <boost/python/detail/api_placeholder.hpp> 60 #include <boost/python/extract.hpp> 61 #include <boost/python/implicit.hpp> 62 #include <boost/python/iterator.hpp> 63 #include <boost/python/make_constructor.hpp> 64 #include <boost/python/object.hpp> 65 #include <boost/python/operators.hpp> 66 #include <boost/python/return_arg.hpp> 67 #include <boost/python/slice.hpp> 68 #include <boost/python/type_id.hpp> 69 #include <boost/python/overloads.hpp> 78 PXR_NAMESPACE_OPEN_SCOPE
80 namespace Vt_WrapArray {
82 using namespace boost::python;
84 using std::unique_ptr;
90 getitem_ellipsis(
VtArray<T> const &
self,
object idx)
92 object ellipsis = object(handle<>(borrowed(Py_Ellipsis)));
93 if (idx != ellipsis) {
94 PyErr_SetString(PyExc_TypeError,
"unsupported index type");
95 throw_error_already_set();
100 template <
typename T>
102 getitem_index(
VtArray<T> const &
self, int64_t idx)
104 static const bool throwError =
true;
106 return object(
self[idx]);
109 template <
typename T>
111 getitem_slice(
VtArray<T> const &
self, slice idx)
114 slice::range<typename VtArray<T>::const_iterator> range =
115 idx.get_indices(
self.begin(),
self.end());
116 const size_t setSize = 1 + (range.stop - range.start) / range.step;
119 for (; range.start != range.stop; range.start += range.step, ++i) {
120 result[i] = *range.start;
122 result[i] = *range.start;
123 return object(result);
125 catch (std::invalid_argument
const &) {
130 template <
typename T,
typename S>
133 slice::range<T*>& range,
size_t setSize,
bool tile =
false)
136 const size_t length = len(value);
139 if (!tile && length < setSize) {
141 (
"Not enough values to set slice. Expected %zu, got %zu.",
148 std::vector<T> extracted;
149 extract<std::vector<T> > vectorExtraction(value);
150 if (vectorExtraction.check()) {
151 std::vector<T> tmp = vectorExtraction();
155 extracted.reserve(length);
156 for (
size_t i = 0; i != length; ++i) {
157 extracted.push_back(extract<T>(value[i]));
163 if (range.step == 1 && length >= setSize) {
164 std::copy(extracted.begin(), extracted.begin() + setSize, range.start);
167 for (
size_t i = 0; i != setSize; range.start += range.step, ++i) {
168 *range.start = extracted[i % length];
173 template <
typename T>
175 setArraySlice(
VtArray<T> &
self, slice idx,
object value,
bool tile =
false)
178 slice::range<T*> range;
180 T* data =
self.data();
181 range = idx.get_indices(data, data +
self.size());
183 catch (std::invalid_argument
const &) {
189 const size_t setSize = 1 + (range.stop - range.start) / range.step;
197 const VtArray<T> val = extract< VtArray<T> >(value);
198 const size_t length = val.
size();
201 if (!tile && length < setSize) {
203 (
"Not enough values to set slice. Expected %zu, got %zu.",
209 for (
size_t i = 0; i != setSize; range.start += range.step, ++i) {
210 *range.start = val[i % length];
215 else if (extract<T>(value).check()) {
222 const T val = extract<T>(value);
223 for (
size_t i = 0; i != setSize; range.start += range.step, ++i) {
229 else if (extract<list>(value).check()) {
230 setArraySlice(
self, extract<list>(value)(), range, setSize, tile);
234 else if (extract<tuple>(value).check()) {
235 setArraySlice(
self, extract<tuple>(value)(), range, setSize, tile);
240 setArraySlice(
self, list(value), range, setSize, tile);
245 template <
typename T>
247 setitem_ellipsis(
VtArray<T> &
self,
object idx,
object value)
249 object ellipsis = object(handle<>(borrowed(Py_Ellipsis)));
250 if (idx != ellipsis) {
251 PyErr_SetString(PyExc_TypeError,
"unsupported index type");
252 throw_error_already_set();
254 setArraySlice(
self, slice(0,
self.size()), value);
257 template <
typename T>
259 setitem_index(
VtArray<T> &
self, int64_t idx,
object value)
261 static const bool tile =
true;
262 setArraySlice(
self, slice(idx, idx + 1), value, tile);
265 template <
typename T>
267 setitem_slice(
VtArray<T> &
self, slice idx,
object value)
269 setArraySlice(
self, idx, value);
274 VT_API
string GetVtArrayName();
279 template <
typename T>
280 static void streamValue(std::ostringstream &stream, T
const &value) {
286 #define _OPTIMIZED_STREAM_INTEGRAL_TYPES \ 296 #define MAKE_STREAM_FUNC(r, unused, type) \ 298 streamValue(std::ostringstream &stream, type const &value) { \ 301 BOOST_PP_SEQ_FOR_EACH(MAKE_STREAM_FUNC, ~, _OPTIMIZED_STREAM_INTEGRAL_TYPES)
302 #undef MAKE_STREAM_FUNC 303 #undef _OPTIMIZED_STREAM_INTEGRAL_TYPES 309 template <
typename T>
310 static bool _IsFinite(T
const &value) {
311 return std::isfinite(value);
313 static bool _IsFinite(
GfHalf const &value) {
314 return std::isfinite(static_cast<float>(value));
318 #define MAKE_STREAM_FUNC(r, unused, elem) \ 320 streamValue(std::ostringstream &stream, VT_TYPE(elem) const &value) { \ 321 if (_IsFinite(value)) { \ 324 stream << TfPyRepr(value); \ 327 BOOST_PP_SEQ_FOR_EACH(
328 MAKE_STREAM_FUNC, ~, VT_FLOATING_POINT_BUILTIN_VALUE_TYPES)
329 #undef MAKE_STREAM_FUNC 332 Vt_ComputeEffectiveRankAndLastDimSize(
333 Vt_ShapeData
const *sd,
size_t *lastDimSize)
335 unsigned int rank = sd->GetRank();
339 size_t divisor = std::accumulate(
340 sd->otherDims, sd->otherDims + rank-1,
341 1, [](
size_t x,
size_t y) { return x * y; });
343 size_t remainder = divisor ? sd->totalSize % divisor : 0;
344 *lastDimSize = divisor ? sd->totalSize / divisor : 0;
352 template <
typename T>
359 std::ostringstream stream;
360 stream.precision(17);
362 for (
size_t i = 0; i <
self.size(); ++i) {
363 stream << (i ?
", " :
"");
364 streamValue(stream,
self[i]);
366 stream << (
self.size() == 1 ?
",)" :
")");
371 self.size(), stream.str().c_str());
380 Vt_ShapeData
const *shapeData =
self._GetShapeData();
381 size_t lastDimSize = 0;
383 Vt_ComputeEffectiveRankAndLastDimSize(shapeData, &lastDimSize);
385 std::string shapeStr =
"(";
386 for (
size_t i = 0; i != rank-1; ++i) {
388 i ?
", %d" :
"%d", shapeData->otherDims[i]);
392 repr.c_str(), shapeStr.c_str());
398 template <
typename T>
399 VtArray<T> *VtArray__init__(
object const &values)
402 unique_ptr<VtArray<T> > ret(
new VtArray<T>(len(values)));
406 static const bool tile =
true;
407 setArraySlice(*ret, slice(0, ret->size()), values, tile);
408 return ret.release();
410 template <
typename T>
411 VtArray<T> *VtArray__init__2(
size_t size,
object const &values)
414 unique_ptr<VtArray<T> > ret(
new VtArray<T>(size));
418 static const bool tile =
true;
419 setArraySlice(*ret, slice(0, ret->size()), values, tile);
421 return ret.release();
427 ARCH_PRAGMA_UNSAFE_USE_OF_BOOL
428 ARCH_PRAGMA_UNARY_MINUS_ON_UNSIGNED
429 VTOPERATOR_WRAP(+,__add__,__radd__)
430 VTOPERATOR_WRAP_NONCOMM(-,__sub__,__rsub__)
431 VTOPERATOR_WRAP(*,__mul__,__rmul__)
432 VTOPERATOR_WRAP_NONCOMM(/,__div__,__rdiv__)
433 VTOPERATOR_WRAP_NONCOMM(%,__mod__,__rmod__)
435 VTOPERATOR_WRAP_BOOL(Equal,==)
436 VTOPERATOR_WRAP_BOOL(NotEqual,!=)
437 VTOPERATOR_WRAP_BOOL(Greater,>)
438 VTOPERATOR_WRAP_BOOL(Less,<)
439 VTOPERATOR_WRAP_BOOL(GreaterOrEqual,>=)
440 VTOPERATOR_WRAP_BOOL(LessOrEqual,<=)
444 template <typename T>
445 static std::
string _VtStr(T const &self)
447 return boost::lexical_cast<std::string>(
self);
450 template <
typename T>
453 using namespace Vt_WrapArray;
456 typedef typename This::ElementType Type;
458 string name = GetVtArrayName<This>();
460 string docStr =
TfStringPrintf(
"An array of type %s.", typeStr.c_str());
462 auto selfCls = class_<This>(name.c_str(), docStr.c_str(), no_init)
463 .setattr(
"_isVtArray",
true)
466 .def(
"__init__", make_constructor(VtArray__init__<Type>),
468 "__init__(values)\n\n" 469 "values: a sequence (tuple, list, or another VtArray with " 470 "element type convertible to the new array's element type)\n\n" 472 .def(
"__init__", make_constructor(VtArray__init__2<Type>))
473 .def(init<unsigned int>())
475 .def(
"__getitem__", getitem_ellipsis<Type>)
476 .def(
"__getitem__", getitem_slice<Type>)
477 .def(
"__getitem__", getitem_index<Type>)
478 .def(
"__setitem__", setitem_ellipsis<Type>)
479 .def(
"__setitem__", setitem_slice<Type>)
480 .def(
"__setitem__", setitem_index<Type>)
482 .def(
"__len__", &This::size)
483 .def(
"__iter__", iterator<This>())
485 .def(
"__repr__", __repr__<Type>)
488 .def(
"__str__", _VtStr<T>)
492 #ifdef NUMERIC_OPERATORS 493 #define ADDITION_OPERATOR 494 #define SUBTRACTION_OPERATOR 495 #define MULTIPLICATION_OPERATOR 496 #define DIVISION_OPERATOR 497 #define UNARY_NEG_OPERATOR 500 #ifdef ADDITION_OPERATOR 501 VTOPERATOR_WRAPDECLARE(+,__add__,__radd__)
503 #ifdef SUBTRACTION_OPERATOR 504 VTOPERATOR_WRAPDECLARE(-,__sub__,__rsub__)
506 #ifdef MULTIPLICATION_OPERATOR 507 VTOPERATOR_WRAPDECLARE(*,__mul__,__rmul__)
509 #ifdef DIVISION_OPERATOR 510 VTOPERATOR_WRAPDECLARE(/,__div__,__rdiv__)
513 VTOPERATOR_WRAPDECLARE(%,__mod__,__rmod__)
515 #ifdef DOUBLE_MULT_OPERATOR 516 .def(
self *
double())
517 .def(
double() *
self)
519 #ifdef DOUBLE_DIV_OPERATOR 520 .def(
self /
double())
522 #ifdef UNARY_NEG_OPERATOR 528 #if PY_MAJOR_VERSION == 2 532 if (PyObject_HasAttrString(selfCls.ptr(),
"__div__")) {
533 selfCls.attr(
"__truediv__") = selfCls.attr(
"__div__");
536 if (PyObject_HasAttrString(selfCls.ptr(),
"__rdiv__")) {
537 selfCls.attr(
"__rtruediv__") = selfCls.attr(
"__rdiv__");
541 #define WRITE(z, n, data) BOOST_PP_COMMA_IF(n) data 542 #define VtCat_DEF(z, n, unused) \ 543 def("Cat",(VtArray<Type> (*)( BOOST_PP_REPEAT(n, WRITE, VtArray<Type> const &) ))VtCat<Type>); 544 BOOST_PP_REPEAT_FROM_TO(1, VT_FUNCTIONS_MAX_ARGS, VtCat_DEF, ~)
547 VTOPERATOR_WRAPDECLARE_BOOL(Equal)
548 VTOPERATOR_WRAPDECLARE_BOOL(NotEqual)
551 TfPyContainerConversions::from_python_sequence<
553 TfPyContainerConversions::
554 variable_capacity_all_items_convertible_policy>();
557 implicitly_convertible<This, TfSpan<Type> >();
558 implicitly_convertible<This, TfSpan<const Type> >();
562 template <
typename T>
563 void VtWrapComparisonFunctions()
565 using namespace Vt_WrapArray;
568 typedef typename This::ElementType Type;
570 def(
"AnyTrue", VtAnyTrue<Type>);
571 def(
"AllTrue", VtAllTrue<Type>);
573 VTOPERATOR_WRAPDECLARE_BOOL(Greater)
574 VTOPERATOR_WRAPDECLARE_BOOL(Less)
575 VTOPERATOR_WRAPDECLARE_BOOL(GreaterOrEqual)
576 VTOPERATOR_WRAPDECLARE_BOOL(LessOrEqual)
579 template <
class Array>
583 typedef typename Array::ElementType ElemType;
585 if (PySequence_Check(obj.
ptr())) {
586 Py_ssize_t len = PySequence_Length(obj.
ptr());
588 ElemType *elem = result.data();
589 for (Py_ssize_t i = 0; i != len; ++i) {
590 boost::python::handle<> h(PySequence_ITEM(obj.
ptr(), i));
592 if (PyErr_Occurred())
596 boost::python::extract<ElemType> e(h.get());
602 }
else if (PyIter_Check(obj.
ptr())) {
604 while (PyObject *item = PyIter_Next(obj.
ptr())) {
605 boost::python::handle<> h(item);
607 if (PyErr_Occurred())
611 boost::python::extract<ElemType> e(h.get());
614 result.push_back(e());
621 template <
class Array,
class Iter>
623 Vt_ConvertFromRange(Iter begin, Iter end)
625 typedef typename Array::ElementType ElemType;
626 Array result(distance(begin, end));
627 for (ElemType *e = result.data(); begin != end; ++begin) {
628 VtValue cast = VtValue::Cast<ElemType>(*begin);
638 Vt_CastToArray(
VtValue const &v) {
644 }
else if (v.
IsHolding<std::vector<VtValue> >()) {
645 std::vector<VtValue>
const &vec = v.
UncheckedGet<std::vector<VtValue> >();
646 ret = Vt_ConvertFromRange<T>(vec.begin(), vec.end());
652 template <
class Elem>
653 void VtRegisterValueCastsFromPythonSequencesToArray()
656 VtValue::RegisterCast<TfPyObjWrapper, Array>(Vt_CastToArray<Array>);
657 VtValue::RegisterCast<std::vector<VtValue>, Array>(Vt_CastToArray<Array>);
660 #define VT_WRAP_ARRAY(r, unused, elem) \ 661 VtWrapArray< VtArray< VT_TYPE(elem) > >(); 662 #define VT_WRAP_COMPARISON(r, unused, elem) \ 663 VtWrapComparisonFunctions< VtArray< VT_TYPE(elem) > >(); 665 PXR_NAMESPACE_CLOSE_SCOPE
667 #endif // PXR_BASE_VT_WRAP_ARRAY_H TF_API std::string TfStringPrintf(const char *fmt,...)
Returns a string formed by a printf()-like specification.
Pragmas for controlling compiler-specific behaviors.
Architecture-specific math function calls.
A simple iterator adapter for STL containers.
T const & UncheckedGet() const &
Returns a const reference to the held object if the held object is of type T.
pxr_half::half GfHalf
A 16-bit floating point data type.
This header serves to simply bring in the half float datatype and provide a hash_value function.
TF_API PyObject * ptr() const
Underlying PyObject* access.
size_t size() const
Return the total number of elements in this array.
A boost.python visitor that associates the Python class object created by the wrapping with the TfTyp...
ARCH_API std::string ArchGetDemangled(const std::string &typeName)
Return demangled RTTI-generated type name.
TF_API void TfPyThrowValueError(std::string const &msg)
Raises a python ValueError and throws a C++ exception.
Definitions of basic string utilities in tf.
Miscellaneous Utilities for dealing with script.
std::string TfPyRepr(T const &t)
Return repr(t).
Convenience class for accessing the Python Global Interpreter Lock.
bool IsEmpty() const
Returns true iff this value is empty.
Represents an arbitrary dimensional rectangular container class.
Utilities for providing C++ <-> Python container support.
Defines all the types "TYPED" for which Vt creates a VtTYPEDArray typedef.
Boost Python object wrapper.
VtValue & Swap(VtValue &rhs) noexcept
Swap this with rhs.
TF_API int64_t TfPyNormalizeIndex(int64_t index, uint64_t size, bool throwError=false)
Return a positive index in the range [0,size).
#define TF_PY_REPR_PREFIX
A macro which expands to the proper repr prefix for a library.
bool IsHolding() const
Return true if this value is holding an object of type T, false otherwise.
Provides a container which may hold any type, and provides introspection and iteration over array typ...
A file containing basic constants and definitions.