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 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 #define WRITE(z, n, data) BOOST_PP_COMMA_IF(n) data
529 #define VtCat_DEF(z, n, unused) \
530 def("Cat",(VtArray<Type> (*)( BOOST_PP_REPEAT(n, WRITE, VtArray<Type> const &) ))VtCat<Type>);
531 BOOST_PP_REPEAT_FROM_TO(1, VT_FUNCTIONS_MAX_ARGS, VtCat_DEF, ~)
534 VTOPERATOR_WRAPDECLARE_BOOL(Equal)
535 VTOPERATOR_WRAPDECLARE_BOOL(NotEqual)
538 TfPyContainerConversions::from_python_sequence<
540 TfPyContainerConversions::
541 variable_capacity_all_items_convertible_policy>();
544 implicitly_convertible<This,
TfSpan<Type> >();
545 implicitly_convertible<This,
TfSpan<const Type> >();
549 template <typename T>
550 void VtWrapComparisonFunctions()
552 using namespace Vt_WrapArray;
555 typedef typename This::ElementType Type;
557 def(
"AnyTrue", VtAnyTrue<Type>);
558 def(
"AllTrue", VtAllTrue<Type>);
560 VTOPERATOR_WRAPDECLARE_BOOL(Greater)
561 VTOPERATOR_WRAPDECLARE_BOOL(Less)
562 VTOPERATOR_WRAPDECLARE_BOOL(GreaterOrEqual)
563 VTOPERATOR_WRAPDECLARE_BOOL(LessOrEqual)
566 template <class Array>
570 typedef typename Array::ElementType ElemType;
572 if (PySequence_Check(obj.ptr())) {
573 Py_ssize_t len = PySequence_Length(obj.ptr());
575 ElemType *elem = result.data();
576 for (Py_ssize_t i = 0; i != len; ++i) {
577 boost::python::handle<> h(PySequence_ITEM(obj.ptr(), i));
579 if (PyErr_Occurred())
583 boost::python::extract<ElemType> e(h.get());
593 template <
class Array,
class Iter>
595 Vt_ConvertFromRange(Iter begin, Iter end)
597 typedef typename Array::ElementType ElemType;
598 Array result(distance(begin, end));
599 for (ElemType *e = result.data(); begin != end; ++begin) {
600 VtValue cast = VtValue::Cast<ElemType>(*begin);
610 Vt_CastToArray(
VtValue const &v) {
616 }
else if (v.
IsHolding<std::vector<VtValue> >()) {
617 std::vector<VtValue>
const &vec = v.
UncheckedGet<std::vector<VtValue> >();
618 ret = Vt_ConvertFromRange<T>(vec.begin(), vec.end());
624 template <
class Elem>
625 void VtRegisterValueCastsFromPythonSequencesToArray()
628 VtValue::RegisterCast<TfPyObjWrapper, Array>(Vt_CastToArray<Array>);
629 VtValue::RegisterCast<std::vector<VtValue>, Array>(Vt_CastToArray<Array>);
632 #define VT_WRAP_ARRAY(r, unused, elem) \
633 VtWrapArray< VtArray< VT_TYPE(elem) > >();
634 #define VT_WRAP_COMPARISON(r, unused, elem) \
635 VtWrapComparisonFunctions< VtArray< VT_TYPE(elem) > >();
637 PXR_NAMESPACE_CLOSE_SCOPE
639 #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.
T const & UncheckedGet() const
Returns a const reference to the held object if the held object is of type T.
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...
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.
bool IsHolding() const
Return true if this value is holding an object of type T, false otherwise.
Definitions of basic string utilities in tf.
Miscellaneous Utilities for dealing with script.
std::string TfPyRepr(T const &t)
Return repr(t).
Represents a range of contiguous elements.
size_t size() const
Return the total number of elements in this array.
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.
void if(!TfPyIsInitialized())
Invokes wrapFunc to wrap type T if T is not already wrapped.
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 IsEmpty() const
Returns true iff this value is empty.
Provides a container which may hold any type, and provides introspection and iteration over array typ...
A file containing basic constants and definitions.