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) {
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) {
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.
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.
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).
bool IsEmpty() const
Returns true iff this value is empty.
T const & UncheckedGet() const
Returns a const reference to the held object if the held object is of type T.
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.