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"
39#include "pxr/base/gf/traits.h"
41#include "pxr/base/tf/pyFunction.h"
42#include "pxr/base/tf/pyLock.h"
43#include "pxr/base/tf/pyObjWrapper.h"
44#include "pxr/base/tf/pyResultConversions.h"
47#include "pxr/base/tf/meta.h"
51#include "pxr/base/tf/wrapTypeHelpers.h"
53#include <boost/preprocessor/punctuation/comma_if.hpp>
54#include <boost/preprocessor/repetition/repeat.hpp>
55#include <boost/preprocessor/seq/for_each.hpp>
57#include <boost/python/class.hpp>
58#include <boost/python/copy_const_reference.hpp>
59#include <boost/python/def.hpp>
60#include <boost/python/detail/api_placeholder.hpp>
61#include <boost/python/extract.hpp>
62#include <boost/python/implicit.hpp>
63#include <boost/python/iterator.hpp>
64#include <boost/python/make_constructor.hpp>
65#include <boost/python/object.hpp>
66#include <boost/python/operators.hpp>
67#include <boost/python/return_arg.hpp>
68#include <boost/python/slice.hpp>
69#include <boost/python/type_id.hpp>
70#include <boost/python/overloads.hpp>
79PXR_NAMESPACE_OPEN_SCOPE
81namespace Vt_WrapArray {
83using namespace boost::python;
91getitem_ellipsis(
VtArray<T> const &self,
object idx)
93 object ellipsis = object(handle<>(borrowed(Py_Ellipsis)));
94 if (idx != ellipsis) {
95 PyErr_SetString(PyExc_TypeError,
"unsupported index type");
96 throw_error_already_set();
103getitem_index(
VtArray<T> const &self, int64_t idx)
105 static const bool throwError =
true;
107 return object(self[idx]);
112getitem_slice(
VtArray<T> const &self, slice idx)
115 slice::range<typename VtArray<T>::const_iterator> range =
116 idx.get_indices(self.
begin(), self.
end());
117 const size_t setSize = 1 + (range.stop - range.start) / range.step;
120 for (; range.start != range.stop; range.start += range.step, ++i) {
121 result[i] = *range.start;
123 result[i] = *range.start;
124 return object(result);
126 catch (std::invalid_argument
const &) {
131template <
typename T,
typename S>
134 slice::range<T*>& range,
size_t setSize,
bool tile =
false)
137 const size_t length = len(value);
140 if (!tile && length < setSize) {
142 (
"Not enough values to set slice. Expected %zu, got %zu.",
149 std::vector<T> extracted;
150 extract<std::vector<T> > vectorExtraction(value);
151 if (vectorExtraction.check()) {
152 std::vector<T> tmp = vectorExtraction();
156 extracted.reserve(length);
157 for (
size_t i = 0; i != length; ++i) {
158 extracted.push_back(extract<T>(value[i]));
164 if (range.step == 1 && length >= setSize) {
165 std::copy(extracted.begin(), extracted.begin() + setSize, range.start);
168 for (
size_t i = 0; i != setSize; range.start += range.step, ++i) {
169 *range.start = extracted[i % length];
176setArraySlice(
VtArray<T> &self, slice idx,
object value,
bool tile =
false)
179 slice::range<T*> range;
181 T* data = self.
data();
182 range = idx.get_indices(data, data + self.
size());
184 catch (std::invalid_argument
const &) {
190 const size_t setSize = 1 + (range.stop - range.start) / range.step;
198 const VtArray<T> val = extract< VtArray<T> >(value);
199 const size_t length = val.
size();
202 if (!tile && length < setSize) {
204 (
"Not enough values to set slice. Expected %zu, got %zu.",
210 for (
size_t i = 0; i != setSize; range.start += range.step, ++i) {
211 *range.start = val[i % length];
216 else if (extract<T>(value).check()) {
223 const T val = extract<T>(value);
224 for (
size_t i = 0; i != setSize; range.start += range.step, ++i) {
230 else if (extract<list>(value).check()) {
231 setArraySlice(self, extract<list>(value)(), range, setSize, tile);
235 else if (extract<tuple>(value).check()) {
236 setArraySlice(self, extract<tuple>(value)(), range, setSize, tile);
241 setArraySlice(self, list(value), range, setSize, tile);
248setitem_ellipsis(
VtArray<T> &self,
object idx,
object value)
250 object ellipsis = object(handle<>(borrowed(Py_Ellipsis)));
251 if (idx != ellipsis) {
252 PyErr_SetString(PyExc_TypeError,
"unsupported index type");
253 throw_error_already_set();
255 setArraySlice(self, slice(0, self.
size()), value);
260setitem_index(
VtArray<T> &self, int64_t idx,
object value)
263 setArraySlice(self, slice(idx, idx+1), value,
true);
268setitem_slice(
VtArray<T> &self, slice idx,
object value)
270 setArraySlice(self, idx, value);
275VT_API
string GetVtArrayName();
277template <
class T,
class... Ts>
278constexpr bool Vt_IsAnySameImpl(TfMetaList<Ts...>) {
279 return (std::is_same_v<T, Ts> || ...);
282template <
class T,
class TypeList>
283constexpr bool Vt_IsAnySame() {
284 return Vt_IsAnySameImpl<T>(TypeList{});
289using Vt_OptimizedStreamIntegralTypes =
290 TfMetaList<short,
unsigned short,
293 long long,
unsigned long long>;
300inline bool _IsFinite(T
const &value) {
301 return std::isfinite(value);
303inline bool _IsFinite(
GfHalf const &value) {
304 return std::isfinite(
static_cast<float>(value));
308static void streamValue(std::ostringstream &stream, T
const &value) {
311 if constexpr(Vt_IsAnySame<T, Vt_OptimizedStreamIntegralTypes>()) {
316 if (_IsFinite(value)) {
329Vt_ComputeEffectiveRankAndLastDimSize(
330 Vt_ShapeData
const *sd,
size_t *lastDimSize)
332 unsigned int rank = sd->GetRank();
336 size_t divisor = std::accumulate(
337 sd->otherDims, sd->otherDims + rank-1,
338 1, [](
size_t x,
size_t y) { return x * y; });
340 size_t remainder = divisor ? sd->totalSize % divisor : 0;
341 *lastDimSize = divisor ? sd->totalSize / divisor : 0;
356 std::ostringstream stream;
357 stream.precision(17);
359 for (
size_t i = 0; i < self.
size(); ++i) {
360 stream << (i ?
", " :
"");
361 streamValue(stream, self[i]);
363 stream << (self.
size() == 1 ?
",)" :
")");
368 self.
size(), stream.str().c_str());
377 Vt_ShapeData
const *shapeData = self._GetShapeData();
378 size_t lastDimSize = 0;
380 Vt_ComputeEffectiveRankAndLastDimSize(shapeData, &lastDimSize);
382 std::string shapeStr =
"(";
383 for (
size_t i = 0; i != rank-1; ++i) {
385 i ?
", %d" :
"%d", shapeData->otherDims[i]);
389 repr.c_str(), shapeStr.c_str());
396VtArray<T> *VtArray__init__(
object const &values)
399 unique_ptr<VtArray<T> > ret(
new VtArray<T>(len(values)));
403 static const bool tile =
true;
404 setArraySlice(*ret, slice(0, ret->size()), values, tile);
405 return ret.release();
408VtArray<T> *VtArray__init__2(
size_t size,
object const &values)
411 unique_ptr<VtArray<T> > ret(
new VtArray<T>(size));
415 static const bool tile =
true;
416 setArraySlice(*ret, slice(0, ret->size()), values, tile);
418 return ret.release();
424ARCH_PRAGMA_UNSAFE_USE_OF_BOOL
425ARCH_PRAGMA_UNARY_MINUS_ON_UNSIGNED
427VTOPERATOR_WRAP(__add__,__radd__)
428VTOPERATOR_WRAP_NONCOMM(__sub__,__rsub__)
429VTOPERATOR_WRAP(__mul__,__rmul__)
430VTOPERATOR_WRAP_NONCOMM(__div__,__rdiv__)
431VTOPERATOR_WRAP_NONCOMM(__mod__,__rmod__)
433VTOPERATOR_WRAP_BOOL(Equal,==)
434VTOPERATOR_WRAP_BOOL(NotEqual,!=)
435VTOPERATOR_WRAP_BOOL(Greater,>)
436VTOPERATOR_WRAP_BOOL(Less,<)
437VTOPERATOR_WRAP_BOOL(GreaterOrEqual,>=)
438VTOPERATOR_WRAP_BOOL(LessOrEqual,<=)
443static
std::
string _VtStr(T const &self)
451 using namespace Vt_WrapArray;
454 typedef typename This::ElementType Type;
456 string name = GetVtArrayName<This>();
458 string docStr =
TfStringPrintf(
"An array of type %s.", typeStr.c_str());
460 auto selfCls = class_<This>(name.c_str(), docStr.c_str(), no_init)
461 .setattr(
"_isVtArray",
true)
464 .def(
"__init__", make_constructor(VtArray__init__<Type>),
466 "__init__(values)\n\n"
467 "values: a sequence (tuple, list, or another VtArray with "
468 "element type convertible to the new array's element type)\n\n"
470 .def(
"__init__", make_constructor(VtArray__init__2<Type>))
471 .def(init<unsigned int>())
473 .def(
"__getitem__", getitem_ellipsis<Type>)
474 .def(
"__getitem__", getitem_slice<Type>)
475 .def(
"__getitem__", getitem_index<Type>)
476 .def(
"__setitem__", setitem_ellipsis<Type>)
477 .def(
"__setitem__", setitem_slice<Type>)
478 .def(
"__setitem__", setitem_index<Type>)
480 .def(
"__len__", &This::size)
481 .def(
"__iter__", iterator<This>())
483 .def(
"__repr__", __repr__<Type>)
486 .def(
"__str__", _VtStr<T>)
490#ifdef NUMERIC_OPERATORS
491#define ADDITION_OPERATOR
492#define SUBTRACTION_OPERATOR
493#define MULTIPLICATION_OPERATOR
494#define DIVISION_OPERATOR
495#define UNARY_NEG_OPERATOR
498#ifdef ADDITION_OPERATOR
499 VTOPERATOR_WRAPDECLARE(+,__add__,__radd__)
501#ifdef SUBTRACTION_OPERATOR
502 VTOPERATOR_WRAPDECLARE(-,__sub__,__rsub__)
504#ifdef MULTIPLICATION_OPERATOR
505 VTOPERATOR_WRAPDECLARE(*,__mul__,__rmul__)
507#ifdef DIVISION_OPERATOR
508 VTOPERATOR_WRAPDECLARE(/,__div__,__rdiv__)
511 VTOPERATOR_WRAPDECLARE(%,__mod__,__rmod__)
513#ifdef DOUBLE_MULT_OPERATOR
514 .def(self *
double())
515 .def(
double() * self)
517#ifdef DOUBLE_DIV_OPERATOR
518 .def(self /
double())
520#ifdef UNARY_NEG_OPERATOR
526#define WRITE(z, n, data) BOOST_PP_COMMA_IF(n) data
527#define VtCat_DEF(z, n, unused) \
528 def("Cat",(VtArray<Type> (*)( BOOST_PP_REPEAT(n, WRITE, VtArray<Type> const &) ))VtCat<Type>);
529 BOOST_PP_REPEAT_FROM_TO(1, VT_FUNCTIONS_MAX_ARGS, VtCat_DEF, ~)
532 VTOPERATOR_WRAPDECLARE_BOOL(Equal)
533 VTOPERATOR_WRAPDECLARE_BOOL(NotEqual)
536 TfPyContainerConversions::from_python_sequence<
538 TfPyContainerConversions::
539 variable_capacity_all_items_convertible_policy>();
542 implicitly_convertible<This, TfSpan<Type> >();
543 implicitly_convertible<This, TfSpan<const Type> >();
548void VtWrapComparisonFunctions()
550 using namespace Vt_WrapArray;
553 typedef typename This::ElementType Type;
555 def(
"AnyTrue", VtAnyTrue<Type>);
556 def(
"AllTrue", VtAllTrue<Type>);
558 VTOPERATOR_WRAPDECLARE_BOOL(Greater)
559 VTOPERATOR_WRAPDECLARE_BOOL(Less)
560 VTOPERATOR_WRAPDECLARE_BOOL(GreaterOrEqual)
561 VTOPERATOR_WRAPDECLARE_BOOL(LessOrEqual)
564template <
class Array>
568 typedef typename Array::ElementType ElemType;
570 if (PySequence_Check(obj.
ptr())) {
571 Py_ssize_t len = PySequence_Length(obj.
ptr());
573 ElemType *elem = result.data();
574 for (Py_ssize_t i = 0; i != len; ++i) {
575 boost::python::handle<> h(PySequence_ITEM(obj.
ptr(), i));
577 if (PyErr_Occurred())
581 boost::python::extract<ElemType> e(h.get());
587 }
else if (PyIter_Check(obj.
ptr())) {
589 while (PyObject *item = PyIter_Next(obj.
ptr())) {
590 boost::python::handle<> h(item);
592 if (PyErr_Occurred())
596 boost::python::extract<ElemType> e(h.get());
599 result.push_back(e());
606template <
class Array,
class Iter>
608Vt_ConvertFromRange(Iter begin, Iter end)
610 typedef typename Array::ElementType ElemType;
611 Array result(distance(begin, end));
612 for (ElemType *e = result.data(); begin != end; ++begin) {
613 VtValue cast = VtValue::Cast<ElemType>(*begin);
623Vt_CastToArray(
VtValue const &v) {
629 }
else if (v.
IsHolding<std::vector<VtValue> >()) {
630 std::vector<VtValue>
const &vec = v.
UncheckedGet<std::vector<VtValue> >();
631 ret = Vt_ConvertFromRange<T>(vec.begin(), vec.end());
638void VtRegisterValueCastsFromPythonSequencesToArray()
641 VtValue::RegisterCast<TfPyObjWrapper, Array>(Vt_CastToArray<Array>);
642 VtValue::RegisterCast<std::vector<VtValue>, Array>(Vt_CastToArray<Array>);
645#define VT_WRAP_ARRAY(r, unused, elem) \
646 VtWrapArray< VtArray< VT_TYPE(elem) > >();
647#define VT_WRAP_COMPARISON(r, unused, elem) \
648 VtWrapComparisonFunctions< VtArray< VT_TYPE(elem) > >();
650PXR_NAMESPACE_CLOSE_SCOPE
Architecture-specific math function calls.
A simple iterator adapter for STL containers.
Miscellaneous Utilities for dealing with script.
#define TF_PY_REPR_PREFIX
A macro which expands to the proper repr prefix for a library.
TF_API void TfPyThrowValueError(const char *msg)
Raises a Python ValueError with the given error msg and throws a boost::python::error_already_set exc...
TF_API int64_t TfPyNormalizeIndex(int64_t index, uint64_t size, bool throwError=false)
Return a positive index in the range [0,size).
std::string TfPyRepr(T const &t)
Return repr(t).
Defines all the types "TYPED" for which Vt creates a VtTYPEDArray typedef.
Convenience class for accessing the Python Global Interpreter Lock.
Boost Python object wrapper.
TF_API PyObject * ptr() const
Underlying PyObject* access.
Represents an arbitrary dimensional rectangular container class.
Provides a container which may hold any type, and provides introspection and iteration over array typ...
bool IsEmpty() const
Returns true iff this value is empty.
VtValue & Swap(VtValue &rhs) noexcept
Swap this with rhs.
bool IsHolding() const
Return true if this value is holding an object of type T, false otherwise.
T const & UncheckedGet() const &
Returns a const reference to the held object if the held object is of type T.
size_t size() const
Return the total number of elements in this array.
pointer data()
Return a non-const pointer to this array's data.
bool empty() const
Return true if this array contains no elements, false otherwise.
iterator end()
Returns a non-const iterator to the end of the array.
iterator begin()
Return a non-const iterator to the start of the array.
std::string ArchGetDemangled()
Return demangled RTTI generated-type name.
std::string TfStringify(const T &v)
Convert an arbitrary type into a string.
TF_API std::string TfStringPrintf(const char *fmt,...)
Returns a string formed by a printf()-like specification.
This header serves to simply bring in the half float datatype and provide a hash_value function.
pxr_half::half GfHalf
A 16-bit floating point data type.
Pragmas for controlling compiler-specific behaviors.
Utilities for providing C++ <-> Python container support.
Definitions of basic string utilities in tf.
A metafunction which is equivalent to std::is_floating_point but allows for additional specialization...
A boost.python visitor that associates the Python class object created by the wrapping with the TfTyp...
A file containing basic constants and definitions.