HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
value.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 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_VALUE_H
8 #define PXR_BASE_VT_VALUE_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"
23 #include "pxr/base/tf/meta.h"
28 #include "pxr/base/tf/tf.h"
29 #include "pxr/base/tf/type.h"
30 
31 #include "pxr/base/vt/api.h"
32 #include "pxr/base/vt/hash.h"
33 #include "pxr/base/vt/streamOut.h"
34 #include "pxr/base/vt/traits.h"
35 #include "pxr/base/vt/types.h"
37 
38 #include <iosfwd>
39 #include <typeinfo>
40 #include <type_traits>
41 
43 
44 class VtValue;
45 class VtValueRef;
46 
47 // Overload VtStreamOut for vector<VtValue>. Produces output like [value1,
48 // value2, ... valueN].
49 VT_API std::ostream &
50 VtStreamOut(std::vector<VtValue> const &val, std::ostream &);
51 
52 /// Provides a container which may hold any type, and provides introspection
53 /// and iteration over array types. See \a VtIsArray for more info.
54 ///
55 /// \section VtValue_Casting Held-type Conversion with VtValue::Cast
56 ///
57 /// VtValue provides a suite of "Cast" methods that convert or create a
58 /// VtValue holding a requested type (via template parameter, typeid, or
59 /// type-matching to another VtValue) from the type of the currently-held
60 /// value. Clients can add conversions between their own types using the
61 /// RegisterCast(), RegisterSimpleCast(), and
62 /// RegisterSimpleBidirectionalCast() methods. Conversions from plugins can
63 /// be guaranteed to be registered before they are needed by registering them
64 /// from within a
65 /// \code
66 /// TF_REGISTRY_FUNCTION(VtValue) {
67 /// }
68 /// \endcode
69 /// block.
70 ///
71 /// \subsection VtValue_builtin_conversions Builtin Type Conversion
72 ///
73 /// Conversions between most of the basic "value types" that are intrinsically
74 /// convertible are builtin, including all numeric types (including Gf's \c
75 /// half), std::string/TfToken, GfVec* (for vecs of the same dimension), and
76 /// VtArray<T> for floating-point POD and GfVec of the preceding.
77 ///
78 /// \subsection VtValue_numeric_conversion Numeric Conversion Safety
79 ///
80 /// The conversions between all scalar numeric types are performed with range
81 /// checks such as provided by boost::numeric_cast(), and will fail, returning
82 /// an empty VtValue if the source value is out of range of the destination
83 /// type.
84 ///
85 /// Conversions between GfVec and other compound-numeric types provide no more
86 /// or less safety or checking than the conversion constructors of the types
87 /// themselves. This includes VtArray, even VtArray<T> for T in scalar types
88 /// that are range-checked when held singly.
89 class VtValue
90 {
91  static const unsigned int _LocalFlag = 1 << 0;
92  static const unsigned int _TrivialCopyFlag = 1 << 1;
93  static const unsigned int _ProxyFlag = 1 << 2;
94  static const unsigned int _AllFlags =
95  _LocalFlag | _TrivialCopyFlag | _ProxyFlag;
96 
97  template <class T>
98  struct _Counted {
99  explicit _Counted(T const &obj) : _obj(obj) {
100  _refCount = 0;
101  }
102  bool IsUnique() const { return _refCount == 1; }
103  T const &Get() const { return _obj; }
104  T &GetMutable() { return _obj; }
105 
106  private:
107  T _obj;
108  mutable std::atomic<int> _refCount;
109 
110  friend inline void TfDelegatedCountIncrement(_Counted const *d) {
111  d->_refCount.fetch_add(1, std::memory_order_relaxed);
112  }
113  friend inline void TfDelegatedCountDecrement(_Counted const *d) noexcept {
114  if (d->_refCount.fetch_sub(1, std::memory_order_release) == 1) {
115  std::atomic_thread_fence(std::memory_order_acquire);
116  delete d;
117  }
118  }
119  };
120 
121  // Hold objects up to 1 word large locally. This makes the total structure
122  // 16 bytes when compiled 64 bit (1 word type-info pointer, 1 word storage
123  // space).
124  static const size_t _MaxLocalSize = sizeof(void*);
125  typedef std::aligned_storage<
126  /* size */_MaxLocalSize, /* alignment */_MaxLocalSize>::type _Storage;
127 
128  template <class T>
129  using _IsTriviallyCopyable = std::integral_constant<bool,
130  std::is_trivially_default_constructible_v<T> &&
131  std::is_trivially_copyable_v<T> &&
132  std::is_trivially_copy_assignable_v<T> &&
133  std::is_trivially_destructible_v<T>>;
134 
135  // Metafunction that returns true if T should be stored locally, false if it
136  // should be stored remotely.
137  template <class T>
138  using _UsesLocalStore = std::integral_constant<bool,
139  (sizeof(T) <= sizeof(_Storage)) &&
143 
144  // Type information base class.
145  // We force alignment here in order to ensure that TfPointerAndBits has
146  // enough room to store all TypeInfo related flags.
147  struct alignas(8) _TypeInfo {
148  private:
149  using _CopyInitFunc = void (*)(_Storage const &, _Storage &);
150  using _DestroyFunc = void (*)(_Storage &);
151  using _MoveFunc = void (*)(_Storage &, _Storage &);
152  using _CanHashFunc = bool (*)(_Storage const &);
153  using _HashFunc = size_t (*)(_Storage const &);
154  using _EqualFunc = bool (*)(_Storage const &, _Storage const &);
155  using _EqualPtrFunc = bool (*)(_Storage const &, void const *);
156  using _MakeMutableFunc = void (*)(_Storage &);
157  using _GetPyObjFunc = TfPyObjWrapper (*)(_Storage const &);
158  using _GetValueRefFunc = VtValueRef (*)(_Storage const &, bool);
159  using _StreamOutFunc =
160  std::ostream & (*)(_Storage const &, std::ostream &);
161  using _GetTypeidFunc = std::type_info const & (*)(_Storage const &);
162  using _IsArrayValuedFunc = bool (*)(_Storage const &);
163  using _GetElementTypeidFunc =
164  std::type_info const & (*)(_Storage const &);
165  using _GetShapeDataFunc = const Vt_ShapeData* (*)(_Storage const &);
166  using _GetNumElementsFunc = size_t (*)(_Storage const &);
167  using _ProxyHoldsTypeFunc = bool (*)(_Storage const &, std::type_info const &);
168  using _GetProxiedTypeFunc = TfType (*)(_Storage const &);
169  using _GetProxiedTypeidFunc =
170  std::type_info const & (*)(_Storage const &);
171  using _GetProxiedObjPtrFunc = void const *(*)(_Storage const &);
172  using _GetProxiedAsVtValueFunc = VtValue (*)(_Storage const &);
173 
174  protected:
175  constexpr _TypeInfo(const std::type_info &ti,
176  const std::type_info &elementTi,
177  int knownTypeIndex,
178  bool isArray,
179  bool isHashable,
180  bool isProxy,
181  bool canComposeOver,
182  bool canTransform,
183  _CopyInitFunc copyInit,
184  _DestroyFunc destroy,
185  _MoveFunc move,
186  _CanHashFunc canHash,
187  _HashFunc hash,
188  _EqualFunc equal,
189  _EqualPtrFunc equalPtr,
190  _MakeMutableFunc makeMutable,
191  _GetPyObjFunc getPyObj,
192  _GetValueRefFunc getValueRef,
193  _StreamOutFunc streamOut,
194  _GetTypeidFunc getTypeid,
195  _IsArrayValuedFunc isArrayValued,
196  _GetElementTypeidFunc getElementTypeid,
197  _GetShapeDataFunc getShapeData,
198  _GetNumElementsFunc getNumElements,
199  _ProxyHoldsTypeFunc proxyHoldsType,
200  _GetProxiedTypeFunc getProxiedType,
201  _GetProxiedTypeidFunc getProxiedTypeid,
202  _GetProxiedObjPtrFunc getProxiedObjPtr,
203  _GetProxiedAsVtValueFunc getProxiedAsVtValue)
204  : typeInfo(ti)
205  , elementTypeInfo(elementTi)
206  , knownTypeIndex(knownTypeIndex)
207  , isProxy(isProxy)
208  , isArray(isArray)
209  , isHashable(isHashable)
210  , canComposeOver(canComposeOver)
211  , canTransform(canTransform)
212  // Function table
213  , _copyInit(copyInit)
214  , _destroy(destroy)
215  , _move(move)
216  , _canHash(canHash)
217  , _hash(hash)
218  , _equal(equal)
219  , _equalPtr(equalPtr)
220  , _makeMutable(makeMutable)
221  , _getPyObj(getPyObj)
222  , _getValueRef(getValueRef)
223  , _streamOut(streamOut)
224  , _getTypeid(getTypeid)
225  , _isArrayValued(isArrayValued)
226  , _getElementTypeid(getElementTypeid)
227  , _getShapeData(getShapeData)
228  , _getNumElements(getNumElements)
229  , _proxyHoldsType(proxyHoldsType)
230  , _getProxiedType(getProxiedType)
231  , _getProxiedTypeid(getProxiedTypeid)
232  , _getProxiedObjPtr(getProxiedObjPtr)
233  , _getProxiedAsVtValue(getProxiedAsVtValue)
234  {}
235 
236  public:
237  void CopyInit(_Storage const &src, _Storage &dst) const {
238  _copyInit(src, dst);
239  }
240  void Destroy(_Storage &storage) const {
241  _destroy(storage);
242  }
243  void Move(_Storage &src, _Storage &dst) const noexcept {
244  _move(src, dst);
245  }
246  bool CanHash(_Storage const &storage) const {
247  return _canHash(storage);
248  }
249  size_t Hash(_Storage const &storage) const {
250  return _hash(storage);
251  }
252  bool Equal(_Storage const &lhs, _Storage const &rhs) const {
253  return _equal(lhs, rhs);
254  }
255  bool EqualPtr(_Storage const &lhs, void const *rhs) const {
256  return _equalPtr(lhs, rhs);
257  }
258  void MakeMutable(_Storage &storage) const {
259  _makeMutable(storage);
260  }
261  TfPyObjWrapper GetPyObj(_Storage const &storage) const {
262  return _getPyObj(storage);
263  }
264  inline VtValueRef GetValueRef(_Storage const &storage,
265  bool rvalue) const;
266  std::ostream &StreamOut(_Storage const &storage,
267  std::ostream &out) const {
268  return _streamOut(storage, out);
269  }
270  bool IsArrayValued(_Storage const &storage) const {
271  return _isArrayValued(storage);
272  }
273  std::type_info const &GetElementTypeid(_Storage const &storage) const {
274  return _getElementTypeid(storage);
275  }
276  std::type_info const &GetTypeid(_Storage const &storage) const {
277  return _getTypeid(storage);
278  }
279  const Vt_ShapeData* GetShapeData(_Storage const &storage) const {
280  return _getShapeData(storage);
281  }
282  size_t GetNumElements(_Storage const &storage) const {
283  return _getNumElements(storage);
284  }
285  bool ProxyHoldsType(_Storage const &storage,
286  std::type_info const &t) const {
287  return _proxyHoldsType(storage, t);
288  }
289  TfType GetProxiedType(_Storage const &storage) const {
290  return _getProxiedType(storage);
291  }
292  std::type_info const &GetProxiedTypeid(_Storage const &storage) const {
293  return _getProxiedTypeid(storage);
294  }
295  VtValue GetProxiedAsVtValue(_Storage const &storage) const {
296  return _getProxiedAsVtValue(storage);
297  }
298  void const *GetProxiedObjPtr(_Storage const &storage) const {
299  return _getProxiedObjPtr(storage);
300  }
301 
302  const std::type_info &typeInfo;
303  const std::type_info &elementTypeInfo;
304  int knownTypeIndex;
305  bool isProxy;
306  bool isArray;
307  bool isHashable;
308  bool canComposeOver;
309  bool canTransform;
310 
311  private:
312  _CopyInitFunc _copyInit;
313  _DestroyFunc _destroy;
314  _MoveFunc _move;
315  _CanHashFunc _canHash;
316  _HashFunc _hash;
317  _EqualFunc _equal;
318  _EqualPtrFunc _equalPtr;
319  _MakeMutableFunc _makeMutable;
320  _GetPyObjFunc _getPyObj;
321  _GetValueRefFunc _getValueRef;
322  _StreamOutFunc _streamOut;
323  _GetTypeidFunc _getTypeid;
324  _IsArrayValuedFunc _isArrayValued;
325  _GetElementTypeidFunc _getElementTypeid;
326  _GetShapeDataFunc _getShapeData;
327  _GetNumElementsFunc _getNumElements;
328  _ProxyHoldsTypeFunc _proxyHoldsType;
329  _GetProxiedTypeFunc _getProxiedType;
330  _GetProxiedTypeidFunc _getProxiedTypeid;
331  _GetProxiedObjPtrFunc _getProxiedObjPtr;
332  _GetProxiedAsVtValueFunc _getProxiedAsVtValue;
333  };
334 
335  // Type-dispatching overloads.
336 
337  // Array type helpers. Non-array types have no shape data, no elements and
338  // report `void` for their element types.
339  template <class T>
340  struct _NonArrayHelper
341  {
342  static const Vt_ShapeData* GetShapeData(T const &) { return NULL; }
343  static size_t GetNumElements(T const &) { return 0; }
344  constexpr static std::type_info const &GetElementTypeid() {
345  return typeid(void);
346  }
347  };
348  // VtArray types report their qualities.
349  template <class Array>
350  struct _IsArrayHelper
351  {
352  static const Vt_ShapeData* GetShapeData(Array const &obj) {
353  return obj._GetShapeData();
354  }
355  static size_t GetNumElements(Array const &obj) {
356  return obj.size();
357  }
358  constexpr static std::type_info const &GetElementTypeid() {
359  return typeid(typename Array::ElementType);
360  }
361  };
362  // VtArrayEdit types are identical to non-array types except that they do
363  // report their underlying element type.
364  template <class ArrayEdit>
365  struct _IsArrayEditHelper : _NonArrayHelper<ArrayEdit>
366  {
367  constexpr static std::type_info const &GetElementTypeid() {
368  return typeid(typename ArrayEdit::ElementType);
369  }
370  };
371 
372  // Select which flavor of array helper to use -- VtArray uses
373  // _IsArrayHelper, VtArrayEdit uses _IsArrayEditHelper, all other types use
374  // _NonArrayHelper.
375  template <class T>
376  using _ArrayHelper = TfConditionalType<
377  VtIsArray<T>::value, _IsArrayHelper<T>,
379  _IsArrayEditHelper<T>, _NonArrayHelper<T>>
380  >;
381 
382  // Function used in case T has equality comparison.
383  template <class T>
384  static inline auto
385  _TypedProxyEqualityImpl(T const &a, T const &b, int) -> decltype(a == b) {
386  return a == b;
387  }
388  // Function used in case T does not have equality comparison.
389  template <class NoEqual>
390  static inline bool
391  _TypedProxyEqualityImpl(NoEqual const &a, NoEqual const &b, long) {
392  return VtGetProxiedObject(a) == VtGetProxiedObject(b);
393  }
394 
395  template <class T>
396  static inline auto
397  _ErasedProxyEqualityImpl(T const &a, T const &b, int) -> decltype(a == b) {
398  return a == b;
399  }
400  // Function used in case T does not have equality comparison.
401  template <class NoEqual>
402  static inline bool
403  _ErasedProxyEqualityImpl(NoEqual const &a, NoEqual const &b, long) {
404  return *VtGetErasedProxiedVtValue(a) == *VtGetErasedProxiedVtValue(b);
405  }
406 
407  // Proxy type helper. This version handles non-proxies and typed proxies.
408  template <class T>
409  struct _TypedProxyHelper
410  {
411  using ProxiedType = typename VtGetProxiedType<T>::type;
412 
413  static bool CanHash(T const &) { return VtIsHashable<ProxiedType>(); }
414  static size_t Hash(T const &obj) {
415  return VtHashValue(VtGetProxiedObject(obj));
416  }
417  static bool Equal(T const &a, T const &b) {
418  // We use the traditional int/long = 0 arg technique to disambiguate
419  // overloads, so we can invoke equality comparison on the *proxy*
420  // type if it provides one, or if it doesn't then invoke equality
421  // comparison on the *proxied* type instead.
422  return _TypedProxyEqualityImpl(a, b, 0);
423  }
424  static TfPyObjWrapper GetPyObj(T const &obj) {
425 #ifdef PXR_PYTHON_SUPPORT_ENABLED
426  ProxiedType const &p = VtGetProxiedObject(obj);
427  TfPyLock lock;
429 #else
430  return {};
431 #endif //PXR_PYTHON_SUPPORT_ENABLED
432  }
433  static VtValueRef GetValueRef(T const &obj);
434  static std::ostream &StreamOut(T const &obj, std::ostream &out) {
435  return VtStreamOut(VtGetProxiedObject(obj), out);
436  }
437  static Vt_ShapeData const *GetShapeData(T const &obj) {
438  return _ArrayHelper<ProxiedType>::GetShapeData(
439  VtGetProxiedObject(obj));
440  }
441  static size_t GetNumElements(T const &obj) {
442  return _ArrayHelper<ProxiedType>::GetNumElements(
443  VtGetProxiedObject(obj));
444  }
445  static bool IsArrayValued(T const &) {
447  }
448  static std::type_info const &GetTypeid(T const &) {
449  return typeid(ProxiedType);
450  }
451  static std::type_info const &GetElementTypeid(T const &) {
452  return _ArrayHelper<ProxiedType>::GetElementTypeid();
453  }
454  static VtValue GetProxiedAsVtValue(T const &obj) {
455  return VtValue(VtGetProxiedObject(obj));
456  }
457  static bool HoldsType(T const &tp, std::type_info const &query) {
458  return TfSafeTypeCompare(typeid(ProxiedType), query);
459  }
460  static TfType GetTfType(T const &tp) {
461  return TfType::Find<ProxiedType>();
462  }
463  static void const *GetObjPtr(T const &tp) {
464  return static_cast<void const *>(&VtGetProxiedObject(tp));
465  }
466  };
467 
468  // Proxy type helper. This version handles type-erased proxies.
469  template <class ErasedProxy>
470  struct _ErasedProxyHelper
471  {
472  static bool CanHash(ErasedProxy const &proxy) {
473  return VtGetErasedProxiedVtValue(proxy)->CanHash();
474  }
475  static size_t Hash(ErasedProxy const &proxy) {
476  return VtGetErasedProxiedVtValue(proxy)->GetHash();
477  }
478  static bool Equal(ErasedProxy const &a, ErasedProxy const &b) {
479  // We use the traditional int/long = 0 arg technique to disambiguate
480  // overloads, so we can invoke equality comparison on the *proxy*
481  // type if it provides one, or if it doesn't then invoke equality
482  // comparison on the VtValue containing the *proxied* type instead.
483  return _ErasedProxyEqualityImpl(a, b, 0);
484  }
485  static TfPyObjWrapper GetPyObj(ErasedProxy const &obj) {
486 #ifdef PXR_PYTHON_SUPPORT_ENABLED
487  VtValue const *val = VtGetErasedProxiedVtValue(obj);
488  TfPyLock lock;
489  return pxr_boost::python::api::object(*val);
490 #else
491  return {};
492 #endif //PXR_PYTHON_SUPPORT_ENABLED
493  }
494  static VtValueRef GetValueRef(ErasedProxy const &obj);
495  static std::ostream &
496  StreamOut(ErasedProxy const &obj, std::ostream &out) {
497  return VtStreamOut(obj, out);
498  }
499  static Vt_ShapeData const *GetShapeData(ErasedProxy const &obj) {
500  return VtGetErasedProxiedVtValue(obj)->_GetShapeData();
501  }
502  static size_t GetNumElements(ErasedProxy const &obj) {
503  return VtGetErasedProxiedVtValue(obj)->_GetNumElements();
504  }
505  static bool IsArrayValued(ErasedProxy const &obj) {
506  return VtGetErasedProxiedVtValue(obj)->IsArrayValued();
507  }
508  static std::type_info const &GetTypeid(ErasedProxy const &obj) {
509  return VtGetErasedProxiedVtValue(obj)->GetTypeid();
510  }
511  static std::type_info const &GetElementTypeid(ErasedProxy const &obj) {
512  return VtGetErasedProxiedVtValue(obj)->GetElementTypeid();
513  }
514  static VtValue GetProxiedAsVtValue(ErasedProxy const &ep) {
515  return *VtGetErasedProxiedVtValue(ep);
516  }
517  static bool
518  HoldsType(ErasedProxy const &ep, std::type_info const &query) {
519  return VtErasedProxyHoldsType(ep, query);
520  }
521  static TfType GetTfType(ErasedProxy const &ep) {
522  return VtGetErasedProxiedTfType(ep);
523  }
524  static void const *GetObjPtr(ErasedProxy const &ep) {
525  VtValue const *val = VtGetErasedProxiedVtValue(ep);
526  return val ? val->_GetProxiedObjPtr() : nullptr;
527  }
528  };
529 
530  // _TypeInfo implementation helper. This is a CRTP base that the
531  // _LocalTypeInfo and _RemoteTypeInfo types derive. It wraps their
532  // type-specific implementations with type-generic interfaces.
533  template <class T, class Container, class Derived>
534  struct _TypeInfoImpl : public _TypeInfo
535  {
536  static const bool IsLocal = _UsesLocalStore<T>::value;
537  static const bool HasTrivialCopy = _IsTriviallyCopyable<T>::value;
538  static const bool IsProxy = VtIsValueProxy<T>::value;
539 
540  using ProxyHelper = TfConditionalType<
542  _ErasedProxyHelper<T>, _TypedProxyHelper<T>>;
543 
544  using This = _TypeInfoImpl;
545 
546  constexpr _TypeInfoImpl()
547  : _TypeInfo(typeid(T),
548  _ArrayHelper<T>::GetElementTypeid(),
549  Vt_KnownValueTypeDetail::GetIndex<T>(),
551  VtIsHashable<T>(),
552  IsProxy,
555  &This::_CopyInit,
556  &This::_Destroy,
557  &This::_Move,
558  &This::_CanHash,
559  &This::_Hash,
560  &This::_Equal,
561  &This::_EqualPtr,
562  &This::_MakeMutable,
563  &This::_GetPyObj,
564  &This::_GetValueRef,
565  &This::_StreamOut,
566 
567  &This::_GetTypeid,
568 
569  // Array support.
570  &This::_IsArrayValued,
571  &This::_GetElementTypeid,
572  &This::_GetShapeData,
573  &This::_GetNumElements,
574 
575  // Proxy support.
576  &This::_ProxyHoldsType,
577  &This::_GetProxiedType,
578  &This::_GetProxiedTypeid,
579  &This::_GetProxiedObjPtr,
580  &This::_GetProxiedAsVtValue)
581  {}
582 
583  ////////////////////////////////////////////////////////////////////
584  // Typed API for client use.
585  static T const &GetObj(_Storage const &storage) {
586  return Derived::_GetObj(_Container(storage));
587  }
588 
589  static T &GetMutableObj(_Storage &storage) {
590  return Derived::_GetMutableObj(_Container(storage));
591  }
592 
593  static void CopyInitObj(T const &objSrc, _Storage &dst) {
594  Derived::_PlaceCopy(&_Container(dst), objSrc);
595  }
596 
597  private:
598  static_assert(sizeof(Container) <= sizeof(_Storage),
599  "Container size cannot exceed storage size.");
600 
601  ////////////////////////////////////////////////////////////////////
602  // _TypeInfo interface function implementations.
603  static void _CopyInit(_Storage const &src, _Storage &dst) {
604  new (&_Container(dst)) Container(_Container(src));
605  }
606 
607  static void _Destroy(_Storage &storage) {
608  _Container(storage).~Container();
609  }
610 
611  static bool _CanHash(_Storage const &storage) {
612  return ProxyHelper::CanHash(GetObj(storage));
613  }
614 
615  static size_t _Hash(_Storage const &storage) {
616  return ProxyHelper::Hash(GetObj(storage));
617  }
618 
619  static bool _Equal(_Storage const &lhs, _Storage const &rhs) {
620  // Equal is only ever invoked with an object of this specific type.
621  // That is, we only ever ask a proxy to compare to a proxy; we never
622  // ask a proxy to compare to the proxied object.
623  return ProxyHelper::Equal(GetObj(lhs), GetObj(rhs));
624  }
625 
626  static bool _EqualPtr(_Storage const &lhs, void const *rhs) {
627  // Equal is only ever invoked with an object of this specific type.
628  // That is, we only ever ask a proxy to compare to a proxy; we never
629  // ask a proxy to compare to the proxied object.
630  return ProxyHelper::Equal(
631  GetObj(lhs), *static_cast<T const *>(rhs));
632  }
633 
634  static void _Move(_Storage &src, _Storage &dst) noexcept {
635  new (&_Container(dst)) Container(std::move(_Container(src)));
636  _Destroy(src);
637  }
638 
639  static void _MakeMutable(_Storage &storage) {
640  GetMutableObj(storage);
641  }
642 
643  static TfPyObjWrapper _GetPyObj(_Storage const &storage) {
644  return ProxyHelper::GetPyObj(GetObj(storage));
645  }
646 
647  static VtValueRef _GetValueRef(_Storage const &storage, bool rvalue);
648 
649  static std::ostream &_StreamOut(
650  _Storage const &storage, std::ostream &out) {
651  return ProxyHelper::StreamOut(GetObj(storage), out);
652  }
653 
654  static std::type_info const &_GetTypeid(_Storage const &storage) {
655  return ProxyHelper::GetTypeid(GetObj(storage));
656  }
657 
658  static bool _IsArrayValued(_Storage const &storage) {
659  return ProxyHelper::IsArrayValued(GetObj(storage));
660  }
661 
662  static std::type_info const &
663  _GetElementTypeid(_Storage const &storage) {
664  return ProxyHelper::GetElementTypeid(GetObj(storage));
665  }
666 
667  static const Vt_ShapeData* _GetShapeData(_Storage const &storage) {
668  return ProxyHelper::GetShapeData(GetObj(storage));
669  }
670 
671  static size_t _GetNumElements(_Storage const &storage) {
672  return ProxyHelper::GetNumElements(GetObj(storage));
673  }
674 
675  static bool
676  _ProxyHoldsType(_Storage const &storage, std::type_info const &t) {
677  return ProxyHelper::HoldsType(GetObj(storage), t);
678  }
679 
680  static TfType
681  _GetProxiedType(_Storage const &storage) {
682  return ProxyHelper::GetTfType(GetObj(storage));
683  }
684 
685  static std::type_info const &
686  _GetProxiedTypeid(_Storage const &storage) {
687  return ProxyHelper::GetTypeid(GetObj(storage));
688  }
689 
690  static void const *
691  _GetProxiedObjPtr(_Storage const &storage) {
692  return ProxyHelper::GetObjPtr(GetObj(storage));
693  }
694 
695  static VtValue
696  _GetProxiedAsVtValue(_Storage const &storage) {
697  return ProxyHelper::GetProxiedAsVtValue(GetObj(storage));
698  }
699 
700  ////////////////////////////////////////////////////////////////////
701  // Internal helper -- cast type-generic storage to type-specific
702  // container.
703  static Container &_Container(_Storage &storage) {
704  // XXX Will need std::launder in c++17.
705  return *reinterpret_cast<Container *>(&storage);
706  }
707  static Container const &_Container(_Storage const &storage) {
708  // XXX Will need std::launder in c++17.
709  return *reinterpret_cast<Container const *>(&storage);
710  }
711  };
712 
713  ////////////////////////////////////////////////////////////////////////
714  // Local-storage type info implementation. The container and the object are
715  // the same -- there is no distinct container.
716  template <class T>
717  struct _LocalTypeInfo : _TypeInfoImpl<
718  T, // type
719  T, // container
720  _LocalTypeInfo<T> // CRTP
721  >
722  {
723  constexpr _LocalTypeInfo()
724  : _TypeInfoImpl<T, T, _LocalTypeInfo<T>>()
725  {}
726 
727  // Get returns object directly.
728  static T &_GetMutableObj(T &obj) { return obj; }
729  static T const &_GetObj(T const &obj) { return obj; }
730  // Place placement new's object directly.
731  static void _PlaceCopy(T *dst, T const &src) { new (dst) T(src); }
732  };
733 
734  ////////////////////////////////////////////////////////////////////////
735  // Remote-storage type info implementation. The container is an
736  // TfDelegatedCountPtr to an object holder: _Counted<T>.
737  template <class T>
738  struct _RemoteTypeInfo : _TypeInfoImpl<
739  T, // type
740  TfDelegatedCountPtr<_Counted<T>>, // container
741  _RemoteTypeInfo<T> // CRTP
742  >
743  {
744  constexpr _RemoteTypeInfo()
745  : _TypeInfoImpl<
746  T, TfDelegatedCountPtr<_Counted<T>>, _RemoteTypeInfo<T>>()
747  {}
748 
749  using Ptr = TfDelegatedCountPtr<_Counted<T>>;
750  // Get returns object stored in the pointed-to _Counted<T>.
751  static T &_GetMutableObj(Ptr &ptr) {
752  if (!ptr->IsUnique()) {
753  ptr = TfMakeDelegatedCountPtr<_Counted<T>>(ptr->Get());
754  }
755  return ptr->GetMutable();
756  }
757  static T const &_GetObj(Ptr const &ptr) { return ptr->Get(); }
758  // PlaceCopy() allocates a new _Counted<T> with a copy of the object.
759  static void _PlaceCopy(Ptr *dst, T const &src) {
760  new (dst) Ptr(TfDelegatedCountIncrementTag, new _Counted<T>(src));
761  }
762  };
763 
764  // Metafunction that returns the specific _TypeInfo subclass for T.
765  template <class T>
766  using _TypeInfoFor =
768  _LocalTypeInfo<T>, _RemoteTypeInfo<T>>;
769 
770  // A helper that moves a held value to temporary storage, but keeps it alive
771  // until the _HoldAside object is destroyed. This is used when assigning
772  // over a VtValue that might own the object being assigned. For instance,
773  // if I have a VtValue holding a map<string, VtValue>, and I reassign this
774  // VtValue with one of the elements from the map, we must ensure that the
775  // map isn't destroyed until after the assignment has taken place.
776  friend struct _HoldAside;
777  struct _HoldAside {
778  explicit _HoldAside(VtValue *val)
779  : info((val->IsEmpty() || val->_IsLocalAndTriviallyCopyable())
780  ? static_cast<_TypeInfo const *>(NULL) : val->_info.Get()) {
781  if (info)
782  info->Move(val->_storage, storage);
783  }
784  ~_HoldAside() {
785  if (info)
786  info->Destroy(storage);
787  }
788  _Storage storage;
789  _TypeInfo const *info;
790  };
791 
792  template <class T>
793  struct _Init {
794  using StoredType = typename Vt_ValueGetStored<T>::Type;
795  using TypeInfo = _TypeInfoFor<StoredType>;
796 
797  static_assert(
799 
800  static TfPointerAndBits<const _TypeInfo> _GetTypeInfo() {
801  static const TypeInfo ti;
802  static constexpr unsigned int flags =
803  (TypeInfo::IsLocal ? _LocalFlag : 0) |
804  (TypeInfo::HasTrivialCopy ? _TrivialCopyFlag : 0) |
805  (TypeInfo::IsProxy ? _ProxyFlag : 0);
807  }
808 
809  static void Init(VtValue *val, T const &obj) {
810  val->_info = _GetTypeInfo();
811  if constexpr (std::is_same_v<T, StoredType>) {
812  TypeInfo::CopyInitObj(obj, val->_storage);
813  }
814  else {
815  TypeInfo::CopyInitObj(StoredType {obj}, val->_storage);
816  }
817  }
818  };
819 
820 public:
821 
822  /// Default ctor gives empty VtValue.
823  VtValue() {}
824 
825  /// Copy construct with \p other.
826  VtValue(VtValue const &other) {
827  _Copy(other, *this);
828  }
829 
830  /// Move construct with \p other.
831  VtValue(VtValue &&other) noexcept {
832  _Move(other, *this);
833  }
834 
835  /// Construct a VtValue holding a copy of \p obj.
836  ///
837  /// If T is a char pointer or array, produce a VtValue holding a
838  /// std::string. If T is pxr_boost::python::object, produce a VtValue
839  /// holding a TfPyObjWrapper.
840  template <class T>
841  explicit VtValue(T const &obj) {
842  _Init<T>::Init(this, obj);
843  }
844 
845  /// Construct with VtValueRef.
846  VT_API
847  explicit VtValue(VtValueRef ref);
848 
849  /// Create a new VtValue, taking its contents from \p obj.
850  ///
851  /// This is equivalent to creating a VtValue holding a value-initialized
852  /// \p T instance, then invoking swap(<held-value>, obj), leaving obj in a
853  /// default-constructed (value-initialized) state. In the case that \p
854  /// obj is expensive to copy, it may be significantly faster to use this
855  /// idiom when \p obj need not retain its contents:
856  ///
857  /// \code
858  /// MyExpensiveObject obj = CreateObject();
859  /// return VtValue::Take(obj);
860  /// \endcode
861  ///
862  /// Rather than:
863  ///
864  /// \code
865  /// MyExpensiveObject obj = CreateObject();
866  /// return VtValue(obj);
867  /// \endcode
868  template <class T>
869  static VtValue Take(T &obj) {
870  VtValue ret;
871  ret.Swap(obj);
872  return ret;
873  }
874 
875  /// Destructor.
876  ~VtValue() { _Clear(); }
877 
878  /// Copy assignment from another \a VtValue.
879  VtValue &operator=(VtValue const &other) {
880  if (ARCH_LIKELY(this != &other))
881  _Copy(other, *this);
882  return *this;
883  }
884 
885  /// Move assignment from another \a VtValue.
886  VtValue &operator=(VtValue &&other) noexcept {
887  if (ARCH_LIKELY(this != &other))
888  _Move(other, *this);
889  return *this;
890  }
891 
892  /// Assignment from VtValueRef
893  VT_API
895 
896  /// Assignment operator from any type.
897  template <class T>
898  VtValue &operator=(T const &obj);
899 
900  /// Swap this with \a rhs.
901  VtValue &Swap(VtValue &rhs) noexcept {
902  // Do nothing if both empty. Otherwise general swap.
903  if (!IsEmpty() || !rhs.IsEmpty()) {
904  VtValue tmp;
905  _Move(*this, tmp);
906  _Move(rhs, *this);
907  _Move(tmp, rhs);
908  }
909  return *this;
910  }
911 
912  /// Overloaded swap() for generic code/stl/etc.
913  friend void swap(VtValue &lhs, VtValue &rhs) { lhs.Swap(rhs); }
914 
915  /// Swap the held value with \a rhs. If this value is holding a T, make an
916  /// unqualified call to swap(<held-value>, rhs). If this value is not
917  /// holding a T, replace the held value with a value-initialized T instance
918  /// first, then swap.
919  template <class T>
920  void
921  Swap(T &rhs) {
922  static_assert(std::is_same_v<T, typename Vt_ValueGetStored<T>::Type>,
923  "Can only VtValue::Swap with a type T that stores as T");
924  if (!IsHolding<T>())
925  *this = T();
926  UncheckedSwap(rhs);
927  }
928 
929  /// Swap the held value with \a rhs. This VtValue must be holding an
930  /// object of type \p T. If it does not, this invokes undefined behavior.
931  /// Use Swap() if this VtValue is not known to contain an object of type
932  /// \p T.
933  template <class T>
934  void
935  UncheckedSwap(T &rhs) {
936  static_assert(std::is_same_v<T, typename Vt_ValueGetStored<T>::Type>,
937  "Can only VtValue::Swap with a type T that stores as T");
938  using std::swap;
939  swap(_GetMutable<T>(), rhs);
940  }
941 
942  /// \overload
943  void UncheckedSwap(VtValue &rhs) { Swap(rhs); }
944 
945  /// Make this value empty and return the held \p T instance. If
946  /// this value does not hold a \p T instance, make this value empty and
947  /// return a default-constructed \p T.
948  template <class T>
949  T Remove() {
950  T result;
951  Swap(result);
952  _Clear();
953  return result;
954  }
955 
956  /// Make this value empty and return the held \p T instance. If this
957  /// value does not hold a \p T instance, this method invokes undefined
958  /// behavior.
959  template <class T>
961  T result;
962  UncheckedSwap(result);
963  _Clear();
964  return result;
965  }
966 
967  /// If this value holds an object of type \p T, invoke \p mutateFn, passing
968  /// it a non-const reference to the held object and return true. Otherwise
969  /// do nothing and return false.
970  template <class T, class Fn>
971  bool
972  Mutate(Fn &&mutateFn) {
973  static_assert(std::is_same_v<T, typename Vt_ValueGetStored<T>::Type>,
974  "Can only VtValue::Mutate a type T that stores as T");
975  if (!IsHolding<T>()) {
976  return false;
977  }
978  UncheckedMutate<T>(std::forward<Fn>(mutateFn));
979  return true;
980  }
981 
982  /// Invoke \p mutateFn, passing it a non-const reference to the held object
983  /// which must be of type \p T. If the held object is not of type \p T,
984  /// this function invokes undefined behavior.
985  template <class T, class Fn>
986  void
987  UncheckedMutate(Fn &&mutateFn) {
988  static_assert(std::is_same_v<T, typename Vt_ValueGetStored<T>::Type>,
989  "Can only VtValue::Mutate a type T that stores as T");
990  // We move to a temporary, mutate the temporary, then move back. This
991  // prevents callers from escaping a mutable reference to the held object
992  // via a side-effect of mutateFn.
993  T &stored =_GetMutable<T>();
994  T tmp = std::move(stored);
995  std::forward<Fn>(mutateFn)(tmp);
996  stored = std::move(tmp);
997  }
998 
999  /// Return true if this value is holding an object of type \p T, false
1000  /// otherwise.
1001  template <class T>
1002  bool IsHolding() const {
1003  return _info.GetLiteral() && _TypeIs<T>();
1004  }
1005 
1006  /// Return true if this holds a VtArray instance, false otherwise.
1007  VT_API bool IsArrayValued() const;
1008 
1009  /// Return true if this holds a VtArrayEdit instance, false otherwise.
1010  VT_API bool IsArrayEditValued() const;
1011 
1012  /// Return the number of elements in the held value if IsArrayValued(),
1013  /// return 0 otherwise.
1014  size_t GetArraySize() const { return _GetNumElements(); }
1015 
1016  /// Return the typeid of the type held by this value.
1017  VT_API std::type_info const &GetTypeid() const;
1018 
1019  /// If this value holds a VtArray or VtArrayEdit instance, return the typeid
1020  /// of its element type. For example, if this value holds a VtIntArray or a
1021  /// VtIntArrayEdit, return typeid(int). Otherwise return typeid(void).
1022  VT_API std::type_info const &GetElementTypeid() const;
1023 
1024  /// Returns the TfType of the type held by this value.
1025  VT_API TfType GetType() const;
1026 
1027  /// Return the type name of the held typeid.
1028  VT_API std::string GetTypeName() const;
1029 
1030  /// Return VtKnownValueTypeIndex<T> for the held type T. If this value
1031  /// holds a proxy type, resolve the proxy and return the proxied type's
1032  /// index. If this value is empty or holds a type that is not 'known',
1033  /// return -1.
1035  if (ARCH_UNLIKELY(_IsProxy())) {
1036  return _info->GetProxiedAsVtValue(
1037  _storage).GetKnownValueTypeIndex();
1038  }
1039  return _info.GetLiteral() ? _info->knownTypeIndex : -1;
1040  }
1041 
1042  /// Returns a const reference to the held object if the held object
1043  /// is of type \a T. Invokes undefined behavior otherwise. This is the
1044  /// fastest \a Get() method to use after a successful \a IsHolding() check.
1045  template <class T>
1046  T const &UncheckedGet() const & { return _Get<T>(); }
1047 
1048  /// \overload
1049  /// In case *this is an rvalue, move the held value out and return
1050  /// by value.
1051  template <class T>
1052  T UncheckedGet() && { return UncheckedRemove<T>(); }
1053 
1054  /// Returns a const reference to the held object if the held object
1055  /// is of type \a T. Issues an error and returns a const reference to a
1056  /// default value if the held object is not of type \a T. Use \a IsHolding
1057  /// to verify correct type before calling this function. The default value
1058  /// returned in case of type mismatch is constructed using
1059  /// Vt_DefaultValueFactory<T>. That may be specialized for client types.
1060  /// The default implementation of the default value factory produces a
1061  /// value-initialized T.
1062  template <class T>
1063  T const &Get() const & {
1065 
1066  // In the unlikely case that the types don't match, we obtain a default
1067  // value to return and issue an error via _FailGet.
1068  if (ARCH_UNLIKELY(!IsHolding<T>())) {
1069  return *(static_cast<T const *>(
1070  _FailGet(Factory::Invoke, typeid(T))));
1071  }
1072 
1073  return _Get<T>();
1074  }
1075 
1076  /// \overload
1077  /// In case *this is an rvalue, move the held value out and return
1078  /// by value.
1079  template <class T>
1080  T Get() && {
1082 
1083  // In the unlikely case that the types don't match, we obtain a default
1084  // value to return and issue an error via _FailGet.
1085  if (ARCH_UNLIKELY(!IsHolding<T>())) {
1086  return *(static_cast<T const *>(
1087  _FailGet(Factory::Invoke, typeid(T))));
1088  }
1089 
1090  return UncheckedRemove<T>();
1091  }
1092 
1093  /// Return a copy of the held object if the held object is of type T.
1094  /// Return a copy of the default value \a def otherwise. Note that this
1095  /// always returns a copy, as opposed to \a Get() which always returns a
1096  /// reference.
1097  template <class T>
1098  T GetWithDefault(T const &def = T()) const {
1099  return IsHolding<T>() ? UncheckedGet<T>() : def;
1100  }
1101 
1102  /// Register a cast from VtValue holding From to VtValue holding To.
1103  template <typename From, typename To>
1104  static void RegisterCast(VtValue (*castFn)(VtValue const &)) {
1105  _RegisterCast(typeid(From), typeid(To), castFn);
1106  }
1107 
1108  /// Register a simple cast from VtValue holding From to VtValue
1109  // holding To.
1110  template <typename From, typename To>
1111  static void RegisterSimpleCast() {
1112  _RegisterCast(typeid(From), typeid(To), _SimpleCast<From, To>);
1113  }
1114 
1115  /// Register a two-way cast from VtValue holding From to VtValue
1116  /// holding To.
1117  template <typename From, typename To>
1119  RegisterSimpleCast<From, To>();
1120  RegisterSimpleCast<To, From>();
1121  }
1122 
1123  /// Return a VtValue holding \c val cast to hold T. Return empty VtValue
1124  /// if cast fails.
1125  ///
1126  /// This Cast() function is safe to call in multiple threads as it does
1127  /// not mutate the operant \p val.
1128  ///
1129  /// \sa \ref VtValue_Casting
1130  template <typename T>
1131  static VtValue Cast(VtValue const &val) {
1132  VtValue ret = val;
1133  ret.Cast<T>();
1134  return ret;
1135  }
1136 
1137  /// Return a VtValue holding \c val cast to same type that \c other is
1138  /// holding. Return empty VtValue if cast fails.
1139  ///
1140  /// This Cast() function is safe to call in multiple threads as it does not
1141  /// mutate the operant \p val.
1142  ///
1143  /// \sa \ref VtValue_Casting
1144  VT_API static VtValue
1145  CastToTypeOf(VtValue const &val, VtValue const &other);
1146 
1147  /// Return a VtValue holding \a val cast to \a type. Return empty VtValue
1148  /// if cast fails.
1149  ///
1150  /// This Cast() function is safe to call in multiple threads as it does not
1151  /// mutate the operant \p val.
1152  ///
1153  /// \sa \ref VtValue_Casting
1154  VT_API static VtValue
1155  CastToTypeid(VtValue const &val, std::type_info const &type);
1156 
1157  /// Return if a value of type \a from can be cast to type \a to.
1158  ///
1159  /// \sa \ref VtValue_Casting
1160  static bool CanCastFromTypeidToTypeid(std::type_info const &from,
1161  std::type_info const &to) {
1162  return _CanCast(from, to);
1163  }
1164 
1165  /// Return \c this holding value type cast to T. This value is left
1166  /// empty if the cast fails.
1167  ///
1168  /// \note Since this method mutates this value, it is not safe to invoke on
1169  /// the same VtValue in multiple threads simultaneously.
1170  ///
1171  /// \sa \ref VtValue_Casting
1172  template <typename T>
1174  if (IsHolding<T>())
1175  return *this;
1176  return *this = _PerformCast(typeid(T), *this);
1177  }
1178 
1179  /// Return \c this holding value type cast to same type that
1180  /// \c other is holding. This value is left empty if the cast fails.
1181  ///
1182  /// \note Since this method mutates this value, it is not safe to invoke on
1183  /// the same VtValue in multiple threads simultaneously.
1184  ///
1185  /// \sa \ref VtValue_Casting
1186  VtValue &CastToTypeOf(VtValue const &other) {
1187  return CastToTypeid(other.GetTypeid());
1188  }
1189 
1190  /// Return \c this holding value type cast to \a type. This value is
1191  /// left empty if the cast fails.
1192  ///
1193  /// \note Since this method mutates this value, it is not safe to invoke on
1194  /// the same VtValue in multiple threads simultaneously.
1195  ///
1196  /// \sa \ref VtValue_Casting
1197  VtValue &CastToTypeid(std::type_info const &type) {
1198  if (!TfSafeTypeCompare(GetTypeid(), type)) {
1199  *this = _PerformCast(type, *this);
1200  }
1201  return *this;
1202  }
1203 
1204  /// Return if \c this can be cast to \a T.
1205  ///
1206  /// \sa \ref VtValue_Casting
1207  template <typename T>
1208  bool CanCast() const {
1209  return _CanCast(GetTypeid(), typeid(T));
1210  }
1211 
1212  /// Return if \c this can be cast to \a type.
1213  ///
1214  /// \sa \ref VtValue_Casting
1215  bool CanCastToTypeOf(VtValue const &other) const {
1216  return _CanCast(GetTypeid(), other.GetTypeid());
1217  }
1218 
1219  /// Return if \c this can be cast to \a type.
1220  ///
1221  /// \sa \ref VtValue_Casting
1222  bool CanCastToTypeid(std::type_info const &type) const {
1223  return _CanCast(GetTypeid(), type);
1224  }
1225 
1226  /// Returns true iff this value is empty.
1227  bool IsEmpty() const { return _info.GetLiteral() == 0; }
1228 
1229  /// Return a VtValueRef that refers to the current object held by this
1230  /// VtValue. The returned VtValueRef is invalidated and must not be used
1231  /// after this VtValue is modified or destroyed.
1232  VT_API VtValueRef Ref() const &;
1233 
1234  /// Return a VtValueRef that refers to the current object held by this
1235  /// rvalue VtValue. The returned VtValueRef is invalidated and must not be
1236  /// used after this VtValue is modified or destroyed.
1237  VT_API VtValueRef Ref() &&;
1238 
1239  /// Implicitly convert to VtValueRef.
1240  VT_API operator VtValueRef() const &;
1241 
1242  /// Implicitly convert to an rvalue VtValueRef.
1243  VT_API operator VtValueRef() &&;
1244 
1245  /// Return true if the held object provides a hash implementation.
1246  VT_API bool CanHash() const;
1247 
1248  /// Return a hash code for the held object by calling VtHashValue() on it.
1249  VT_API size_t GetHash() const;
1250 
1251  friend inline size_t hash_value(VtValue const &val) {
1252  return val.GetHash();
1253  }
1254 
1255  /// Return true if this value holds a type that has been declared at compile
1256  /// time to support composing over other types. This is a fast check that
1257  /// can be used to avoid calling `VtValueComposeOver(strong, weak)` if
1258  /// `strong` does not support composing over. Empty VtValue always can
1259  /// compose over.
1260  VT_API bool CanComposeOver() const;
1261 
1262  /// Return true if this value holds a type that has been declared to support
1263  /// value transforms at compile time. This is a fast check that can be used
1264  /// to avoid calling the relatively slower `VtValueTryTransform(obj, xform)`
1265  /// if `obj` does not support transforms at all. Empty VtValue does not
1266  /// support transforms.
1267  VT_API bool CanTransform() const;
1268 
1269  /// Tests for equality.
1270  template <typename T>
1271  friend bool operator == (VtValue const &lhs, T const &rhs) {
1272  typedef typename Vt_ValueGetStored<T>::Type Stored;
1273  return lhs.IsHolding<Stored>() && lhs.UncheckedGet<Stored>() == rhs;
1274  }
1275  template <typename T>
1276  friend bool operator == (T const &lhs, VtValue const &rhs) {
1277  return rhs == lhs;
1278  }
1279 
1280  /// Tests for inequality.
1281  template <typename T>
1282  friend bool operator != (VtValue const &lhs, T const &rhs) {
1283  return !(lhs == rhs);
1284  }
1285  template <typename T>
1286  friend bool operator != (T const &lhs, VtValue const &rhs) {
1287  return !(lhs == rhs);
1288  }
1289 
1290  /// Test two values for equality.
1291  bool operator == (const VtValue &rhs) const {
1292  bool empty = IsEmpty(), rhsEmpty = rhs.IsEmpty();
1293  if (empty || rhsEmpty) {
1294  // Either one or both empty -- only equal if both empty.
1295  return empty == rhsEmpty;
1296  }
1297  if (_info.GetLiteral() == rhs._info.GetLiteral()) {
1298  // Holding identical types -- compare directly.
1299  return _info.Get()->Equal(_storage, rhs._storage);
1300  }
1301  return _EqualityImpl(rhs);
1302  }
1303  bool operator != (const VtValue &rhs) const { return !(*this == rhs); }
1304 
1305  /// Calls through to operator << on the held object.
1306  VT_API friend std::ostream &
1307  operator << (std::ostream &out, const VtValue &self);
1308 
1309 private:
1310  VT_API const Vt_ShapeData* _GetShapeData() const;
1311  VT_API size_t _GetNumElements() const;
1313 
1314  static inline void _Copy(VtValue const &src, VtValue &dst) {
1315  if (src.IsEmpty()) {
1316  dst._Clear();
1317  return;
1318  }
1319 
1320  _HoldAside tmp(&dst);
1321  dst._info = src._info;
1322  if (src._IsLocalAndTriviallyCopyable()) {
1323  dst._storage = src._storage;
1324  } else {
1325  dst._info->CopyInit(src._storage, dst._storage);
1326  }
1327  }
1328 
1329  static inline void _Move(VtValue &src, VtValue &dst) noexcept {
1330  if (src.IsEmpty()) {
1331  dst._Clear();
1332  return;
1333  }
1334 
1335  _HoldAside tmp(&dst);
1336  dst._info = src._info;
1337  if (src._IsLocalAndTriviallyCopyable()) {
1338  dst._storage = src._storage;
1339  } else {
1340  dst._info->Move(src._storage, dst._storage);
1341  }
1342 
1343  src._info.Set(nullptr, 0);
1344  }
1345 
1346  template <class T>
1347  inline bool
1348  _TypeIs() const {
1350  return _info->knownTypeIndex == VtGetKnownValueTypeIndex<T>() ||
1351  ARCH_UNLIKELY(_IsProxy() && _TypeIsImpl(typeid(T)));
1352  }
1353  else {
1354  std::type_info const &t = typeid(T);
1355  return TfSafeTypeCompare(_info->typeInfo, t) ||
1356  ARCH_UNLIKELY(_IsProxy() && _TypeIsImpl(t));
1357  }
1358  }
1359 
1360  VT_API bool _TypeIsImpl(std::type_info const &queriedType) const;
1361 
1362  VT_API bool _EqualityImpl(VtValue const &rhs) const;
1363 
1364  template <class T>
1365  T &
1366  _GetMutable() {
1367  using TypeInfo = _TypeInfoFor<T>;
1368  if constexpr (!VtIsValueProxy<T>::value) {
1369  // The request is not for a proxy type, so if we are holding a
1370  // proxy, collapse it out to the proxied value first.
1371  if (ARCH_UNLIKELY(_IsProxy())) {
1372  *this = _info->GetProxiedAsVtValue(_storage);
1373  }
1374  }
1375  return TypeInfo::GetMutableObj(_storage);
1376  }
1377 
1378  template <class T>
1379  T const &
1380  _Get() const {
1381  using TypeInfo = _TypeInfoFor<T>;
1382  if constexpr (!VtIsValueProxy<T>::value) {
1383  // The request is not for a proxy type, so if we are holding a
1384  // proxy, fetch the underlying proxied object pointer.
1385  if (ARCH_UNLIKELY(_IsProxy())) {
1386  return *static_cast<T const *>(_GetProxiedObjPtr());
1387  }
1388  }
1389  return TypeInfo::GetObj(_storage);
1390  }
1391 
1392  void const *_GetProxiedObjPtr() const {
1393  return _info->GetProxiedObjPtr(_storage);
1394  }
1395 
1396  // Helper invoked in case Get fails. Reports an error and returns a default
1397  // value for \a queryType.
1398  VT_API void const *
1399  _FailGet(Vt_DefaultValueHolder (*factory)(),
1400  std::type_info const &queryType) const;
1401 
1402  inline void _Clear() {
1403  // optimize for local types not to deref _info.
1405 // XXX: http://bug/DEV-16695
1407  if (_info.GetLiteral() && !_IsLocalAndTriviallyCopyable())
1408  _info.Get()->Destroy(_storage);
1410  _info.Set(nullptr, 0);
1411  }
1412 
1413  inline bool _IsLocalAndTriviallyCopyable() const {
1414  unsigned int bits = _info.BitsAs<unsigned int>();
1415  return (bits & (_LocalFlag | _TrivialCopyFlag)) ==
1416  (_LocalFlag | _TrivialCopyFlag);
1417  }
1418 
1419  inline bool _IsProxy() const {
1420  return _info.BitsAs<unsigned int>() & _ProxyFlag;
1421  }
1422 
1423  VT_API static void _RegisterCast(std::type_info const &from,
1424  std::type_info const &to,
1425  VtValue (*castFn)(VtValue const &));
1426 
1427  // Cast \p value to the type \p to. Caller must ensure that val's type is
1428  // not already \p to.
1429  VT_API static VtValue
1430  _PerformCast(std::type_info const &to, VtValue const &val);
1431 
1432  // Return true if \p from == \p to or if there is a registered cast to
1433  // convert VtValues holding \p from to \p to.
1434  VT_API static bool
1435  _CanCast(std::type_info const &from, std::type_info const &to);
1436 
1437  // helper template function for simple casts from From to To.
1438  template <typename From, typename To>
1439  static VtValue _SimpleCast(VtValue const &val) {
1440  return VtValue(To(val.UncheckedGet<From>()));
1441  }
1442 
1443  // This grants friend access to a function in the wrapper file for this
1444  // class. This lets the wrapper reach down into a value to get a
1445  // pxr_boost::python wrapped object corresponding to the held type. This
1446  // facility is necessary to get the python API we want.
1447  friend TfPyObjWrapper
1449 
1450  VT_API TfPyObjWrapper _GetPythonObject() const;
1451 
1452  // This grants friend access to tests. This is necessary to test the
1453  // _GetHeldObjectPtrForDebugger method, which is specifically made private
1454  // in order to restrict its usage to debuggers.
1455  friend struct Vt_ValueTestAccess;
1456 
1457  // Return the address of the held object or nullptr if empty. This function
1458  // is intended for use within debuggers.
1459  VT_API const void *_GetHeldObjectPtrForDebugger() const;
1460 
1461  _Storage _storage;
1463 };
1464 
1465 #ifndef doxygen
1466 
1468  static const Vt_ShapeData* _GetShapeData(const VtValue& value) {
1469  return value._GetShapeData();
1470  }
1471 
1472  static size_t _GetNumElements(const VtValue& value) {
1473  return value._GetNumElements();
1474  }
1475 };
1476 
1477 //
1478 // The Get()/IsHolding routines needs to be special-cased to handle getting a
1479 // VtValue *as* a VtValue.
1480 //
1481 
1482 template <>
1483 inline const VtValue&
1484 VtValue::Get<VtValue>() const & {
1485  return *this;
1486 }
1487 
1488 template <>
1489 inline VtValue
1490 VtValue::Get<VtValue>() && {
1491  return std::move(*this);
1492 }
1493 
1494 template <>
1495 inline const VtValue&
1496 VtValue::UncheckedGet<VtValue>() const & {
1497  return *this;
1498 }
1499 
1500 template <>
1501 inline VtValue
1502 VtValue::UncheckedGet<VtValue>() && {
1503  return std::move(*this);
1504 }
1505 
1506 template <>
1507 inline bool
1508 VtValue::IsHolding<VtValue>() const {
1509  return true;
1510 }
1511 
1512 // Specialize VtValue::IsHolding<void>() to always return false.
1513 template <>
1514 inline bool
1515 VtValue::IsHolding<void>() const {
1516  return false;
1517 }
1518 
1519 #endif // !doxygen
1520 
1522 
1523 // This unusual arrangement of closing the namespace, including valueRef.h, then
1524 // reopening the namespace exists because value.h and valueRef.h are
1525 // interdependent. A similar symmetric construct exists in valueRef.h. If
1526 // value.h is included first, then valueRef.h will be included here. Otherwise
1527 // if valueRef.h is included first then it will have included value.h. Either
1528 // way all the necessary declarations from both types are present prior to the
1529 // appearance of the following defintions.
1530 
1531 #include "pxr/base/vt/valueRef.h"
1532 
1534 
1535 template <class T>
1536 VtValue &
1537 VtValue::operator=(T const &obj)
1538 {
1539  if constexpr (_TypeInfoFor<T>::IsLocal &&
1540  _TypeInfoFor<T>::HasTrivialCopy) {
1541  _Clear();
1542  _Init<T>::Init(this, obj);
1543  return *this;
1544  }
1545  else {
1546  _HoldAside tmp(this);
1547  _Init<T>::Init(this, obj);
1548  return *this;
1549  }
1550 }
1551 
1552 template <>
1553 VtValue &
1554 VtValue::operator=<VtValueRef>(VtValueRef const &obj) = delete;
1555 
1556 VtValueRef
1557 VtValue::_TypeInfo::GetValueRef(_Storage const &storage, bool rvalue) const
1558 {
1559  return _getValueRef(storage, rvalue);
1560 }
1561 
1562 template <class T>
1563 VtValueRef
1564 VtValue::_TypedProxyHelper<T>::GetValueRef(T const &obj)
1565 {
1566  return VtGetProxiedObject(obj);
1567 }
1568 
1569 template <class T>
1570 VtValueRef
1571 VtValue::_ErasedProxyHelper<T>::GetValueRef(T const &obj)
1572 {
1573  return *VtGetErasedProxiedVtValue(obj);
1574 }
1575 
1576 template <class T, class C, class D>
1577 VtValueRef
1578 VtValue::_TypeInfoImpl<T, C, D>
1579 ::_GetValueRef(_Storage const &storage, bool rvalue)
1580 {
1581  if constexpr (!IsProxy) {
1582  // If `rvalue` is true, then this value is not a proxy, and we've been
1583  // called by a non-const member function, so it is safe to cast away
1584  // constness here.
1585  if (rvalue) {
1586  return std::move(GetMutableObj(const_cast<_Storage &>(storage)));
1587  }
1588  }
1589  return ProxyHelper::GetValueRef(GetObj(storage));
1590 }
1591 
1593 
1594 #endif // PXR_BASE_VT_VALUE_H
#define ARCH_LIKELY(x)
Definition: hints.h:29
GLenum query
Definition: glad.h:2772
~VtValue()
Destructor.
Definition: value.h:876
bool CanCast() const
Definition: value.h:1208
GLbitfield flags
Definition: glcorearb.h:1596
Definition: ImfArray.h:45
VtValue & Cast()
Definition: value.h:1173
T const & UncheckedGet() const &
Definition: value.h:1046
STATIC_INLINE size_t Hash(const char *s, size_t len)
Definition: farmhash.h:2099
void UncheckedSwap(T &rhs)
Definition: value.h:935
void TfDelegatedCountIncrement(VdfMask::_BitsImpl *p) noexcept
Definition: mask.h:686
friend TfPyObjWrapper Vt_GetPythonObjectFromHeldValue(VtValue const &self)
static VtValue Take(T &obj)
Definition: value.h:869
void
Definition: png.h:1083
long size() const
Definition: ImfArray.h:90
getFileOption("OpenEXR:storage") storage
Definition: HDK_Image.dox:276
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
VtValue & CastToTypeOf(VtValue const &other)
Definition: value.h:1186
static void RegisterCast(VtValue(*castFn)(VtValue const &))
Register a cast from VtValue holding From to VtValue holding To.
Definition: value.h:1104
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
GLsizei const GLfloat * value
Definition: glcorearb.h:824
static const Vt_ShapeData * _GetShapeData(const VtValue &value)
Definition: value.h:1468
#define ARCH_PRAGMA_POP
Definition: pragmas.h:170
VtValue(T const &obj)
Definition: value.h:841
VT_API bool CanTransform() const
T Get()&&
Definition: value.h:1080
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
size_t GetArraySize() const
Definition: value.h:1014
void UncheckedMutate(Fn &&mutateFn)
Definition: value.h:987
#define VT_API
Definition: api.h:23
IMATH_HOSTDEVICE constexpr bool equal(T1 a, T2 b, T3 t) IMATH_NOEXCEPT
Definition: ImathFun.h:105
VtValue & Swap(VtValue &rhs) noexcept
Swap this with rhs.
Definition: value.h:901
T Remove()
Definition: value.h:949
VT_API bool IsArrayEditValued() const
Return true if this holds a VtArrayEdit instance, false otherwise.
**But if you need a result
Definition: thread.h:622
bool IsEmpty() const
Returns true iff this value is empty.
Definition: value.h:1227
friend struct _HoldAside
Definition: value.h:776
VT_API VtValueRef Ref() const &
static size_t _GetNumElements(const VtValue &value)
Definition: value.h:1472
VtValue(VtValue const &other)
Copy construct with other.
Definition: value.h:826
OutGridT const XformOp bool bool
T const & VtGetProxiedObject(T const &nonProxy)
Definition: traits.h:105
constexpr T * Get() const noexcept
Retrieve the pointer.
bool CanCastToTypeOf(VtValue const &other) const
Definition: value.h:1215
static VT_API VtValue CastToTypeOf(VtValue const &val, VtValue const &other)
T const & Get() const &
Definition: value.h:1063
#define ARCH_UNLIKELY(x)
Definition: hints.h:30
int GetKnownValueTypeIndex() const
Definition: value.h:1034
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
constexpr uintptr_t GetLiteral() const noexcept
static VT_API VtValue CastToTypeid(VtValue const &val, std::type_info const &type)
VT_API bool IsArrayValued() const
Return true if this holds a VtArray instance, false otherwise.
#define ARCH_PRAGMA_PUSH
Definition: pragmas.h:166
GLint ref
Definition: glcorearb.h:124
VT_API std::type_info const & GetElementTypeid() const
void Swap(T &rhs)
Definition: value.h:921
T UncheckedRemove()
Definition: value.h:960
friend bool operator!=(VtValue const &lhs, T const &rhs)
Tests for inequality.
Definition: value.h:1282
void UncheckedSwap(VtValue &rhs)
Definition: value.h:943
typename std::decay< decltype(VtGetProxiedObject(std::declval< T >()))>::type type
Definition: traits.h:114
constexpr Integral BitsAs() const noexcept
Retrieve the stored bits as the integral type Integral.
VT_API bool CanComposeOver() const
static bool CanCastFromTypeidToTypeid(std::type_info const &from, std::type_info const &to)
Definition: value.h:1160
friend bool operator==(VtValue const &lhs, T const &rhs)
Tests for equality.
Definition: value.h:1271
VT_API std::ostream & VtStreamOut(std::vector< VtValue > const &val, std::ostream &)
VtValue(VtValue &&other) noexcept
Move construct with other.
Definition: value.h:831
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
VtValue & operator=(VtValue &&other) noexcept
Move assignment from another VtValue.
Definition: value.h:886
GLdouble t
Definition: glad.h:2397
void Set(T *ptr) noexcept
Set the pointer value to ptr.
VT_API std::type_info const & GetTypeid() const
Return the typeid of the type held by this value.
A trait to detect instantiations of VtArray, specialized in array.h.
Definition: traits.h:22
T UncheckedGet()&&
Definition: value.h:1052
GLenum GLenum dst
Definition: glcorearb.h:1793
VT_API size_t GetHash() const
Return a hash code for the held object by calling VtHashValue() on it.
typename Tf_ConditionalImpl< Cond >::template Type< T, F > TfConditionalType
Definition: meta.h:73
VtValue & operator=(VtValue const &other)
Copy assignment from another VtValue.
Definition: value.h:879
friend size_t hash_value(VtValue const &val)
Definition: value.h:1251
#define ARCH_PRAGMA_MAYBE_UNINITIALIZED
Definition: pragmas.h:186
bool Mutate(Fn &&mutateFn)
Definition: value.h:972
size_t VtHashValue(T const &val)
Definition: hash.h:66
static VtValue Cast(VtValue const &val)
Definition: value.h:1131
bool IsHolding() const
Definition: value.h:1002
auto ptr(T p) -> const void *
Definition: format.h:4331
GLuint GLfloat * val
Definition: glcorearb.h:1608
VT_API std::string GetTypeName() const
Return the type name of the held typeid.
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
friend void swap(VtValue &lhs, VtValue &rhs)
Overloaded swap() for generic code/stl/etc.
Definition: value.h:913
static void RegisterSimpleCast()
Register a simple cast from VtValue holding From to VtValue.
Definition: value.h:1111
friend struct Vt_ValueTestAccess
Definition: value.h:1455
Definition: type.h:47
VtValue & CastToTypeid(std::type_info const &type)
Definition: value.h:1197
PXR_NAMESPACE_OPEN_SCOPE bool TfSafeTypeCompare(const std::type_info &t1, const std::type_info &t2)
VtValue()
Default ctor gives empty VtValue.
Definition: value.h:823
static void RegisterSimpleBidirectionalCast()
Definition: value.h:1118
VT_API friend std::ostream & operator<<(std::ostream &out, const VtValue &self)
Calls through to operator << on the held object.
T GetWithDefault(T const &def=T()) const
Definition: value.h:1098
PXR_NAMESPACE_OPEN_SCOPE constexpr struct TfDelegatedCountIncrementTagType TfDelegatedCountIncrementTag
Definition: value.h:89
bool CanCastToTypeid(std::type_info const &type) const
Definition: value.h:1222
VT_API TfType GetType() const
Returns the TfType of the type held by this value.
VT_API bool CanHash() const
Return true if the held object provides a hash implementation.
void TfDelegatedCountDecrement(VdfMask::_BitsImpl *p) noexcept
Definition: mask.h:703
GLenum src
Definition: glcorearb.h:1793