HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
valueRef.h
Go to the documentation of this file.
1 //
2 // Copyright 2025 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_BASE_VT_VALUEREF_H
8 #define PXR_BASE_VT_VALUEREF_H
9 
10 #include "pxr/pxr.h"
11 
12 // XXX: Include pyLock.h after pyObjWrapper.h to work around
13 // Python include ordering issues.
15 
16 #include "pxr/base/tf/pyLock.h"
17 
18 #include "pxr/base/arch/demangle.h"
19 #include "pxr/base/arch/hints.h"
20 #include "pxr/base/arch/pragmas.h"
25 #include "pxr/base/tf/tf.h"
26 #include "pxr/base/tf/type.h"
27 
28 #include "pxr/base/vt/api.h"
29 #include "pxr/base/vt/hash.h"
30 #include "pxr/base/vt/streamOut.h"
31 #include "pxr/base/vt/traits.h"
32 #include "pxr/base/vt/types.h"
34 
35 #include <iosfwd>
36 #include <typeinfo>
37 #include <type_traits>
38 
40 
41 class VtValue;
42 class VtValueRef;
43 
44 // Overload VtStreamOut for vector<VtValueRef>. Produces output like [value1,
45 // value2, ... valueN].
46 VT_API std::ostream &
47 VtStreamOut(std::vector<VtValueRef> const &val, std::ostream &);
48 
49 /// A non-owning type-erased view of a value, interoperating with VtValue.
50 /// Since VtValueRef is non-owning it must not persist beyond the lifetime of
51 /// the value it views, and so it is typically best used as a function argument
52 /// or an automatic variable.
53 ///
54 /// Both ordinary typed values and VtValues are implicitly convertible to
55 /// VtValueRef. This makes it convenient to use when writing a function that
56 /// can take an object of any type. Since it's non-owning, it is relatively
57 /// light-weight, incurring no heap allocations or reference counting
58 /// operations. In addition, VtValueRef remembers if it is viewing an
59 /// rvalue-reference, in which case the underlying object can be removed by a
60 /// move() operation rather than a copy. See Remove().
61 ///
62 /// VtValueRef supports much of the same API as VtValue, including implicitly
63 /// converting back to VtValue if needed.
65 {
66 protected:
67 
68  // This unfortunately needs to be a union since there are some callers that
69  // place function pointers in VtValue. The specific _TypeInfo
70  // instantiations know which union member to use at based on their type
71  // parameter.
72  union _RefdObjPtr {
73  void const *objPtr;
74  void (*fnPtr)();
75  };
76 
77  // Type information base class.
78  // We force alignment here in order to ensure that TfPointerAndBits has
79  // enough room to store all TypeInfo related flags.
80  struct alignas(8) _TypeInfo {
81  private:
82  using _CanHashFunc = bool (*)(_RefdObjPtr);
83  using _HashFunc = size_t (*)(_RefdObjPtr);
84  using _EqualFunc = bool (*)(_RefdObjPtr, _RefdObjPtr);
85  using _GetPyObjFunc = TfPyObjWrapper (*)(_RefdObjPtr);
86  using _GetVtValueFunc = VtValue (*)(_RefdObjPtr);
87  using _StreamOutFunc = std::ostream & (*)(_RefdObjPtr, std::ostream &);
88  using _IsArrayValuedFunc = bool (*)(_RefdObjPtr);
89  using _GetNumElementsFunc = size_t (*)(_RefdObjPtr);
90 
91  protected:
92  constexpr _TypeInfo(const std::type_info &ti,
93  const std::type_info &elementTi,
94  int knownTypeIndex,
95  bool isArray,
96  bool isHashable,
97  bool canComposeOver,
98  bool canTransform,
99  bool isMutable,
100  _CanHashFunc canHash,
101  _HashFunc hash,
102  _EqualFunc equal,
103  _GetPyObjFunc getPyObj,
104  _GetVtValueFunc getVtValue,
105  _StreamOutFunc streamOut,
106  _IsArrayValuedFunc isArrayValued,
107  _GetNumElementsFunc getNumElements)
108  : typeInfo(ti)
109  , elementTypeInfo(elementTi)
110  , knownTypeIndex(knownTypeIndex)
111  , isArray(isArray)
112  , isHashable(isHashable)
113  , canComposeOver(canComposeOver)
114  , canTransform(canTransform)
115  , isMutable(isMutable)
116  // Function table
117  , _canHash(canHash)
118  , _hash(hash)
119  , _equal(equal)
120  , _getPyObj(getPyObj)
121  , _getVtValue(getVtValue)
122  , _streamOut(streamOut)
123  , _isArrayValued(isArrayValued)
124  , _getNumElements(getNumElements)
125  {}
126 
127  public:
129  return _canHash(storage);
130  }
131  size_t Hash(_RefdObjPtr storage) const {
132  return _hash(storage);
133  }
134  bool Equal(_RefdObjPtr lhs, _RefdObjPtr rhs) const {
135  return _equal(lhs, rhs);
136  }
138  return _getPyObj(storage);
139  }
140  // Defined below due to circular VtValue <-> VtValueRef includes.
141  inline VtValue GetVtValue(_RefdObjPtr storage) const;
143  std::ostream &out) const {
144  return _streamOut(storage, out);
145  }
147  return _isArrayValued(storage);
148  }
150  return _getNumElements(storage);
151  }
152 
153  const std::type_info &typeInfo;
154  const std::type_info &elementTypeInfo;
155  const int knownTypeIndex;
156  const bool isArray;
157  const bool isHashable;
158  const bool canComposeOver;
159  const bool canTransform;
160  const bool isMutable;
161 
162  private:
163  _CanHashFunc _canHash;
164  _HashFunc _hash;
165  _EqualFunc _equal;
166  _GetPyObjFunc _getPyObj;
167  _GetVtValueFunc _getVtValue;
168  _StreamOutFunc _streamOut;
169  _IsArrayValuedFunc _isArrayValued;
170  _GetNumElementsFunc _getNumElements;
171  };
172 
173  // Type-dispatching overloads.
174 
175  // Array type helpers. Non-array types have no shape data, no elements and
176  // report `void` for their element types.
177  template <class T>
179  {
180  template <class U>
181  static size_t GetNumElements(U &&) { return 0; }
182  constexpr static std::type_info const &GetElementTypeid() {
183  return typeid(void);
184  }
185  };
186  // VtArray types report their qualities.
187  template <class Array>
189  {
190  static size_t GetNumElements(Array const &obj) {
191  return obj.size();
192  }
193  constexpr static std::type_info const &GetElementTypeid() {
194  return typeid(typename Array::ElementType);
195  }
196  };
197  // VtArrayEdit types are identical to non-array types except that they do
198  // report their underlying element type.
199  template <class ArrayEdit>
201  {
202  constexpr static std::type_info const &GetElementTypeid() {
203  return typeid(typename ArrayEdit::ElementType);
204  }
205  };
206 
207  // Select which flavor of array helper to use -- VtArray uses
208  // _IsArrayHelper, VtArrayEdit uses _IsArrayEditHelper, all other types use
209  // _NonArrayHelper.
210  template <class T>
212  VtIsArray<T>::value, _IsArrayHelper<T>,
214  _IsArrayEditHelper<T>, _NonArrayHelper<T>>
215  >;
216 
217  // _TypeInfo implementation.
218  template <class T, bool IsMutable>
219  struct _TypeInfoImpl : public _TypeInfo
220  {
221  using Type = T;
223 
224  static constexpr bool IsPointer = std::is_pointer_v<Type>;
225  static constexpr bool IsFunctionPointer =
226  IsPointer && std::is_function_v<std::remove_pointer_t<Type>>;
227 
229  IsPointer,
230  const std::remove_pointer_t<Type> *,
231  const Type>;
232 
235 
238 
239  //using RefType = Type &;
240  // using ObjType = std::conditional_t<
241  // std::is_pointer_v<Type>, Type, Type &>;
242  //using ConstRefType = ConstType const &;
243 
244  constexpr _TypeInfoImpl()
245  : _TypeInfo(typeid(T),
247  Vt_KnownValueTypeDetail::GetIndex<T>(),
248  VtIsArray<T>::value,
249  VtIsHashable<T>(),
252  IsMutable,
253  &This::_CanHash,
254  &This::_Hash,
255  &This::_Equal,
256  &This::_GetPyObj,
257  &This::_GetVtValue,
258  &This::_StreamOut,
259 
260  // Array support.
261  &This::_IsArrayValued,
262  &This::_GetNumElements)
263 
264  {}
265 
266  ////////////////////////////////////////////////////////////////////
267  // Typed API for client use.
268  static GetObjResultType
270  if constexpr (IsFunctionPointer) {
271  return reinterpret_cast<GetObjResultType>(storage.fnPtr);
272  }
273  else if constexpr (IsPointer) {
274  return reinterpret_cast<GetObjResultType>(storage.objPtr);
275  }
276  else {
277  return *static_cast<ConstType *>(storage.objPtr);
278  }
279  }
280 
283  // This const cast is safe since the original VtValueRef must've
284  // been constructed with a mutable object.
285  if constexpr (IsFunctionPointer) {
286  return reinterpret_cast<GetMutableObjResultType>(storage.fnPtr);
287  }
288  else if constexpr (IsPointer) {
289  return reinterpret_cast<
291  }
292  else {
293  return *static_cast<Type *>(const_cast<void *>(storage.objPtr));
294  }
295  }
296 
297  static void SetObj(T const &obj, _RefdObjPtr &storage) {
298  if constexpr (IsFunctionPointer) {
299  storage.fnPtr = reinterpret_cast<void (*)()>(obj);
300  }
301  else if constexpr (IsPointer) {
302  storage.objPtr = static_cast<void const *>(obj);
303  }
304  else {
305  storage.objPtr = static_cast<void const *>(std::addressof(obj));
306  }
307  }
308 
309  private:
310  static bool _CanHash(_RefdObjPtr) {
311  return VtIsHashable<T>();
312  }
313 
314  static size_t _Hash(_RefdObjPtr ptr) {
315  return VtHashValue(GetObj(ptr));
316  }
317 
318  static bool _Equal(_RefdObjPtr lhs, _RefdObjPtr rhs) {
319  return GetObj(lhs) == GetObj(rhs);
320  }
321 
322  static TfPyObjWrapper _GetPyObj(_RefdObjPtr storage) {
323 #ifdef PXR_PYTHON_SUPPORT_ENABLED
324  TfPyLock lock;
325  return pxr_boost::python::api::object(GetObj(storage));
326 #else
327  return {};
328 #endif
329  }
330 
331  // Defined below.
332  static VtValue _GetVtValue(_RefdObjPtr storage);
333 
334  static std::ostream &_StreamOut(
335  _RefdObjPtr storage, std::ostream &out) {
336  return VtStreamOut(GetObj(storage), out);
337  }
338 
339  static bool _IsArrayValued(_RefdObjPtr storage) {
340  return VtIsArray<T>::value;
341  }
342 
343  static std::type_info const &
344  _GetElementTypeid(_RefdObjPtr ptr) {
345  return _ArrayHelper<T>::GetElementTypeid();
346  }
347 
348  static size_t _GetNumElements(_RefdObjPtr ptr) {
349  return _ArrayHelper<T>::GetNumElements(GetObj(ptr));
350  }
351 
352  };
353 
354  // Metafunction that returns the specific _TypeInfo subclass for T or T&.
355  // The passed `T` should be as-if deduced by a forwarding reference, so a
356  // reference type if the referenced object is mutable, otherwise a
357  // non-reference type.
358  template <class T>
359  using _TypeInfoFor = _TypeInfoImpl<
360  std::decay_t<T>,
361  std::is_reference_v<T> && std::is_const_v<T>>;
362 
363 public:
364 
365  /// Default ctor gives empty VtValueRef.
366  VtValueRef() : _info(nullptr) {}
367 
368  VtValueRef(VtValueRef const &) = default;
369  VtValueRef(VtValueRef &&) = default;
370 
371  /// Implicitly convert or construct a VtValueRef referring to \p obj. The
372  /// passed \p obj must outlive this VtValueRef instance.
373  template <class T>
375  !std::is_same_v<std::decay_t<T>, VtValueRef> &&
376  !std::is_same_v<std::decay_t<T>, VtValue>> * = 0) {
377  using TypeInfo = _TypeInfoFor<T>;
378  using TypeInfoType = typename TypeInfo::Type;
380  "VtValueRef does not support proxies");
381  static const TypeInfo ti;
382  ti.SetObj(obj, _ptr);
383  _info = std::addressof(ti);
384  }
385 
386  /// Rebind to view the same object as another VtValueRef.
387  VtValueRef &operator=(VtValueRef const &ref) = default;
388  VtValueRef &operator=(VtValueRef &&ref) = default;
389 
390  // Disallow implicit conversion assignments.
391  template <class T>
392  VtValueRef &operator=(T &&) = delete;
393 
394  /// Overloaded swap() for generic code/stl/etc. Swaps the viewed objects.
395  friend void swap(VtValueRef &lhs, VtValueRef &rhs) {
396  std::swap(lhs._ptr, rhs._ptr);
397  std::swap(lhs._info, rhs._info);
398  }
399 
400  /// Return true if this value is viewing an object of type \p T, false
401  /// otherwise.
402  template <class T>
403  bool IsHolding() const {
404  return _info && _TypeIs<T>();
405  }
406 
407  /// Return true if this refers to an rvalue, and thus can be `Remove()`d by
408  /// a move construction operation instead of a copy.
409  bool IsRValue() const {
410  return _info && _info->isMutable;
411  }
412 
413  /// Return true if this views a VtArray instance, false otherwise.
414  VT_API bool IsArrayValued() const;
415 
416  /// Return true if this views a VtArrayEdit instance, false otherwise.
417  VT_API bool IsArrayEditValued() const;
418 
419  /// Return the number of elements in the viewed value if IsArrayValued(),
420  /// return 0 otherwise.
421  size_t GetArraySize() const { return _GetNumElements(); }
422 
423  /// Return the typeid of the type viewed by this value.
424  std::type_info const &GetTypeid() const {
425  return _info ? _info->typeInfo : typeid(void);
426  }
427 
428  /// If this value views a VtArray or VtArrayEdit instance, return the typeid
429  /// of its element type. For example, if this value views a VtIntArray or a
430  /// VtIntArrayEdit, return typeid(int). Otherwise return typeid(void).
431  std::type_info const &GetElementTypeid() const {
432  return _info ? _info->elementTypeInfo : typeid(void);
433  }
434 
435  /// Returns the TfType of the type viewed by this value.
436  VT_API TfType GetType() const;
437 
438  /// Return the type name of the viewed typeid.
439  VT_API std::string GetTypeName() const;
440 
441  /// Return VtKnownValueTypeIndex<T> for the viewed type T. If this value is
442  /// empty or views a type that is not 'known', return -1.
444  return _info ? _info->knownTypeIndex : -1;
445  }
446 
447  /// Return a const reference to the viewed object if the viewed object is of
448  /// type \a T. Invokes undefined behavior otherwise. This is the fastest
449  /// \a Get() method to use after a successful \a IsHolding() check.
450  template <class T>
451  typename _TypeInfoFor<T>::GetObjResultType
452  UncheckedGet() const { return _Get<T>(); }
453 
454  /// Return a const reference to the viewed object if the viewed object is of
455  /// type \a T. Issues an error and return a const reference to a default
456  /// value if the viewed object is not of type \a T. Use \a IsHolding to
457  /// verify correct type before calling this function. The default value
458  /// returned in case of type mismatch is constructed using
459  /// Vt_DefaultValueFactory<T>. That may be specialized for client types.
460  /// The default implementation of the default value factory produces a
461  /// value-initialized T.
462  template <class T>
463  typename _TypeInfoFor<T>::GetObjResultType
464  Get() const {
466 
467  // In the unlikely case that the types don't match, we obtain a default
468  // value to return and issue an error via _FailGet.
469  if (ARCH_UNLIKELY(!IsHolding<T>())) {
470  return *(static_cast<T const *>(
471  _FailGet(Factory::Invoke, typeid(T))));
472  }
473 
474  return _Get<T>();
475  }
476 
477  /// Return a copy of the viewed object if the viewed object is of type T.
478  /// Return a copy of the default value \a def otherwise. Note that this
479  /// always returns a copy, as opposed to \a Get() which always returns a
480  /// reference.
481  template <class T>
482  T GetWithDefault(T const &def = T()) const {
483  return IsHolding<T>() ? UncheckedGet<T>() : def;
484  }
485 
486  /// Return a move-constructed (if the viewed object is an rvalue) or
487  /// copy-constructed \p T instance from the viewed object. If the viewed
488  /// object is an rvalue then it is left in its moved-from state. If this
489  /// value does not view a \p T instance, issue an error and return a
490  /// default-constructed \p T.
491  template <class T>
492  T Remove() {
493  if (IsHolding<T>()) {
494  return UncheckedRemove<T>();
495  }
496  else {
497  _FailRemove(typeid(T));
498  }
499  return {};
500  }
501 
502  /// Return a move-constructed (if the viewed object is an rvalue) or
503  /// copy-constructed \p T instance from the viewed object. If the viewed
504  /// object is an rvalue then it is left in its moved-from state. If this
505  /// value does not view a \p T instance, invoke undefined behavior.
506  template <class T>
508  if (IsRValue()) {
509  return std::move(_GetMutable<T>());
510  }
511  return _Get<T>();
512  }
513 
514  /// Returns true iff this value is empty.
515  bool IsEmpty() const { return !_info; }
516 
517  /// Implicitly convert to a VtValue by copying the viewed object.
518  VT_API operator VtValue() const;
519 
520  /// Return true if the viewed object provides a hash implementation.
521  VT_API bool CanHash() const;
522 
523  /// Return a hash code for the viewed object by calling VtHashValue() on it.
524  VT_API size_t GetHash() const;
525 
526  friend inline size_t hash_value(VtValueRef const &val) {
527  return val.GetHash();
528  }
529 
530  /// Return true if this value holds a type that has been declared at compile
531  /// time to support composing over other types. This is a fast check that
532  /// can be used to avoid calling `VtValueComposeOver(strong, weak)` if
533  /// `strong` does not support composing over. Empty VtValue always can
534  /// compose over.
535  bool CanComposeOver() const {
536  return !_info || _info->canComposeOver;
537  }
538 
539  /// Return true if this value holds a type that has been declared to support
540  /// value transforms at compile time. This is a fast check that can be used
541  /// to avoid calling the relatively slower `VtValueTryTransform(obj, xform)`
542  /// if `obj` does not support transforms at all. Empty VtValue does not
543  /// support transforms.
544  bool CanTransform() const {
545  return _info && _info->canTransform;
546  }
547 
548  /// Test two values for equality.
549  bool operator == (const VtValueRef &rhs) const {
550  bool empty = IsEmpty(), rhsEmpty = rhs.IsEmpty();
551  if (empty || rhsEmpty) {
552  // Either one or both empty -- only equal if both empty.
553  return empty == rhsEmpty;
554  }
555  if (_info == rhs._info) {
556  // Holding identical types -- compare directly.
557  return _info->Equal(_ptr, rhs._ptr);
558  }
559  return false;
560  }
561  bool operator != (const VtValueRef &rhs) const { return !(*this == rhs); }
562 
563  /// Calls through to operator << on the viewed object.
564  VT_API friend std::ostream &
565  operator << (std::ostream &out, const VtValueRef &self);
566 
567 protected:
568  VT_API size_t _GetNumElements() const;
569 
570  template <class T>
571  inline bool
572  _TypeIs() const {
574  return _info->knownTypeIndex == VtGetKnownValueTypeIndex<T>();
575  }
576  else {
577  std::type_info const &t = typeid(T);
578  return TfSafeTypeCompare(_info->typeInfo, t);
579  }
580  }
581 
582  template <class T>
583  typename _TypeInfoFor<T>::GetMutableObjResultType
585  using TypeInfo = _TypeInfoFor<T>;
586  return TypeInfo::GetMutableObj(_ptr);
587  }
588 
589  template <class T>
590  typename _TypeInfoFor<T>::GetObjResultType
591  _Get() const {
592  using TypeInfo = _TypeInfoFor<T>;
593  return TypeInfo::GetObj(_ptr);
594  }
595 
596  // Helper invoked in case Get fails. Reports an error and returns a default
597  // value for \a queryType.
598  VT_API void const *
599  _FailGet(Vt_DefaultValueHolder (*factory)(),
600  std::type_info const &queryType) const;
601 
602  VT_API void _FailRemove(std::type_info const &);
603 
604  // This grants friend access to a function in the wrapper file for this
605  // class. This lets the wrapper reach down into a value to get a
606  // pxr_boost::python wrapped object corresponding to the viewed type. This
607  // facility is necessary to get the python API we want.
608  friend TfPyObjWrapper
610 
612 
614  _TypeInfo const *_info;
615 };
616 
617 #ifndef doxygen
618 
619 //
620 // The Get()/IsHolding routines needs to be special-cased to handle getting a
621 // VtValueRef *as* a VtValueRef.
622 //
623 
624 template <>
625 inline VtValueRef const &
626 VtValueRef::Get<VtValueRef>() const {
627  return *this;
628 }
629 
630 template <>
631 inline VtValueRef const &
632 VtValueRef::UncheckedGet<VtValueRef>() const {
633  return *this;
634 }
635 
636 template <>
637 inline bool
638 VtValueRef::IsHolding<VtValueRef>() const {
639  return true;
640 }
641 
642 // Specialize VtValueRef::IsHolding<void>() to always return false.
643 template <>
644 inline bool
645 VtValueRef::IsHolding<void>() const {
646  return false;
647 }
648 
649 #endif // !doxygen
650 
651 /// A non-owning type-erased view of a mutable lvalue, interoperating with
652 /// VtValue. Since VtMutableValueRef is non-owning it must not persist beyond
653 /// the lifetime of the value it views, and so it is typically best used as a
654 /// function argument or an automatic variable.
655 ///
656 /// Ordinary typed values are implicitly convertible to VtMutableValueRef. This
657 /// makes it convenient to use when writing a function that can take an object
658 /// of any type. Since it's non-owning, it is relatively light-weight,
659 /// incurring no heap allocations or reference counting operations.
660 ///
662 {
663 public:
664  /// Default ctor gives empty VtMutableValueRef.
665  VtMutableValueRef() = default;
666 
667  template <class T>
669 
670  /// Assign to the viewed value.
671  template <class T>
673  static_assert(std::is_same_v<T, typename Vt_ValueGetStored<T>::Type>,
674  "Can only assign to VtMutableValueRef with a type T "
675  "that stores as T");
676  if (IsHolding<T>()) {
677  _GetMutable<T>() = std::forward<T>(obj);
678  }
679  else {
680  _FailAssign(typeid(T));
681  }
682  return *this;
683  }
684 
685  template <class T>
687  static_assert(std::is_same_v<T, typename Vt_ValueGetStored<T>::Type>,
688  "Can only assign to VtMutableValueRef with a type T "
689  "that stores as T");
690  _GetMutable<T>() = std::forward<T>(obj);
691  return *this;
692  }
693 
694  /// Swap the viewed value with \a rhs. If this value is holding a T, make an
695  /// unqualified call to swap(<viewed-value>, rhs). If this value is not
696  /// holding a T, replace the viewed value with a value-initialized T instance
697  /// first, then swap.
698  template <class T>
699  void
700  Swap(T &rhs) {
701  static_assert(std::is_same_v<T, typename Vt_ValueGetStored<T>::Type>,
702  "Can only VtValueRef::Swap with a type T "
703  "that stores as T");
704  if (IsHolding<T>()) {
705  UncheckedSwap(rhs);
706  }
707  else {
708  _FailSwap(typeid(T));
709  }
710  }
711 
712  /// Swap the viewed value with \a rhs. This VtValue must be holding an
713  /// object of type \p T. If it does not, this invokes undefined behavior.
714  /// Use Swap() if this VtValue is not known to contain an object of type
715  /// \p T.
716  template <class T>
717  void
718  UncheckedSwap(T &rhs) {
719  static_assert(std::is_same_v<T, typename Vt_ValueGetStored<T>::Type>,
720  "Can only VtValueRef::Swap with a type T "
721  "that stores as T");
722  using std::swap;
723  swap(_GetMutable<T>(), rhs);
724  }
725 
726  /// If this value holds an object of type \p T, invoke \p mutateFn, passing
727  /// it a non-const reference to the viewed object and return true. Otherwise
728  /// do nothing and return false.
729  template <class T, class Fn>
730  bool
731  Mutate(Fn &&mutateFn) {
732  static_assert(std::is_same_v<T, typename Vt_ValueGetStored<T>::Type>,
733  "Can only VtValueRef::Mutate a type T that stores as T");
734  if (!IsHolding<T>()) {
735  return false;
736  }
737  UncheckedMutate<T>(std::forward<Fn>(mutateFn));
738  return true;
739  }
740 
741  /// Invoke \p mutateFn, passing it a non-const reference to the viewed
742  /// object which must be of type \p T. If the viewed object is not of type
743  /// \p T, this function invokes undefined behavior.
744  template <class T, class Fn>
745  void
746  UncheckedMutate(Fn &&mutateFn) {
747  static_assert(std::is_same_v<T, typename Vt_ValueGetStored<T>::Type>,
748  "Can only VtValueRef::Mutate a type T that stores as T");
749  // We move to a temporary, mutate the temporary, then move back. This
750  // prevents callers from escaping a mutable reference to the viewed
751  // object via a side-effect of mutateFn.
752  T &stored = _GetMutable<T>();
753  T tmp = std::move(stored);
754  std::forward<Fn>(mutateFn)(tmp);
755  stored = std::move(tmp);
756  }
757 
758 private:
759  VT_API void _FailAssign(std::type_info const &);
760  VT_API void _FailSwap(std::type_info const &);
761 
762 };
763 
765 
766 // This unusual arrangement of closing the namespace, including value.h, then
767 // reopening the namespace exists because valueRef.h and value.h are
768 // interdependent. A similar symmetric construct exists in value.h. If
769 // valueRef.h is included first, then value.h will be included here. Otherwise
770 // if value.h is included first then it will have included valueRef.h. Either
771 // way all the necessary declarations from both types are present prior to the
772 // appearance of the following defintions.
773 
774 #include "pxr/base/vt/value.h"
775 
777 
778 // Defined here due to circular dependencies.
779 VtValue
781  return _getVtValue(storage);
782 }
783 
784 template <class T, bool B>
785 VtValue
787  return VtValue { GetObj(storage) };
788 }
789 
791 
792 #ifdef PXR_PYTHON_SUPPORT_ENABLED
793 
794 #include "pxr/external/boost/python/converter/arg_from_python.hpp"
795 #include <optional>
796 
797 namespace PXR_BOOST_NAMESPACE::python::converter {
798 
799 // We specialize arg_rvalue_from_python<VtValueRef> to derive
800 // arg_rvalue_from_python<VtValue>. This way we get storage for both -- an
801 // `rvalue_from_python_data<VtValue &> m_data` in the base and a VtValueRef in
802 // this class. There's no other way afaict to "add space" in an rvalue
803 // converter to support a "view" type where we need to also conjure a temporary
804 // for that view. This way we can create the `VtValue` in the base as usual and
805 // let the `VtValueRef` here refer to it for the lifetime of the arg.
806 template <>
807 struct arg_rvalue_from_python<PXR_NS::VtValueRef>
808  : public arg_rvalue_from_python<PXR_NS::VtValue>
809 {
810  using base_type = arg_rvalue_from_python<PXR_NS::VtValue>;
811  using base_type::convertible;
812  using result_type = PXR_NS::VtValueRef &; // boost.python convention.
813 
814  VT_API arg_rvalue_from_python(PyObject* obj);
815 
816  VT_API result_type operator()();
817 
818  std::optional<PXR_NS::VtValueRef> optValueRef;
819 };
820 
821 } // namespace PXR_BOOST_NAMESPACE::python::converter
822 
823 #endif // PXR_PYTHON_SUPPORT_ENABLED
824 
825 #endif // PXR_BASE_VT_VALUEREF_H
826 
bool Equal(_RefdObjPtr lhs, _RefdObjPtr rhs) const
Definition: valueRef.h:134
VtMutableValueRef & UncheckedAssign(T &&obj)
Definition: valueRef.h:686
static constexpr std::type_info const & GetElementTypeid()
Definition: valueRef.h:182
bool operator==(const VtValueRef &rhs) const
Test two values for equality.
Definition: valueRef.h:549
friend void swap(VtValueRef &lhs, VtValueRef &rhs)
Overloaded swap() for generic code/stl/etc. Swaps the viewed objects.
Definition: valueRef.h:395
friend size_t hash_value(VtValueRef const &val)
Definition: valueRef.h:526
typename std::enable_if< B, T >::type enable_if_t
Define Imath::enable_if_t to be std for C++14, equivalent for C++11.
bool _TypeIs() const
Definition: valueRef.h:572
Definition: ImfArray.h:45
bool Mutate(Fn &&mutateFn)
Definition: valueRef.h:731
VtValueRef(T &&obj, std::enable_if_t< !std::is_same_v< std::decay_t< T >, VtValueRef > &&!std::is_same_v< std::decay_t< T >, VtValue >> *=0)
Definition: valueRef.h:374
VtMutableValueRef(T &obj)
Definition: valueRef.h:668
friend TfPyObjWrapper Vt_GetPythonObjectFromHeldValue(VtValueRef const &self)
void
Definition: png.h:1083
long size() const
Definition: ImfArray.h:90
getFileOption("OpenEXR:storage") storage
Definition: HDK_Image.dox:276
static constexpr std::type_info const & GetElementTypeid()
Definition: valueRef.h:202
void swap(UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &a, UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &b)
Definition: UT_ArraySet.h:1699
typename std::conditional< B, T, F >::type conditional_t
Definition: core.h:266
TfPyObjWrapper GetPyObj(_RefdObjPtr storage) const
Definition: valueRef.h:137
std::ostream & StreamOut(_RefdObjPtr storage, std::ostream &out) const
Definition: valueRef.h:142
const bool isArray
Definition: valueRef.h:156
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
GLsizei const GLfloat * value
Definition: glcorearb.h:824
static void SetObj(T const &obj, _RefdObjPtr &storage)
Definition: valueRef.h:297
VT_API size_t _GetNumElements() const
_RefdObjPtr _ptr
Definition: valueRef.h:613
static size_t GetNumElements(Array const &obj)
Definition: valueRef.h:190
static constexpr bool IsPointer
Definition: valueRef.h:224
void UncheckedSwap(T &rhs)
Definition: valueRef.h:718
#define VT_API
Definition: api.h:23
const std::type_info & typeInfo
Definition: valueRef.h:153
bool CanTransform() const
Definition: valueRef.h:544
VT_API bool IsArrayValued() const
Return true if this views a VtArray instance, false otherwise.
IMATH_HOSTDEVICE constexpr bool equal(T1 a, T2 b, T3 t) IMATH_NOEXCEPT
Definition: ImathFun.h:105
VT_API bool CanHash() const
Return true if the viewed object provides a hash implementation.
void Swap(T &rhs)
Definition: valueRef.h:700
VT_API void _FailRemove(std::type_info const &)
VtValue GetVtValue(_RefdObjPtr storage) const
Definition: valueRef.h:780
_TypeInfoFor< T >::GetObjResultType _Get() const
Definition: valueRef.h:591
OutGridT const XformOp bool bool
bool IsHolding() const
Definition: valueRef.h:403
VT_API size_t GetHash() const
Return a hash code for the viewed object by calling VtHashValue() on it.
VtValueRef & operator=(VtValueRef const &ref)=default
Rebind to view the same object as another VtValueRef.
_TypeInfo const * _info
Definition: valueRef.h:614
VT_API std::ostream & VtStreamOut(std::vector< VtValueRef > const &val, std::ostream &)
VT_API bool IsArrayEditValued() const
Return true if this views a VtArrayEdit instance, false otherwise.
VT_API void const * _FailGet(Vt_DefaultValueHolder(*factory)(), std::type_info const &queryType) const
#define ARCH_UNLIKELY(x)
Definition: hints.h:30
#define PXR_NS
Definition: pxr.h:54
_TypeInfoFor< T >::GetObjResultType Get() const
Definition: valueRef.h:464
bool CanComposeOver() const
Definition: valueRef.h:535
std::conditional_t< IsPointer, const std::remove_pointer_t< Type > *, const Type > ConstType
Definition: valueRef.h:231
std::type_info const & GetTypeid() const
Return the typeid of the type viewed by this value.
Definition: valueRef.h:424
GLint ref
Definition: glcorearb.h:124
size_t GetNumElements(_RefdObjPtr storage) const
Definition: valueRef.h:149
bool IsRValue() const
Definition: valueRef.h:409
bool IsEmpty() const
Returns true iff this value is empty.
Definition: valueRef.h:515
VT_API TfType GetType() const
Returns the TfType of the type viewed by this value.
static constexpr bool IsFunctionPointer
Definition: valueRef.h:225
constexpr _TypeInfo(const std::type_info &ti, const std::type_info &elementTi, int knownTypeIndex, bool isArray, bool isHashable, bool canComposeOver, bool canTransform, bool isMutable, _CanHashFunc canHash, _HashFunc hash, _EqualFunc equal, _GetPyObjFunc getPyObj, _GetVtValueFunc getVtValue, _StreamOutFunc streamOut, _IsArrayValuedFunc isArrayValued, _GetNumElementsFunc getNumElements)
Definition: valueRef.h:92
VT_API TfPyObjWrapper _GetPythonObject() const
std::conditional_t< IsPointer, Type, Type & > GetMutableObjResultType
Definition: valueRef.h:237
constexpr bool VtIsHashable()
Definition: hash.h:59
size_t Hash(_RefdObjPtr storage) const
Definition: valueRef.h:131
int GetKnownValueTypeIndex() const
Definition: valueRef.h:443
void UncheckedMutate(Fn &&mutateFn)
Definition: valueRef.h:746
T Remove()
Definition: valueRef.h:492
VtMutableValueRef & operator=(T &&obj)
Assign to the viewed value.
Definition: valueRef.h:672
GLdouble t
Definition: glad.h:2397
T GetWithDefault(T const &def=T()) const
Definition: valueRef.h:482
VT_API std::string GetTypeName() const
Return the type name of the viewed typeid.
A trait to detect instantiations of VtArray, specialized in array.h.
Definition: traits.h:22
bool IsArrayValued(_RefdObjPtr storage) const
Definition: valueRef.h:146
void const * objPtr
Definition: valueRef.h:73
_TypeInfoFor< T >::GetObjResultType UncheckedGet() const
Definition: valueRef.h:452
typename Tf_ConditionalImpl< Cond >::template Type< T, F > TfConditionalType
Definition: meta.h:73
VtValueRef()
Default ctor gives empty VtValueRef.
Definition: valueRef.h:366
_TypeInfoFor< T >::GetMutableObjResultType _GetMutable()
Definition: valueRef.h:584
constexpr _TypeInfoImpl()
Definition: valueRef.h:244
bool CanHash(_RefdObjPtr storage) const
Definition: valueRef.h:128
size_t VtHashValue(T const &val)
Definition: hash.h:66
VT_API friend std::ostream & operator<<(std::ostream &out, const VtValueRef &self)
Calls through to operator << on the viewed object.
const bool isHashable
Definition: valueRef.h:157
auto ptr(T p) -> const void *
Definition: format.h:4331
GLuint GLfloat * val
Definition: glcorearb.h:1608
static size_t GetNumElements(U &&)
Definition: valueRef.h:181
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
std::type_info const & GetElementTypeid() const
Definition: valueRef.h:431
static GetObjResultType GetObj(_RefdObjPtr const &storage)
Definition: valueRef.h:269
const int knownTypeIndex
Definition: valueRef.h:155
Definition: type.h:47
const bool canTransform
Definition: valueRef.h:159
VtMutableValueRef()=default
Default ctor gives empty VtMutableValueRef.
static GetMutableObjResultType GetMutableObj(_RefdObjPtr &storage)
Definition: valueRef.h:282
static constexpr std::type_info const & GetElementTypeid()
Definition: valueRef.h:193
std::conditional_t< IsPointer, ConstType, ConstType & > GetObjResultType
Definition: valueRef.h:234
PXR_NAMESPACE_OPEN_SCOPE bool TfSafeTypeCompare(const std::type_info &t1, const std::type_info &t2)
TfConditionalType< VtIsArray< T >::value, _IsArrayHelper< T >, TfConditionalType< VtIsArrayEdit< T >::value, _IsArrayEditHelper< T >, _NonArrayHelper< T >> > _ArrayHelper
Definition: valueRef.h:215
T UncheckedRemove()
Definition: valueRef.h:507
constexpr int GetIndex()
Definition: types.h:249
const bool canComposeOver
Definition: valueRef.h:158
_TypeInfoImpl< std::decay_t< T >, std::is_reference_v< T > &&std::is_const_v< T >> _TypeInfoFor
Definition: valueRef.h:361
Definition: value.h:89
const bool isMutable
Definition: valueRef.h:160
const std::type_info & elementTypeInfo
Definition: valueRef.h:154
size_t GetArraySize() const
Definition: valueRef.h:421
bool operator!=(const VtValueRef &rhs) const
Definition: valueRef.h:561