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
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>
70
71#include <algorithm>
72#include <numeric>
73#include <ostream>
74#include <string>
75#include <memory>
76#include <vector>
77
78PXR_NAMESPACE_OPEN_SCOPE
79
80namespace Vt_WrapArray {
81
82using namespace boost::python;
83
84using std::unique_ptr;
85using std::vector;
86using std::string;
87
88template <typename T>
89object
90getitem_ellipsis(VtArray<T> const &self, object idx)
91{
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();
96 }
97 return object(self);
98}
99
100template <typename T>
101object
102getitem_index(VtArray<T> const &self, int64_t idx)
103{
104 static const bool throwError = true;
105 idx = TfPyNormalizeIndex(idx, self.size(), throwError);
106 return object(self[idx]);
107}
108
109template <typename T>
110object
111getitem_slice(VtArray<T> const &self, slice idx)
112{
113 try {
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;
117 VtArray<T> result(setSize);
118 size_t i = 0;
119 for (; range.start != range.stop; range.start += range.step, ++i) {
120 result[i] = *range.start;
121 }
122 result[i] = *range.start;
123 return object(result);
124 }
125 catch (std::invalid_argument const &) {
126 return object();
127 }
128}
129
130template <typename T, typename S>
131void
132setArraySlice(VtArray<T> &self, S value,
133 slice::range<T*>& range, size_t setSize, bool tile = false)
134{
135 // Check size.
136 const size_t length = len(value);
137 if (length == 0)
138 TfPyThrowValueError("No values with which to set array slice.");
139 if (!tile && length < setSize) {
140 string msg = TfStringPrintf
141 ("Not enough values to set slice. Expected %zu, got %zu.",
142 setSize, length);
144 }
145
146 // Extract the values before setting any. If we can extract the
147 // whole vector at once then do that since it should be faster.
148 std::vector<T> extracted;
149 extract<std::vector<T> > vectorExtraction(value);
150 if (vectorExtraction.check()) {
151 std::vector<T> tmp = vectorExtraction();
152 extracted.swap(tmp);
153 }
154 else {
155 extracted.reserve(length);
156 for (size_t i = 0; i != length; ++i) {
157 extracted.push_back(extract<T>(value[i]));
158 }
159 }
160
161 // We're fine, go through and set them. Handle common case as a fast
162 // path.
163 if (range.step == 1 && length >= setSize) {
164 std::copy(extracted.begin(), extracted.begin() + setSize, range.start);
165 }
166 else {
167 for (size_t i = 0; i != setSize; range.start += range.step, ++i) {
168 *range.start = extracted[i % length];
169 }
170 }
171}
172
173template <typename T>
174void
175setArraySlice(VtArray<T> &self, slice idx, object value, bool tile = false)
176{
177 // Get the range.
178 slice::range<T*> range;
179 try {
180 T* data = self.data();
181 range = idx.get_indices(data, data + self.size());
182 }
183 catch (std::invalid_argument const &) {
184 // Do nothing
185 return;
186 }
187
188 // Get the number of items to be set.
189 const size_t setSize = 1 + (range.stop - range.start) / range.step;
190
191 // Copy from VtArray. We only want to take this path if the passed value is
192 // *exactly* a VtArray. That is, we don't want to take this path if it can
193 // merely *convert* to a VtArray, so we check that we can extract a mutable
194 // lvalue reference from the python object, which requires that there be a
195 // real VtArray there.
196 if (extract< VtArray<T> &>(value).check()) {
197 const VtArray<T> val = extract< VtArray<T> >(value);
198 const size_t length = val.size();
199 if (length == 0)
200 TfPyThrowValueError("No values with which to set array slice.");
201 if (!tile && length < setSize) {
202 string msg = TfStringPrintf
203 ("Not enough values to set slice. Expected %zu, got %zu.",
204 setSize, length);
206 }
207
208 // We're fine, go through and set them.
209 for (size_t i = 0; i != setSize; range.start += range.step, ++i) {
210 *range.start = val[i % length];
211 }
212 }
213
214 // Copy from scalar.
215 else if (extract<T>(value).check()) {
216 if (!tile) {
217 // XXX -- We're allowing implicit tiling; do we want to?
218 //TfPyThrowValueError("can only assign an iterable.");
219 }
220
221 // Use scalar to fill entire slice.
222 const T val = extract<T>(value);
223 for (size_t i = 0; i != setSize; range.start += range.step, ++i) {
224 *range.start = val;
225 }
226 }
227
228 // Copy from list.
229 else if (extract<list>(value).check()) {
230 setArraySlice(self, extract<list>(value)(), range, setSize, tile);
231 }
232
233 // Copy from tuple.
234 else if (extract<tuple>(value).check()) {
235 setArraySlice(self, extract<tuple>(value)(), range, setSize, tile);
236 }
237
238 // Copy from iterable.
239 else {
240 setArraySlice(self, list(value), range, setSize, tile);
241 }
242}
243
244
245template <typename T>
246void
247setitem_ellipsis(VtArray<T> &self, object idx, object value)
248{
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();
253 }
254 setArraySlice(self, slice(0, self.size()), value);
255}
256
257template <typename T>
258void
259setitem_index(VtArray<T> &self, int64_t idx, object value)
260{
261 idx = TfPyNormalizeIndex(idx, self.size(), /*throwError=*/true);
262 setArraySlice(self, slice(idx, idx+1), value, /*tile=*/true);
263}
264
265template <typename T>
266void
267setitem_slice(VtArray<T> &self, slice idx, object value)
268{
269 setArraySlice(self, idx, value);
270}
271
272
273template <class T>
274VT_API string GetVtArrayName();
275
276template <class T, class... Ts>
277constexpr bool Vt_IsAnySameImpl(TfMetaList<Ts...>) {
278 return (std::is_same_v<T, Ts> || ...);
279}
280
281template <class T, class TypeList>
282constexpr bool Vt_IsAnySame() {
283 return Vt_IsAnySameImpl<T>(TypeList{});
284}
285
286// This is the same types as in VT_INTEGRAL_BUILTIN_VALUE_TYPES with char
287// and bool types removed.
288using Vt_OptimizedStreamIntegralTypes =
289 TfMetaList<short, unsigned short,
290 int, unsigned int,
291 long, unsigned long,
292 long long, unsigned long long>;
293
294// Explicitly convert half to float here instead of relying on implicit
295// conversion to float to work around the fact that libc++ only provides
296// implementations of std::isfinite for types where std::is_arithmetic
297// is true.
298template <typename T>
299inline bool _IsFinite(T const &value) {
300 return std::isfinite(value);
301}
302inline bool _IsFinite(GfHalf const &value) {
303 return std::isfinite(static_cast<float>(value));
304}
305
306template <typename T>
307static void streamValue(std::ostringstream &stream, T const &value) {
308 // To avoid overhead we stream out certain builtin types directly
309 // without calling TfPyRepr().
310 if constexpr(Vt_IsAnySame<T, Vt_OptimizedStreamIntegralTypes>()) {
311 stream << value;
312 }
313 // For float types we need to be make sure to represent infs and nans correctly.
314 else if constexpr(GfIsFloatingPoint<T>::value) {
315 if (_IsFinite(value)) {
316 stream << value;
317 }
318 else {
319 stream << TfPyRepr(value);
320 }
321 }
322 else {
323 stream << TfPyRepr(value);
324 }
325}
326
327static unsigned int
328Vt_ComputeEffectiveRankAndLastDimSize(
329 Vt_ShapeData const *sd, size_t *lastDimSize)
330{
331 unsigned int rank = sd->GetRank();
332 if (rank == 1)
333 return rank;
334
335 size_t divisor = std::accumulate(
336 sd->otherDims, sd->otherDims + rank-1,
337 1, [](size_t x, size_t y) { return x * y; });
338
339 size_t remainder = divisor ? sd->totalSize % divisor : 0;
340 *lastDimSize = divisor ? sd->totalSize / divisor : 0;
341
342 if (remainder)
343 rank = 1;
344
345 return rank;
346}
347
348template <typename T>
349string __repr__(VtArray<T> const &self)
350{
351 if (self.empty())
352 return TF_PY_REPR_PREFIX +
353 TfStringPrintf("%s()", GetVtArrayName<VtArray<T> >().c_str());
354
355 std::ostringstream stream;
356 stream.precision(17);
357 stream << "(";
358 for (size_t i = 0; i < self.size(); ++i) {
359 stream << (i ? ", " : "");
360 streamValue(stream, self[i]);
361 }
362 stream << (self.size() == 1 ? ",)" : ")");
363
364 const std::string repr = TF_PY_REPR_PREFIX +
365 TfStringPrintf("%s(%zd, %s)",
366 GetVtArrayName<VtArray<T> >().c_str(),
367 self.size(), stream.str().c_str());
368
369 // XXX: This is to deal with legacy shaped arrays and should be removed
370 // once all shaped arrays have been eliminated.
371 // There is no nice way to make an eval()able __repr__ for shaped arrays
372 // that preserves the shape information, so put it in <> to make it
373 // clearly not eval()able. That has the advantage that, if somebody passes
374 // the repr into eval(), it'll raise a SyntaxError that clearly points to
375 // the beginning of the __repr__.
376 Vt_ShapeData const *shapeData = self._GetShapeData();
377 size_t lastDimSize = 0;
378 unsigned int rank =
379 Vt_ComputeEffectiveRankAndLastDimSize(shapeData, &lastDimSize);
380 if (rank > 1) {
381 std::string shapeStr = "(";
382 for (size_t i = 0; i != rank-1; ++i) {
383 shapeStr += TfStringPrintf(
384 i ? ", %d" : "%d", shapeData->otherDims[i]);
385 }
386 shapeStr += TfStringPrintf(", %zu)", lastDimSize);
387 return TfStringPrintf("<%s with shape %s>",
388 repr.c_str(), shapeStr.c_str());
389 }
390
391 return repr;
392}
393
394template <typename T>
395VtArray<T> *VtArray__init__(object const &values)
396{
397 // Make an array.
398 unique_ptr<VtArray<T> > ret(new VtArray<T>(len(values)));
399
400 // Set the values. This is equivalent to saying 'ret[...] = values'
401 // in python, except that we allow tiling here.
402 static const bool tile = true;
403 setArraySlice(*ret, slice(0, ret->size()), values, tile);
404 return ret.release();
405}
406template <typename T>
407VtArray<T> *VtArray__init__2(size_t size, object const &values)
408{
409 // Make the array.
410 unique_ptr<VtArray<T> > ret(new VtArray<T>(size));
411
412 // Set the values. This is equivalent to saying 'ret[...] = values'
413 // in python, except that we allow tiling here.
414 static const bool tile = true;
415 setArraySlice(*ret, slice(0, ret->size()), values, tile);
416
417 return ret.release();
418}
419
420// overloading for operator special methods, to allow tuple / list & array
421// combinations
422ARCH_PRAGMA_PUSH
423ARCH_PRAGMA_UNSAFE_USE_OF_BOOL
424ARCH_PRAGMA_UNARY_MINUS_ON_UNSIGNED
425
426VTOPERATOR_WRAP(__add__,__radd__)
427VTOPERATOR_WRAP_NONCOMM(__sub__,__rsub__)
428VTOPERATOR_WRAP(__mul__,__rmul__)
429VTOPERATOR_WRAP_NONCOMM(__div__,__rdiv__)
430VTOPERATOR_WRAP_NONCOMM(__mod__,__rmod__)
431
432VTOPERATOR_WRAP_BOOL(Equal,==)
433VTOPERATOR_WRAP_BOOL(NotEqual,!=)
434VTOPERATOR_WRAP_BOOL(Greater,>)
435VTOPERATOR_WRAP_BOOL(Less,<)
436VTOPERATOR_WRAP_BOOL(GreaterOrEqual,>=)
437VTOPERATOR_WRAP_BOOL(LessOrEqual,<=)
438ARCH_PRAGMA_POP
439}
440
441template <typename T>
442static std::string _VtStr(T const &self)
443{
444 return TfStringify(self);
445}
446
447template <typename T>
448void VtWrapArray()
449{
450 using namespace Vt_WrapArray;
451
452 typedef T This;
453 typedef typename This::ElementType Type;
454
455 string name = GetVtArrayName<This>();
456 string typeStr = ArchGetDemangled(typeid(Type));
457 string docStr = TfStringPrintf("An array of type %s.", typeStr.c_str());
458
459 auto selfCls = class_<This>(name.c_str(), docStr.c_str(), no_init)
460 .setattr("_isVtArray", true)
461 .def(TfTypePythonClass())
462 .def(init<>())
463 .def("__init__", make_constructor(VtArray__init__<Type>),
464 (const char *)
465 "__init__(values)\n\n"
466 "values: a sequence (tuple, list, or another VtArray with "
467 "element type convertible to the new array's element type)\n\n"
468 )
469 .def("__init__", make_constructor(VtArray__init__2<Type>))
470 .def(init<unsigned int>())
471
472 .def("__getitem__", getitem_ellipsis<Type>)
473 .def("__getitem__", getitem_slice<Type>)
474 .def("__getitem__", getitem_index<Type>)
475 .def("__setitem__", setitem_ellipsis<Type>)
476 .def("__setitem__", setitem_slice<Type>)
477 .def("__setitem__", setitem_index<Type>)
478
479 .def("__len__", &This::size)
480 .def("__iter__", iterator<This>())
481
482 .def("__repr__", __repr__<Type>)
483
484// .def(str(self))
485 .def("__str__", _VtStr<T>)
486 .def(self == self)
487 .def(self != self)
488
489#ifdef NUMERIC_OPERATORS
490#define ADDITION_OPERATOR
491#define SUBTRACTION_OPERATOR
492#define MULTIPLICATION_OPERATOR
493#define DIVISION_OPERATOR
494#define UNARY_NEG_OPERATOR
495#endif
496
497#ifdef ADDITION_OPERATOR
498 VTOPERATOR_WRAPDECLARE(+,__add__,__radd__)
499#endif
500#ifdef SUBTRACTION_OPERATOR
501 VTOPERATOR_WRAPDECLARE(-,__sub__,__rsub__)
502#endif
503#ifdef MULTIPLICATION_OPERATOR
504 VTOPERATOR_WRAPDECLARE(*,__mul__,__rmul__)
505#endif
506#ifdef DIVISION_OPERATOR
507 VTOPERATOR_WRAPDECLARE(/,__div__,__rdiv__)
508#endif
509#ifdef MOD_OPERATOR
510 VTOPERATOR_WRAPDECLARE(%,__mod__,__rmod__)
511#endif
512#ifdef DOUBLE_MULT_OPERATOR
513 .def(self * double())
514 .def(double() * self)
515#endif
516#ifdef DOUBLE_DIV_OPERATOR
517 .def(self / double())
518#endif
519#ifdef UNARY_NEG_OPERATOR
520 .def(- self)
521#endif
522
523 ;
524
525#define WRITE(z, n, data) BOOST_PP_COMMA_IF(n) data
526#define VtCat_DEF(z, n, unused) \
527 def("Cat",(VtArray<Type> (*)( BOOST_PP_REPEAT(n, WRITE, VtArray<Type> const &) ))VtCat<Type>);
528 BOOST_PP_REPEAT_FROM_TO(1, VT_FUNCTIONS_MAX_ARGS, VtCat_DEF, ~)
529#undef VtCat_DEF
530
531 VTOPERATOR_WRAPDECLARE_BOOL(Equal)
532 VTOPERATOR_WRAPDECLARE_BOOL(NotEqual)
533
534 // Wrap conversions from python sequences.
535 TfPyContainerConversions::from_python_sequence<
536 This,
537 TfPyContainerConversions::
538 variable_capacity_all_items_convertible_policy>();
539
540 // Wrap implicit conversions from VtArray to TfSpan.
541 implicitly_convertible<This, TfSpan<Type> >();
542 implicitly_convertible<This, TfSpan<const Type> >();
543}
544
545// wrapping for functions that work for base types that support comparisons
546template <typename T>
547void VtWrapComparisonFunctions()
548{
549 using namespace Vt_WrapArray;
550
551 typedef T This;
552 typedef typename This::ElementType Type;
553
554 def("AnyTrue", VtAnyTrue<Type>);
555 def("AllTrue", VtAllTrue<Type>);
556
557 VTOPERATOR_WRAPDECLARE_BOOL(Greater)
558 VTOPERATOR_WRAPDECLARE_BOOL(Less)
559 VTOPERATOR_WRAPDECLARE_BOOL(GreaterOrEqual)
560 VTOPERATOR_WRAPDECLARE_BOOL(LessOrEqual)
561}
562
563template <class Array>
565Vt_ConvertFromPySequenceOrIter(TfPyObjWrapper const &obj)
566{
567 typedef typename Array::ElementType ElemType;
568 TfPyLock lock;
569 if (PySequence_Check(obj.ptr())) {
570 Py_ssize_t len = PySequence_Length(obj.ptr());
571 Array result(len);
572 ElemType *elem = result.data();
573 for (Py_ssize_t i = 0; i != len; ++i) {
574 boost::python::handle<> h(PySequence_ITEM(obj.ptr(), i));
575 if (!h) {
576 if (PyErr_Occurred())
577 PyErr_Clear();
578 return VtValue();
579 }
580 boost::python::extract<ElemType> e(h.get());
581 if (!e.check())
582 return VtValue();
583 *elem++ = e();
584 }
585 return VtValue(result);
586 } else if (PyIter_Check(obj.ptr())) {
587 Array result;
588 while (PyObject *item = PyIter_Next(obj.ptr())) {
589 boost::python::handle<> h(item);
590 if (!h) {
591 if (PyErr_Occurred())
592 PyErr_Clear();
593 return VtValue();
594 }
595 boost::python::extract<ElemType> e(h.get());
596 if (!e.check())
597 return VtValue();
598 result.push_back(e());
599 }
600 return VtValue(result);
601 }
602 return VtValue();
603}
604
605template <class Array, class Iter>
607Vt_ConvertFromRange(Iter begin, Iter end)
608{
609 typedef typename Array::ElementType ElemType;
610 Array result(distance(begin, end));
611 for (ElemType *e = result.data(); begin != end; ++begin) {
612 VtValue cast = VtValue::Cast<ElemType>(*begin);
613 if (cast.IsEmpty())
614 return cast;
615 cast.Swap(*e++);
616 }
617 return VtValue(result);
618}
619
620template <class T>
622Vt_CastToArray(VtValue const &v) {
623 VtValue ret;
624 TfPyObjWrapper obj;
625 // Attempt to convert from either python sequence or vector<VtValue>.
626 if (v.IsHolding<TfPyObjWrapper>()) {
627 ret = Vt_ConvertFromPySequenceOrIter<T>(v.UncheckedGet<TfPyObjWrapper>());
628 } else if (v.IsHolding<std::vector<VtValue> >()) {
629 std::vector<VtValue> const &vec = v.UncheckedGet<std::vector<VtValue> >();
630 ret = Vt_ConvertFromRange<T>(vec.begin(), vec.end());
631 }
632 return ret;
633}
634
636template <class Elem>
637void VtRegisterValueCastsFromPythonSequencesToArray()
638{
639 typedef VtArray<Elem> Array;
640 VtValue::RegisterCast<TfPyObjWrapper, Array>(Vt_CastToArray<Array>);
641 VtValue::RegisterCast<std::vector<VtValue>, Array>(Vt_CastToArray<Array>);
642}
643
644#define VT_WRAP_ARRAY(unused, elem) \
645 VtWrapArray< VtArray< VT_TYPE(elem) > >();
646#define VT_WRAP_COMPARISON(unused, elem) \
647 VtWrapComparisonFunctions< VtArray< VT_TYPE(elem) > >();
648
649PXR_NAMESPACE_CLOSE_SCOPE
650
651#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:228
Provides a container which may hold any type, and provides introspection and iteration over array typ...
Definition: value.h:165
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:972
bool IsHolding() const
Return true if this value is holding an object of type T, false otherwise.
Definition: value.h:1081
T const & UncheckedGet() const &
Returns a const reference to the held object if the held object is of type T.
Definition: value.h:1121
size_t size() const
Return the total number of elements in this array.
Definition: array.h:489
pointer data()
Return a non-const pointer to this array's data.
Definition: array.h:418
bool empty() const
Return true if this array contains no elements, false otherwise.
Definition: array.h:515
iterator end()
Returns a non-const iterator to the end of the array.
Definition: array.h:383
iterator begin()
Return a non-const iterator to the start of the array.
Definition: array.h:380
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.