Loading...
Searching...
No Matches
wrapArray.h
1//
2// Copyright 2016 Pixar
3//
4// Licensed under the Apache License, Version 2.0 (the "Apache License")
5// with the following modification; you may not use this file except in
6// compliance with the Apache License and the following modification to it:
7// Section 6. Trademarks. is deleted and replaced with:
8//
9// 6. Trademarks. This License does not grant permission to use the trade
10// names, trademarks, service marks, or product names of the Licensor
11// and its affiliates, except as required to comply with Section 4(c) of
12// the License and to reproduce the content of the NOTICE file.
13//
14// You may obtain a copy of the Apache License at
15//
16// http://www.apache.org/licenses/LICENSE-2.0
17//
18// Unless required by applicable law or agreed to in writing, software
19// distributed under the Apache License with the above modification is
20// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21// KIND, either express or implied. See the Apache License for the specific
22// language governing permissions and limitations under the Apache License.
23//
24#ifndef PXR_BASE_VT_WRAP_ARRAY_H
25#define PXR_BASE_VT_WRAP_ARRAY_H
26
27#include "pxr/pxr.h"
28#include "pxr/base/vt/api.h"
29#include "pxr/base/vt/array.h"
30#include "pxr/base/vt/types.h"
31#include "pxr/base/vt/value.h"
32#include "pxr/base/vt/pyOperators.h"
34
35#include "pxr/base/arch/math.h"
38#include "pxr/base/gf/half.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"
45#include "pxr/base/tf/pyUtils.h"
47#include "pxr/base/tf/meta.h"
48#include "pxr/base/tf/span.h"
50#include "pxr/base/tf/tf.h"
51#include "pxr/base/tf/wrapTypeHelpers.h"
52
53#include <boost/preprocessor/punctuation/comma_if.hpp>
54#include <boost/preprocessor/repetition/repeat.hpp>
55#include <boost/preprocessor/seq/for_each.hpp>
56
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>
71
72#include <algorithm>
73#include <numeric>
74#include <ostream>
75#include <string>
76#include <memory>
77#include <vector>
78
79PXR_NAMESPACE_OPEN_SCOPE
80
81namespace Vt_WrapArray {
82
83using namespace boost::python;
84
85using std::unique_ptr;
86using std::vector;
87using std::string;
88
89template <typename T>
90object
91getitem_ellipsis(VtArray<T> const &self, object idx)
92{
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();
97 }
98 return object(self);
99}
100
101template <typename T>
102object
103getitem_index(VtArray<T> const &self, int64_t idx)
104{
105 static const bool throwError = true;
106 idx = TfPyNormalizeIndex(idx, self.size(), throwError);
107 return object(self[idx]);
108}
109
110template <typename T>
111object
112getitem_slice(VtArray<T> const &self, slice idx)
113{
114 try {
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;
118 VtArray<T> result(setSize);
119 size_t i = 0;
120 for (; range.start != range.stop; range.start += range.step, ++i) {
121 result[i] = *range.start;
122 }
123 result[i] = *range.start;
124 return object(result);
125 }
126 catch (std::invalid_argument const &) {
127 return object();
128 }
129}
130
131template <typename T, typename S>
132void
133setArraySlice(VtArray<T> &self, S value,
134 slice::range<T*>& range, size_t setSize, bool tile = false)
135{
136 // Check size.
137 const size_t length = len(value);
138 if (length == 0)
139 TfPyThrowValueError("No values with which to set array slice.");
140 if (!tile && length < setSize) {
141 string msg = TfStringPrintf
142 ("Not enough values to set slice. Expected %zu, got %zu.",
143 setSize, length);
145 }
146
147 // Extract the values before setting any. If we can extract the
148 // whole vector at once then do that since it should be faster.
149 std::vector<T> extracted;
150 extract<std::vector<T> > vectorExtraction(value);
151 if (vectorExtraction.check()) {
152 std::vector<T> tmp = vectorExtraction();
153 extracted.swap(tmp);
154 }
155 else {
156 extracted.reserve(length);
157 for (size_t i = 0; i != length; ++i) {
158 extracted.push_back(extract<T>(value[i]));
159 }
160 }
161
162 // We're fine, go through and set them. Handle common case as a fast
163 // path.
164 if (range.step == 1 && length >= setSize) {
165 std::copy(extracted.begin(), extracted.begin() + setSize, range.start);
166 }
167 else {
168 for (size_t i = 0; i != setSize; range.start += range.step, ++i) {
169 *range.start = extracted[i % length];
170 }
171 }
172}
173
174template <typename T>
175void
176setArraySlice(VtArray<T> &self, slice idx, object value, bool tile = false)
177{
178 // Get the range.
179 slice::range<T*> range;
180 try {
181 T* data = self.data();
182 range = idx.get_indices(data, data + self.size());
183 }
184 catch (std::invalid_argument const &) {
185 // Do nothing
186 return;
187 }
188
189 // Get the number of items to be set.
190 const size_t setSize = 1 + (range.stop - range.start) / range.step;
191
192 // Copy from VtArray. We only want to take this path if the passed value is
193 // *exactly* a VtArray. That is, we don't want to take this path if it can
194 // merely *convert* to a VtArray, so we check that we can extract a mutable
195 // lvalue reference from the python object, which requires that there be a
196 // real VtArray there.
197 if (extract< VtArray<T> &>(value).check()) {
198 const VtArray<T> val = extract< VtArray<T> >(value);
199 const size_t length = val.size();
200 if (length == 0)
201 TfPyThrowValueError("No values with which to set array slice.");
202 if (!tile && length < setSize) {
203 string msg = TfStringPrintf
204 ("Not enough values to set slice. Expected %zu, got %zu.",
205 setSize, length);
207 }
208
209 // We're fine, go through and set them.
210 for (size_t i = 0; i != setSize; range.start += range.step, ++i) {
211 *range.start = val[i % length];
212 }
213 }
214
215 // Copy from scalar.
216 else if (extract<T>(value).check()) {
217 if (!tile) {
218 // XXX -- We're allowing implicit tiling; do we want to?
219 //TfPyThrowValueError("can only assign an iterable.");
220 }
221
222 // Use scalar to fill entire slice.
223 const T val = extract<T>(value);
224 for (size_t i = 0; i != setSize; range.start += range.step, ++i) {
225 *range.start = val;
226 }
227 }
228
229 // Copy from list.
230 else if (extract<list>(value).check()) {
231 setArraySlice(self, extract<list>(value)(), range, setSize, tile);
232 }
233
234 // Copy from tuple.
235 else if (extract<tuple>(value).check()) {
236 setArraySlice(self, extract<tuple>(value)(), range, setSize, tile);
237 }
238
239 // Copy from iterable.
240 else {
241 setArraySlice(self, list(value), range, setSize, tile);
242 }
243}
244
245
246template <typename T>
247void
248setitem_ellipsis(VtArray<T> &self, object idx, object value)
249{
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();
254 }
255 setArraySlice(self, slice(0, self.size()), value);
256}
257
258template <typename T>
259void
260setitem_index(VtArray<T> &self, int64_t idx, object value)
261{
262 idx = TfPyNormalizeIndex(idx, self.size(), /*throwError=*/true);
263 setArraySlice(self, slice(idx, idx+1), value, /*tile=*/true);
264}
265
266template <typename T>
267void
268setitem_slice(VtArray<T> &self, slice idx, object value)
269{
270 setArraySlice(self, idx, value);
271}
272
273
274template <class T>
275VT_API string GetVtArrayName();
276
277template <class T, class... Ts>
278constexpr bool Vt_IsAnySameImpl(TfMetaList<Ts...>) {
279 return (std::is_same_v<T, Ts> || ...);
280}
281
282template <class T, class TypeList>
283constexpr bool Vt_IsAnySame() {
284 return Vt_IsAnySameImpl<T>(TypeList{});
285}
286
287// This is the same types as in VT_INTEGRAL_BUILTIN_VALUE_TYPES with char
288// and bool types removed.
289using Vt_OptimizedStreamIntegralTypes =
290 TfMetaList<short, unsigned short,
291 int, unsigned int,
292 long, unsigned long,
293 long long, unsigned long long>;
294
295// Explicitly convert half to float here instead of relying on implicit
296// conversion to float to work around the fact that libc++ only provides
297// implementations of std::isfinite for types where std::is_arithmetic
298// is true.
299template <typename T>
300inline bool _IsFinite(T const &value) {
301 return std::isfinite(value);
302}
303inline bool _IsFinite(GfHalf const &value) {
304 return std::isfinite(static_cast<float>(value));
305}
306
307template <typename T>
308static void streamValue(std::ostringstream &stream, T const &value) {
309 // To avoid overhead we stream out certain builtin types directly
310 // without calling TfPyRepr().
311 if constexpr(Vt_IsAnySame<T, Vt_OptimizedStreamIntegralTypes>()) {
312 stream << value;
313 }
314 // For float types we need to be make sure to represent infs and nans correctly.
315 else if constexpr(GfIsFloatingPoint<T>::value) {
316 if (_IsFinite(value)) {
317 stream << value;
318 }
319 else {
320 stream << TfPyRepr(value);
321 }
322 }
323 else {
324 stream << TfPyRepr(value);
325 }
326}
327
328static unsigned int
329Vt_ComputeEffectiveRankAndLastDimSize(
330 Vt_ShapeData const *sd, size_t *lastDimSize)
331{
332 unsigned int rank = sd->GetRank();
333 if (rank == 1)
334 return rank;
335
336 size_t divisor = std::accumulate(
337 sd->otherDims, sd->otherDims + rank-1,
338 1, [](size_t x, size_t y) { return x * y; });
339
340 size_t remainder = divisor ? sd->totalSize % divisor : 0;
341 *lastDimSize = divisor ? sd->totalSize / divisor : 0;
342
343 if (remainder)
344 rank = 1;
345
346 return rank;
347}
348
349template <typename T>
350string __repr__(VtArray<T> const &self)
351{
352 if (self.empty())
353 return TF_PY_REPR_PREFIX +
354 TfStringPrintf("%s()", GetVtArrayName<VtArray<T> >().c_str());
355
356 std::ostringstream stream;
357 stream.precision(17);
358 stream << "(";
359 for (size_t i = 0; i < self.size(); ++i) {
360 stream << (i ? ", " : "");
361 streamValue(stream, self[i]);
362 }
363 stream << (self.size() == 1 ? ",)" : ")");
364
365 const std::string repr = TF_PY_REPR_PREFIX +
366 TfStringPrintf("%s(%zd, %s)",
367 GetVtArrayName<VtArray<T> >().c_str(),
368 self.size(), stream.str().c_str());
369
370 // XXX: This is to deal with legacy shaped arrays and should be removed
371 // once all shaped arrays have been eliminated.
372 // There is no nice way to make an eval()able __repr__ for shaped arrays
373 // that preserves the shape information, so put it in <> to make it
374 // clearly not eval()able. That has the advantage that, if somebody passes
375 // the repr into eval(), it'll raise a SyntaxError that clearly points to
376 // the beginning of the __repr__.
377 Vt_ShapeData const *shapeData = self._GetShapeData();
378 size_t lastDimSize = 0;
379 unsigned int rank =
380 Vt_ComputeEffectiveRankAndLastDimSize(shapeData, &lastDimSize);
381 if (rank > 1) {
382 std::string shapeStr = "(";
383 for (size_t i = 0; i != rank-1; ++i) {
384 shapeStr += TfStringPrintf(
385 i ? ", %d" : "%d", shapeData->otherDims[i]);
386 }
387 shapeStr += TfStringPrintf(", %zu)", lastDimSize);
388 return TfStringPrintf("<%s with shape %s>",
389 repr.c_str(), shapeStr.c_str());
390 }
391
392 return repr;
393}
394
395template <typename T>
396VtArray<T> *VtArray__init__(object const &values)
397{
398 // Make an array.
399 unique_ptr<VtArray<T> > ret(new VtArray<T>(len(values)));
400
401 // Set the values. This is equivalent to saying 'ret[...] = values'
402 // in python, except that we allow tiling here.
403 static const bool tile = true;
404 setArraySlice(*ret, slice(0, ret->size()), values, tile);
405 return ret.release();
406}
407template <typename T>
408VtArray<T> *VtArray__init__2(size_t size, object const &values)
409{
410 // Make the array.
411 unique_ptr<VtArray<T> > ret(new VtArray<T>(size));
412
413 // Set the values. This is equivalent to saying 'ret[...] = values'
414 // in python, except that we allow tiling here.
415 static const bool tile = true;
416 setArraySlice(*ret, slice(0, ret->size()), values, tile);
417
418 return ret.release();
419}
420
421// overloading for operator special methods, to allow tuple / list & array
422// combinations
423ARCH_PRAGMA_PUSH
424ARCH_PRAGMA_UNSAFE_USE_OF_BOOL
425ARCH_PRAGMA_UNARY_MINUS_ON_UNSIGNED
426
427VTOPERATOR_WRAP(__add__,__radd__)
428VTOPERATOR_WRAP_NONCOMM(__sub__,__rsub__)
429VTOPERATOR_WRAP(__mul__,__rmul__)
430VTOPERATOR_WRAP_NONCOMM(__div__,__rdiv__)
431VTOPERATOR_WRAP_NONCOMM(__mod__,__rmod__)
432
433VTOPERATOR_WRAP_BOOL(Equal,==)
434VTOPERATOR_WRAP_BOOL(NotEqual,!=)
435VTOPERATOR_WRAP_BOOL(Greater,>)
436VTOPERATOR_WRAP_BOOL(Less,<)
437VTOPERATOR_WRAP_BOOL(GreaterOrEqual,>=)
438VTOPERATOR_WRAP_BOOL(LessOrEqual,<=)
439ARCH_PRAGMA_POP
440}
441
442template <typename T>
443static std::string _VtStr(T const &self)
444{
445 return TfStringify(self);
446}
447
448template <typename T>
449void VtWrapArray()
450{
451 using namespace Vt_WrapArray;
452
453 typedef T This;
454 typedef typename This::ElementType Type;
455
456 string name = GetVtArrayName<This>();
457 string typeStr = ArchGetDemangled(typeid(Type));
458 string docStr = TfStringPrintf("An array of type %s.", typeStr.c_str());
459
460 auto selfCls = class_<This>(name.c_str(), docStr.c_str(), no_init)
461 .setattr("_isVtArray", true)
462 .def(TfTypePythonClass())
463 .def(init<>())
464 .def("__init__", make_constructor(VtArray__init__<Type>),
465 (const char *)
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"
469 )
470 .def("__init__", make_constructor(VtArray__init__2<Type>))
471 .def(init<unsigned int>())
472
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>)
479
480 .def("__len__", &This::size)
481 .def("__iter__", iterator<This>())
482
483 .def("__repr__", __repr__<Type>)
484
485// .def(str(self))
486 .def("__str__", _VtStr<T>)
487 .def(self == self)
488 .def(self != self)
489
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
496#endif
497
498#ifdef ADDITION_OPERATOR
499 VTOPERATOR_WRAPDECLARE(+,__add__,__radd__)
500#endif
501#ifdef SUBTRACTION_OPERATOR
502 VTOPERATOR_WRAPDECLARE(-,__sub__,__rsub__)
503#endif
504#ifdef MULTIPLICATION_OPERATOR
505 VTOPERATOR_WRAPDECLARE(*,__mul__,__rmul__)
506#endif
507#ifdef DIVISION_OPERATOR
508 VTOPERATOR_WRAPDECLARE(/,__div__,__rdiv__)
509#endif
510#ifdef MOD_OPERATOR
511 VTOPERATOR_WRAPDECLARE(%,__mod__,__rmod__)
512#endif
513#ifdef DOUBLE_MULT_OPERATOR
514 .def(self * double())
515 .def(double() * self)
516#endif
517#ifdef DOUBLE_DIV_OPERATOR
518 .def(self / double())
519#endif
520#ifdef UNARY_NEG_OPERATOR
521 .def(- self)
522#endif
523
524 ;
525
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, ~)
530#undef VtCat_DEF
531
532 VTOPERATOR_WRAPDECLARE_BOOL(Equal)
533 VTOPERATOR_WRAPDECLARE_BOOL(NotEqual)
534
535 // Wrap conversions from python sequences.
536 TfPyContainerConversions::from_python_sequence<
537 This,
538 TfPyContainerConversions::
539 variable_capacity_all_items_convertible_policy>();
540
541 // Wrap implicit conversions from VtArray to TfSpan.
542 implicitly_convertible<This, TfSpan<Type> >();
543 implicitly_convertible<This, TfSpan<const Type> >();
544}
545
546// wrapping for functions that work for base types that support comparisons
547template <typename T>
548void VtWrapComparisonFunctions()
549{
550 using namespace Vt_WrapArray;
551
552 typedef T This;
553 typedef typename This::ElementType Type;
554
555 def("AnyTrue", VtAnyTrue<Type>);
556 def("AllTrue", VtAllTrue<Type>);
557
558 VTOPERATOR_WRAPDECLARE_BOOL(Greater)
559 VTOPERATOR_WRAPDECLARE_BOOL(Less)
560 VTOPERATOR_WRAPDECLARE_BOOL(GreaterOrEqual)
561 VTOPERATOR_WRAPDECLARE_BOOL(LessOrEqual)
562}
563
564template <class Array>
566Vt_ConvertFromPySequenceOrIter(TfPyObjWrapper const &obj)
567{
568 typedef typename Array::ElementType ElemType;
569 TfPyLock lock;
570 if (PySequence_Check(obj.ptr())) {
571 Py_ssize_t len = PySequence_Length(obj.ptr());
572 Array result(len);
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));
576 if (!h) {
577 if (PyErr_Occurred())
578 PyErr_Clear();
579 return VtValue();
580 }
581 boost::python::extract<ElemType> e(h.get());
582 if (!e.check())
583 return VtValue();
584 *elem++ = e();
585 }
586 return VtValue(result);
587 } else if (PyIter_Check(obj.ptr())) {
588 Array result;
589 while (PyObject *item = PyIter_Next(obj.ptr())) {
590 boost::python::handle<> h(item);
591 if (!h) {
592 if (PyErr_Occurred())
593 PyErr_Clear();
594 return VtValue();
595 }
596 boost::python::extract<ElemType> e(h.get());
597 if (!e.check())
598 return VtValue();
599 result.push_back(e());
600 }
601 return VtValue(result);
602 }
603 return VtValue();
604}
605
606template <class Array, class Iter>
608Vt_ConvertFromRange(Iter begin, Iter end)
609{
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);
614 if (cast.IsEmpty())
615 return cast;
616 cast.Swap(*e++);
617 }
618 return VtValue(result);
619}
620
621template <class T>
623Vt_CastToArray(VtValue const &v) {
624 VtValue ret;
625 TfPyObjWrapper obj;
626 // Attempt to convert from either python sequence or vector<VtValue>.
627 if (v.IsHolding<TfPyObjWrapper>()) {
628 ret = Vt_ConvertFromPySequenceOrIter<T>(v.UncheckedGet<TfPyObjWrapper>());
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());
632 }
633 return ret;
634}
635
637template <class Elem>
638void VtRegisterValueCastsFromPythonSequencesToArray()
639{
640 typedef VtArray<Elem> Array;
641 VtValue::RegisterCast<TfPyObjWrapper, Array>(Vt_CastToArray<Array>);
642 VtValue::RegisterCast<std::vector<VtValue>, Array>(Vt_CastToArray<Array>);
643}
644
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) > >();
649
650PXR_NAMESPACE_CLOSE_SCOPE
651
652#endif // PXR_BASE_VT_WRAP_ARRAY_H
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.
Definition: pyUtils.h:59
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).
Definition: pyUtils.h:180
Defines all the types "TYPED" for which Vt creates a VtTYPEDArray typedef.
Convenience class for accessing the Python Global Interpreter Lock.
Definition: pyLock.h:122
Boost Python object wrapper.
Definition: pyObjWrapper.h:97
TF_API PyObject * ptr() const
Underlying PyObject* access.
Represents an arbitrary dimensional rectangular container class.
Definition: array.h:227
Provides a container which may hold any type, and provides introspection and iteration over array typ...
Definition: value.h:164
bool IsEmpty() const
Returns true iff this value is empty.
Definition: value.h:1300
VtValue & Swap(VtValue &rhs) noexcept
Swap this with rhs.
Definition: value.h:973
bool IsHolding() const
Return true if this value is holding an object of type T, false otherwise.
Definition: value.h:1082
T const & UncheckedGet() const &
Returns a const reference to the held object if the held object is of type T.
Definition: value.h:1122
size_t size() const
Return the total number of elements in this array.
Definition: array.h:488
pointer data()
Return a non-const pointer to this array's data.
Definition: array.h:417
bool empty() const
Return true if this array contains no elements, false otherwise.
Definition: array.h:514
iterator end()
Returns a non-const iterator to the end of the array.
Definition: array.h:382
iterator begin()
Return a non-const iterator to the start of the array.
Definition: array.h:379
std::string ArchGetDemangled()
Return demangled RTTI generated-type name.
Definition: demangle.h:103
std::string TfStringify(const T &v)
Convert an arbitrary type into a string.
Definition: stringUtils.h:572
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.
Definition: half.h:41
Define integral types.
STL namespace.
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...
Definition: traits.h:62
A boost.python visitor that associates the Python class object created by the wrapping with the TfTyp...
A file containing basic constants and definitions.