value.h
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_BASE_VT_VALUE_H
25 #define PXR_BASE_VT_VALUE_H
26 
27 #include "pxr/pxr.h"
28 
29 // XXX: Include pyLock.h after pyObjWrapper.h to work around
30 // Python include ordering issues.
31 #include "pxr/base/tf/pyObjWrapper.h"
32 
33 #include "pxr/base/tf/pyLock.h"
34 
35 #include "pxr/base/arch/demangle.h"
36 #include "pxr/base/arch/hints.h"
37 #include "pxr/base/tf/anyUniquePtr.h"
38 #include "pxr/base/tf/pointerAndBits.h"
41 #include "pxr/base/tf/tf.h"
42 #include "pxr/base/tf/type.h"
43 
44 #include "pxr/base/vt/api.h"
45 #include "pxr/base/vt/hash.h"
46 #include "pxr/base/vt/streamOut.h"
47 #include "pxr/base/vt/traits.h"
48 #include "pxr/base/vt/types.h"
49 
50 #include <boost/intrusive_ptr.hpp>
51 #include <boost/type_traits/has_trivial_assign.hpp>
52 #include <boost/type_traits/has_trivial_constructor.hpp>
53 #include <boost/type_traits/has_trivial_copy.hpp>
54 #include <boost/type_traits/has_trivial_destructor.hpp>
55 
56 #include <iosfwd>
57 #include <typeinfo>
58 #include <type_traits>
59 
60 PXR_NAMESPACE_OPEN_SCOPE
61 
65 template <class T>
66 struct Vt_DefaultValueFactory;
67 
68 // This is a helper class used by Vt_DefaultValueFactory to return a value with
69 // its type erased and only known at runtime via a std::type_info.
70 struct Vt_DefaultValueHolder
71 {
72  // Creates a value-initialized object and stores the type_info for the
73  // static type.
74  template <typename T>
75  static Vt_DefaultValueHolder Create() {
76  return Vt_DefaultValueHolder(TfAnyUniquePtr::New<T>(), typeid(T));
77  }
78 
79  // Creates a copy of the object and stores the type_info for the static
80  // type.
81  template <typename T>
82  static Vt_DefaultValueHolder Create(T const &val) {
83  return Vt_DefaultValueHolder(TfAnyUniquePtr::New(val), typeid(T));
84  }
85 
86  // Return the runtime type of the held object.
87  std::type_info const &GetType() const {
88  return *_type;
89  }
90 
91  // Return a pointer to the held object. This may be safely cast to the
92  // static type corresponding to the type_info returned by GetType.
93  void const *GetPointer() const {
94  return _ptr.Get();
95  }
96 
97 private:
98  Vt_DefaultValueHolder(TfAnyUniquePtr &&ptr, std::type_info const &type)
99  : _ptr(std::move(ptr)), _type(&type) {}
100 
101  TfAnyUniquePtr _ptr;
102  std::type_info const *_type;
103 };
104 
105 class VtValue;
106 
107 // Overload VtStreamOut for vector<VtValue>. Produces output like [value1,
108 // value2, ... valueN].
109 VT_API std::ostream &VtStreamOut(std::vector<VtValue> const &val, std::ostream &);
110 
111 #define VT_VALUE_SET_STORED_TYPE(SRC, DST) \
112  template <> struct Vt_ValueStoredType<SRC> { typedef DST Type; }
113 
114 template <class T> struct Vt_ValueStoredType { typedef T Type; };
115 VT_VALUE_SET_STORED_TYPE(char const *, std::string);
116 VT_VALUE_SET_STORED_TYPE(char *, std::string);
117 
118 #ifdef PXR_PYTHON_SUPPORT_ENABLED
119 VT_VALUE_SET_STORED_TYPE(boost::python::object, TfPyObjWrapper);
120 #endif // PXR_PYTHON_SUPPORT_ENABLED
121 
122 #undef VT_VALUE_SET_STORED_TYPE
123 
124 // A metafunction that gives the type VtValue should store for a given type T.
125 template <class T>
126 struct Vt_ValueGetStored
127  : Vt_ValueStoredType<std::decay_t<T>> {};
128 
166 class VtValue
167 {
168  static const unsigned int _LocalFlag = 1 << 0;
169  static const unsigned int _TrivialCopyFlag = 1 << 1;
170  static const unsigned int _ProxyFlag = 1 << 2;
171 
172  template <class T>
173  struct _Counted {
174  explicit _Counted(T const &obj) : _obj(obj) {
175  _refCount = 0;
176  }
177  bool IsUnique() const { return _refCount == 1; }
178  T const &Get() const { return _obj; }
179  T &GetMutable() { return _obj; }
180 
181  private:
182  T _obj;
183  mutable std::atomic<int> _refCount;
184 
185  friend inline void intrusive_ptr_add_ref(_Counted const *d) {
186  d->_refCount.fetch_add(1, std::memory_order_relaxed);
187  }
188  friend inline void intrusive_ptr_release(_Counted const *d) {
189  if (d->_refCount.fetch_sub(1, std::memory_order_release) == 1) {
190  std::atomic_thread_fence(std::memory_order_acquire);
191  delete d;
192  }
193  }
194  };
195 
196  // Hold objects up to 1 word large locally. This makes the total structure
197  // 16 bytes when compiled 64 bit (1 word type-info pointer, 1 word storage
198  // space).
199  static const size_t _MaxLocalSize = sizeof(void*);
200  typedef std::aligned_storage<
201  /* size */_MaxLocalSize, /* alignment */_MaxLocalSize>::type _Storage;
202 
203  template <class T>
204  using _IsTriviallyCopyable = std::integral_constant<bool,
205  boost::has_trivial_constructor<T>::value &&
206  boost::has_trivial_copy<T>::value &&
207  boost::has_trivial_assign<T>::value &&
208  boost::has_trivial_destructor<T>::value>;
209 
210  // Metafunction that returns true if T should be stored locally, false if it
211  // should be stored remotely.
212  template <class T>
213  using _UsesLocalStore = std::integral_constant<bool,
214  (sizeof(T) <= sizeof(_Storage)) &&
215  VtValueTypeHasCheapCopy<T>::value &&
216  std::is_nothrow_move_constructible<T>::value &&
217  std::is_nothrow_move_assignable<T>::value>;
218 
219  // Type information base class.
220  struct _TypeInfo {
221  private:
222  using _CopyInitFunc = void (*)(_Storage const &, _Storage &);
223  using _DestroyFunc = void (*)(_Storage &);
224  using _MoveFunc = void (*)(_Storage &, _Storage &);
225  using _CanHashFunc = bool (*)(_Storage const &);
226  using _HashFunc = size_t (*)(_Storage const &);
227  using _EqualFunc = bool (*)(_Storage const &, _Storage const &);
228  using _EqualPtrFunc = bool (*)(_Storage const &, void const *);
229  using _MakeMutableFunc = void (*)(_Storage &);
230  using _GetPyObjFunc = TfPyObjWrapper (*)(_Storage const &);
231  using _StreamOutFunc =
232  std::ostream & (*)(_Storage const &, std::ostream &);
233  using _GetTypeidFunc = std::type_info const & (*)(_Storage const &);
234  using _IsArrayValuedFunc = bool (*)(_Storage const &);
235  using _GetElementTypeidFunc =
236  std::type_info const & (*)(_Storage const &);
237  using _GetShapeDataFunc = const Vt_ShapeData* (*)(_Storage const &);
238  using _GetNumElementsFunc = size_t (*)(_Storage const &);
239  using _ProxyHoldsTypeFunc = bool (*)(_Storage const &, std::type_info const &);
240  using _GetProxiedTypeFunc = TfType (*)(_Storage const &);
241  using _GetProxiedTypeidFunc =
242  std::type_info const & (*)(_Storage const &);
243  using _GetProxiedObjPtrFunc = void const *(*)(_Storage const &);
244  using _GetProxiedAsVtValueFunc = VtValue (*)(_Storage const &);
245 
246  protected:
247  constexpr _TypeInfo(const std::type_info &ti,
248  const std::type_info &elementTi,
249  bool isArray,
250  bool isHashable,
251  bool isProxy,
252  _CopyInitFunc copyInit,
253  _DestroyFunc destroy,
254  _MoveFunc move,
255  _CanHashFunc canHash,
256  _HashFunc hash,
257  _EqualFunc equal,
258  _EqualPtrFunc equalPtr,
259  _MakeMutableFunc makeMutable,
260  _GetPyObjFunc getPyObj,
261  _StreamOutFunc streamOut,
262  _GetTypeidFunc getTypeid,
263  _IsArrayValuedFunc isArrayValued,
264  _GetElementTypeidFunc getElementTypeid,
265  _GetShapeDataFunc getShapeData,
266  _GetNumElementsFunc getNumElements,
267  _ProxyHoldsTypeFunc proxyHoldsType,
268  _GetProxiedTypeFunc getProxiedType,
269  _GetProxiedTypeidFunc getProxiedTypeid,
270  _GetProxiedObjPtrFunc getProxiedObjPtr,
271  _GetProxiedAsVtValueFunc getProxiedAsVtValue)
272  : typeInfo(ti)
273  , elementTypeInfo(elementTi)
274  , isProxy(isProxy)
275  , isArray(isArray)
276  , isHashable(isHashable)
277  // Function table
278  , _copyInit(copyInit)
279  , _destroy(destroy)
280  , _move(move)
281  , _canHash(canHash)
282  , _hash(hash)
283  , _equal(equal)
284  , _equalPtr(equalPtr)
285  , _makeMutable(makeMutable)
286  , _getPyObj(getPyObj)
287  , _streamOut(streamOut)
288  , _getTypeid(getTypeid)
289  , _isArrayValued(isArrayValued)
290  , _getElementTypeid(getElementTypeid)
291  , _getShapeData(getShapeData)
292  , _getNumElements(getNumElements)
293  , _proxyHoldsType(proxyHoldsType)
294  , _getProxiedType(getProxiedType)
295  , _getProxiedTypeid(getProxiedTypeid)
296  , _getProxiedObjPtr(getProxiedObjPtr)
297  , _getProxiedAsVtValue(getProxiedAsVtValue)
298  {}
299 
300  public:
301  void CopyInit(_Storage const &src, _Storage &dst) const {
302  _copyInit(src, dst);
303  }
304  void Destroy(_Storage &storage) const {
305  _destroy(storage);
306  }
307  void Move(_Storage &src, _Storage &dst) const noexcept {
308  _move(src, dst);
309  }
310  bool CanHash(_Storage const &storage) const {
311  return _canHash(storage);
312  }
313  size_t Hash(_Storage const &storage) const {
314  return _hash(storage);
315  }
316  bool Equal(_Storage const &lhs, _Storage const &rhs) const {
317  return _equal(lhs, rhs);
318  }
319  bool EqualPtr(_Storage const &lhs, void const *rhs) const {
320  return _equalPtr(lhs, rhs);
321  }
322  void MakeMutable(_Storage &storage) const {
323  _makeMutable(storage);
324  }
325  TfPyObjWrapper GetPyObj(_Storage const &storage) const {
326  return _getPyObj(storage);
327  }
328  std::ostream &StreamOut(_Storage const &storage,
329  std::ostream &out) const {
330  return _streamOut(storage, out);
331  }
332  bool IsArrayValued(_Storage const &storage) const {
333  return _isArrayValued(storage);
334  }
335  std::type_info const &GetElementTypeid(_Storage const &storage) const {
336  return _getElementTypeid(storage);
337  }
338  std::type_info const &GetTypeid(_Storage const &storage) const {
339  return _getTypeid(storage);
340  }
341  const Vt_ShapeData* GetShapeData(_Storage const &storage) const {
342  return _getShapeData(storage);
343  }
344  size_t GetNumElements(_Storage const &storage) const {
345  return _getNumElements(storage);
346  }
347  bool ProxyHoldsType(_Storage const &storage,
348  std::type_info const &t) const {
349  return _proxyHoldsType(storage, t);
350  }
351  TfType GetProxiedType(_Storage const &storage) const {
352  return _getProxiedType(storage);
353  }
354  std::type_info const &GetProxiedTypeid(_Storage const &storage) const {
355  return _getProxiedTypeid(storage);
356  }
357  VtValue GetProxiedAsVtValue(_Storage const &storage) const {
358  return _getProxiedAsVtValue(storage);
359  }
360  void const *GetProxiedObjPtr(_Storage const &storage) const {
361  return _getProxiedObjPtr(storage);
362  }
363 
364  const std::type_info &typeInfo;
365  const std::type_info &elementTypeInfo;
366  bool isProxy;
367  bool isArray;
368  bool isHashable;
369 
370  private:
371  _CopyInitFunc _copyInit;
372  _DestroyFunc _destroy;
373  _MoveFunc _move;
374  _CanHashFunc _canHash;
375  _HashFunc _hash;
376  _EqualFunc _equal;
377  _EqualPtrFunc _equalPtr;
378  _MakeMutableFunc _makeMutable;
379  _GetPyObjFunc _getPyObj;
380  _StreamOutFunc _streamOut;
381  _GetTypeidFunc _getTypeid;
382  _IsArrayValuedFunc _isArrayValued;
383  _GetElementTypeidFunc _getElementTypeid;
384  _GetShapeDataFunc _getShapeData;
385  _GetNumElementsFunc _getNumElements;
386  _ProxyHoldsTypeFunc _proxyHoldsType;
387  _GetProxiedTypeFunc _getProxiedType;
388  _GetProxiedTypeidFunc _getProxiedTypeid;
389  _GetProxiedObjPtrFunc _getProxiedObjPtr;
390  _GetProxiedAsVtValueFunc _getProxiedAsVtValue;
391  };
392 
393  // Type-dispatching overloads.
394 
395  // Array type helper.
396  template <class T, class Enable=void>
397  struct _ArrayHelper
398  {
399  static const Vt_ShapeData* GetShapeData(T const &) { return NULL; }
400  static size_t GetNumElements(T const &) { return 0; }
401  constexpr static std::type_info const &GetElementTypeid() {
402  return typeid(void);
403  }
404  };
405  template <class Array>
406  struct _ArrayHelper<
407  Array, typename std::enable_if<VtIsArray<Array>::value>::type>
408  {
409  static const Vt_ShapeData* GetShapeData(Array const &obj) {
410  return obj._GetShapeData();
411  }
412  static size_t GetNumElements(Array const &obj) {
413  return obj.size();
414  }
415  constexpr static std::type_info const &GetElementTypeid() {
416  return typeid(typename Array::ElementType);
417  }
418  };
419 
420  // Function used in case T has equality comparison.
421  template <class T>
422  static inline auto
423  _TypedProxyEqualityImpl(T const &a, T const &b, int) -> decltype(a == b) {
424  return a == b;
425  }
426  // Function used in case T does not have equality comparison.
427  template <class NoEqual>
428  static inline bool
429  _TypedProxyEqualityImpl(NoEqual const &a, NoEqual const &b, long) {
430  return VtGetProxiedObject(a) == VtGetProxiedObject(b);
431  }
432 
433  template <class T>
434  static inline auto
435  _ErasedProxyEqualityImpl(T const &a, T const &b, int) -> decltype(a == b) {
436  return a == b;
437  }
438  // Function used in case T does not have equality comparison.
439  template <class NoEqual>
440  static inline bool
441  _ErasedProxyEqualityImpl(NoEqual const &a, NoEqual const &b, long) {
442  return *VtGetErasedProxiedVtValue(a) == *VtGetErasedProxiedVtValue(b);
443  }
444 
445  // Proxy type helper. Base case handles non-proxies and typed proxies.
446  template <class T, class Enable = void>
447  struct _ProxyHelper
448  {
449  using ProxiedType = typename VtGetProxiedType<T>::type;
450 
451  static bool CanHash(T const &) { return VtIsHashable<ProxiedType>(); }
452  static size_t Hash(T const &obj) {
453  return VtHashValue(VtGetProxiedObject(obj));
454  }
455  static bool Equal(T const &a, T const &b) {
456  // We use the traditional int/long = 0 arg technique to disambiguate
457  // overloads, so we can invoke equality comparison on the *proxy*
458  // type if it provides one, or if it doesn't then invoke equality
459  // comparison on the *proxied* type instead.
460  return _TypedProxyEqualityImpl(a, b, 0);
461  }
462  static TfPyObjWrapper GetPyObj(T const &obj) {
463 #ifdef PXR_PYTHON_SUPPORT_ENABLED
464  ProxiedType const &p = VtGetProxiedObject(obj);
465  TfPyLock lock;
466  return boost::python::api::object(p);
467 #else
468  return {};
469 #endif //PXR_PYTHON_SUPPORT_ENABLED
470  }
471  static std::ostream &StreamOut(T const &obj, std::ostream &out) {
472  return VtStreamOut(VtGetProxiedObject(obj), out);
473  }
474  static Vt_ShapeData const *GetShapeData(T const &obj) {
475  return _ArrayHelper<ProxiedType>::GetShapeData(
476  VtGetProxiedObject(obj));
477  }
478  static size_t GetNumElements(T const &obj) {
479  return _ArrayHelper<ProxiedType>::GetNumElements(
480  VtGetProxiedObject(obj));
481  }
482  static bool IsArrayValued(T const &) {
484  }
485  static std::type_info const &GetTypeid(T const &) {
486  return typeid(ProxiedType);
487  }
488  static std::type_info const &GetElementTypeid(T const &) {
489  return _ArrayHelper<ProxiedType>::GetElementTypeid();
490  }
491  static VtValue GetProxiedAsVtValue(T const &obj) {
492  return VtValue(VtGetProxiedObject(obj));
493  }
494  static bool HoldsType(T const &tp, std::type_info const &query) {
495  return TfSafeTypeCompare(typeid(ProxiedType), query);
496  }
497  static TfType GetTfType(T const &tp) {
498  return TfType::Find<ProxiedType>();
499  }
500  static void const *GetObjPtr(T const &tp) {
501  return static_cast<void const *>(&VtGetProxiedObject(tp));
502  }
503  };
504 
505  template <class ErasedProxy>
506  struct _ProxyHelper<
507  ErasedProxy, typename std::enable_if<
508  VtIsErasedValueProxy<ErasedProxy>::value>::type>
509  {
510  static bool CanHash(ErasedProxy const &proxy) {
511  return VtGetErasedProxiedVtValue(proxy)->CanHash();
512  }
513  static size_t Hash(ErasedProxy const &proxy) {
514  return VtGetErasedProxiedVtValue(proxy)->GetHash();
515  }
516  static bool Equal(ErasedProxy const &a, ErasedProxy const &b) {
517  // We use the traditional int/long = 0 arg technique to disambiguate
518  // overloads, so we can invoke equality comparison on the *proxy*
519  // type if it provides one, or if it doesn't then invoke equality
520  // comparison on the VtValue containing the *proxied* type instead.
521  return _ErasedProxyEqualityImpl(a, b, 0);
522  }
523  static TfPyObjWrapper GetPyObj(ErasedProxy const &obj) {
524 #ifdef PXR_PYTHON_SUPPORT_ENABLED
525  VtValue const *val = VtGetErasedProxiedVtValue(obj);
526  TfPyLock lock;
527  return boost::python::api::object(*val);
528 #else
529  return {};
530 #endif //PXR_PYTHON_SUPPORT_ENABLED
531  }
532  static std::ostream &
533  StreamOut(ErasedProxy const &obj, std::ostream &out) {
534  return VtStreamOut(obj, out);
535  }
536  static Vt_ShapeData const *GetShapeData(ErasedProxy const &obj) {
537  return VtGetErasedProxiedVtValue(obj)->_GetShapeData();
538  }
539  static size_t GetNumElements(ErasedProxy const &obj) {
540  return VtGetErasedProxiedVtValue(obj)->_GetNumElements();
541  }
542  static bool IsArrayValued(ErasedProxy const &obj) {
543  return VtGetErasedProxiedVtValue(obj)->IsArrayValued();
544  }
545  static std::type_info const &GetTypeid(ErasedProxy const &obj) {
546  return VtGetErasedProxiedVtValue(obj)->GetTypeid();
547  }
548  static std::type_info const &GetElementTypeid(ErasedProxy const &obj) {
549  return VtGetErasedProxiedVtValue(obj)->GetElementTypeid();
550  }
551  static VtValue GetProxiedAsVtValue(ErasedProxy const &ep) {
552  return *VtGetErasedProxiedVtValue(ep);
553  }
554  static bool
555  HoldsType(ErasedProxy const &ep, std::type_info const &query) {
556  return VtErasedProxyHoldsType(ep, query);
557  }
558  static TfType GetTfType(ErasedProxy const &ep) {
559  return VtGetErasedProxiedTfType(ep);
560  }
561  static void const *GetObjPtr(ErasedProxy const &ep) {
562  VtValue const *val = VtGetErasedProxiedVtValue(ep);
563  return val ? val->_GetProxiedObjPtr() : nullptr;
564  }
565  };
566 
567  // _TypeInfo implementation helper. This is a CRTP base that the
568  // _LocalTypeInfo and _RemoteTypeInfo types derive. It wraps their
569  // type-specific implementations with type-generic interfaces.
570  template <class T, class Container, class Derived>
571  struct _TypeInfoImpl : public _TypeInfo
572  {
573  static const bool IsLocal = _UsesLocalStore<T>::value;
574  static const bool HasTrivialCopy = _IsTriviallyCopyable<T>::value;
575  static const bool IsProxy = VtIsValueProxy<T>::value;
576 
577  using ProxyHelper = _ProxyHelper<T>;
578 
579  using This = _TypeInfoImpl;
580 
581  constexpr _TypeInfoImpl()
582  : _TypeInfo(typeid(T),
583  _ArrayHelper<T>::GetElementTypeid(),
585  VtIsHashable<T>(),
586  IsProxy,
587  &This::_CopyInit,
588  &This::_Destroy,
589  &This::_Move,
590  &This::_CanHash,
591  &This::_Hash,
592  &This::_Equal,
593  &This::_EqualPtr,
594  &This::_MakeMutable,
595  &This::_GetPyObj,
596  &This::_StreamOut,
597 
598  &This::_GetTypeid,
599 
600  // Array support.
601  &This::_IsArrayValued,
602  &This::_GetElementTypeid,
603  &This::_GetShapeData,
604  &This::_GetNumElements,
605 
606  // Proxy support.
607  &This::_ProxyHoldsType,
608  &This::_GetProxiedType,
609  &This::_GetProxiedTypeid,
610  &This::_GetProxiedObjPtr,
611  &This::_GetProxiedAsVtValue)
612  {}
613 
615  // Typed API for client use.
616  static T const &GetObj(_Storage const &storage) {
617  return Derived::_GetObj(_Container(storage));
618  }
619 
620  static T &GetMutableObj(_Storage &storage) {
621  return Derived::_GetMutableObj(_Container(storage));
622  }
623 
624  static void CopyInitObj(T const &objSrc, _Storage &dst) {
625  Derived::_PlaceCopy(&_Container(dst), objSrc);
626  }
627 
628  private:
629  static_assert(sizeof(Container) <= sizeof(_Storage),
630  "Container size cannot exceed storage size.");
631 
633  // _TypeInfo interface function implementations.
634  static void _CopyInit(_Storage const &src, _Storage &dst) {
635  new (&_Container(dst)) Container(_Container(src));
636  }
637 
638  static void _Destroy(_Storage &storage) {
639  _Container(storage).~Container();
640  }
641 
642  static bool _CanHash(_Storage const &storage) {
643  return ProxyHelper::CanHash(GetObj(storage));
644  }
645 
646  static size_t _Hash(_Storage const &storage) {
647  return ProxyHelper::Hash(GetObj(storage));
648  }
649 
650  static bool _Equal(_Storage const &lhs, _Storage const &rhs) {
651  // Equal is only ever invoked with an object of this specific type.
652  // That is, we only ever ask a proxy to compare to a proxy; we never
653  // ask a proxy to compare to the proxied object.
654  return ProxyHelper::Equal(GetObj(lhs), GetObj(rhs));
655  }
656 
657  static bool _EqualPtr(_Storage const &lhs, void const *rhs) {
658  // Equal is only ever invoked with an object of this specific type.
659  // That is, we only ever ask a proxy to compare to a proxy; we never
660  // ask a proxy to compare to the proxied object.
661  return ProxyHelper::Equal(
662  GetObj(lhs), *static_cast<T const *>(rhs));
663  }
664 
665  static void _Move(_Storage &src, _Storage &dst) noexcept {
666  new (&_Container(dst)) Container(std::move(_Container(src)));
667  _Destroy(src);
668  }
669 
670  static void _MakeMutable(_Storage &storage) {
671  GetMutableObj(storage);
672  }
673 
674  static TfPyObjWrapper _GetPyObj(_Storage const &storage) {
675  return ProxyHelper::GetPyObj(GetObj(storage));
676  }
677 
678  static std::ostream &_StreamOut(
679  _Storage const &storage, std::ostream &out) {
680  return ProxyHelper::StreamOut(GetObj(storage), out);
681  }
682 
683  static std::type_info const &_GetTypeid(_Storage const &storage) {
684  return ProxyHelper::GetTypeid(GetObj(storage));
685  }
686 
687  static bool _IsArrayValued(_Storage const &storage) {
688  return ProxyHelper::IsArrayValued(GetObj(storage));
689  }
690 
691  static std::type_info const &
692  _GetElementTypeid(_Storage const &storage) {
693  return ProxyHelper::GetElementTypeid(GetObj(storage));
694  }
695 
696  static const Vt_ShapeData* _GetShapeData(_Storage const &storage) {
697  return ProxyHelper::GetShapeData(GetObj(storage));
698  }
699 
700  static size_t _GetNumElements(_Storage const &storage) {
701  return ProxyHelper::GetNumElements(GetObj(storage));
702  }
703 
704  static bool
705  _ProxyHoldsType(_Storage const &storage, std::type_info const &t) {
706  return ProxyHelper::HoldsType(GetObj(storage), t);
707  }
708 
709  static TfType
710  _GetProxiedType(_Storage const &storage) {
711  return ProxyHelper::GetTfType(GetObj(storage));
712  }
713 
714  static std::type_info const &
715  _GetProxiedTypeid(_Storage const &storage) {
716  return ProxyHelper::GetTypeid(GetObj(storage));
717  }
718 
719  static void const *
720  _GetProxiedObjPtr(_Storage const &storage) {
721  return ProxyHelper::GetObjPtr(GetObj(storage));
722  }
723 
724  static VtValue
725  _GetProxiedAsVtValue(_Storage const &storage) {
726  return ProxyHelper::GetProxiedAsVtValue(GetObj(storage));
727  }
728 
730  // Internal helper -- cast type-generic storage to type-specific
731  // container.
732  static Container &_Container(_Storage &storage) {
733  // XXX Will need std::launder in c++17.
734  return *reinterpret_cast<Container *>(&storage);
735  }
736  static Container const &_Container(_Storage const &storage) {
737  // XXX Will need std::launder in c++17.
738  return *reinterpret_cast<Container const *>(&storage);
739  }
740  };
741 
743  // Local-storage type info implementation. The container and the object are
744  // the same -- there is no distinct container.
745  template <class T>
746  struct _LocalTypeInfo : _TypeInfoImpl<
747  T, // type
748  T, // container
749  _LocalTypeInfo<T> // CRTP
750  >
751  {
752  constexpr _LocalTypeInfo()
753  : _TypeInfoImpl<T, T, _LocalTypeInfo<T>>()
754  {}
755 
756  // Get returns object directly.
757  static T &_GetMutableObj(T &obj) { return obj; }
758  static T const &_GetObj(T const &obj) { return obj; }
759  // Place placement new's object directly.
760  static void _PlaceCopy(T *dst, T const &src) { new (dst) T(src); }
761  };
762 
764  // Remote-storage type info implementation. The container is an
765  // intrusive_ptr to an object holder: _Counted<T>.
766  template <class T>
767  struct _RemoteTypeInfo : _TypeInfoImpl<
768  T, // type
769  boost::intrusive_ptr<_Counted<T> >, // container
770  _RemoteTypeInfo<T> // CRTP
771  >
772  {
773  constexpr _RemoteTypeInfo()
774  : _TypeInfoImpl<
775  T, boost::intrusive_ptr<_Counted<T>>, _RemoteTypeInfo<T>>()
776  {}
777 
778  typedef boost::intrusive_ptr<_Counted<T> > Ptr;
779  // Get returns object stored in the pointed-to _Counted<T>.
780  static T &_GetMutableObj(Ptr &ptr) {
781  if (!ptr->IsUnique())
782  ptr.reset(new _Counted<T>(ptr->Get()));
783  return ptr->GetMutable();
784  }
785  static T const &_GetObj(Ptr const &ptr) { return ptr->Get(); }
786  // PlaceCopy() allocates a new _Counted<T> with a copy of the object.
787  static void _PlaceCopy(Ptr *dst, T const &src) {
788  new (dst) Ptr(new _Counted<T>(src));
789  }
790  };
791 
792  // Metafunction that returns the specific _TypeInfo subclass for T.
793  template <class T>
794  struct _TypeInfoFor {
795  // return _UsesLocalStore(T) ? _LocalTypeInfo<T> : _RemoteTypeInfo<T>;
796  typedef std::conditional_t<_UsesLocalStore<T>::value,
797  _LocalTypeInfo<T>,
798  _RemoteTypeInfo<T>> Type;
799  };
800 
801  // Make sure char[N] is treated as a string.
802  template <size_t N>
803  struct _TypeInfoFor<char[N]> : _TypeInfoFor<std::string> {};
804 
805  // Runtime function to return a _TypeInfo base pointer to a specific
806  // _TypeInfo subclass for type T.
807  template <class T>
808  static TfPointerAndBits<const _TypeInfo> GetTypeInfo() {
809  typedef typename _TypeInfoFor<T>::Type TI;
810  static const TI ti;
811  static constexpr unsigned int flags =
812  (TI::IsLocal ? _LocalFlag : 0) |
813  (TI::HasTrivialCopy ? _TrivialCopyFlag : 0) |
814  (TI::IsProxy ? _ProxyFlag : 0);
815  return TfPointerAndBits<const _TypeInfo>(&ti, flags);
816  }
817 
818  // A helper that moves a held value to temporary storage, but keeps it alive
819  // until the _HoldAside object is destroyed. This is used when assigning
820  // over a VtValue that might own the object being assigned. For instance,
821  // if I have a VtValue holding a map<string, VtValue>, and I reassign this
822  // VtValue with one of the elements from the map, we must ensure that the
823  // map isn't destroyed until after the assignment has taken place.
824  friend struct _HoldAside;
825  struct _HoldAside {
826  explicit _HoldAside(VtValue *val)
827  : info((val->IsEmpty() || val->_IsLocalAndTriviallyCopyable())
828  ? static_cast<_TypeInfo const *>(NULL) : val->_info.Get()) {
829  if (info)
830  info->Move(val->_storage, storage);
831  }
832  ~_HoldAside() {
833  if (info)
834  info->Destroy(storage);
835  }
836  _Storage storage;
837  _TypeInfo const *info;
838  };
839 
840  template <class T>
841  std::enable_if_t<
842  std::is_same<T, typename Vt_ValueGetStored<T>::Type>::value>
843  _Init(T const &obj) {
844  _info = GetTypeInfo<T>();
845  typedef typename _TypeInfoFor<T>::Type TypeInfo;
846  TypeInfo::CopyInitObj(obj, _storage);
847  }
848 
849  template <class T>
850  std::enable_if_t<
851  !std::is_same<T, typename Vt_ValueGetStored<T>::Type>::value>
852  _Init(T const &obj) {
853  _Init(typename Vt_ValueGetStored<T>::Type(obj));
854  }
855 
856 public:
857 
859  VtValue() {}
860 
862  VtValue(VtValue const &other) {
863  _Copy(other, *this);
864  }
865 
867  VtValue(VtValue &&other) noexcept {
868  _Move(other, *this);
869  }
870 
876  template <class T>
877  explicit VtValue(T const &obj) {
878  _Init(obj);
879  }
880 
900  template <class T>
901  static VtValue Take(T &obj) {
902  VtValue ret;
903  ret.Swap(obj);
904  return ret;
905  }
906 
908  ~VtValue() { _Clear(); }
909 
911  VtValue &operator=(VtValue const &other) {
912  if (ARCH_LIKELY(this != &other))
913  _Copy(other, *this);
914  return *this;
915  }
916 
918  VtValue &operator=(VtValue &&other) noexcept {
919  if (ARCH_LIKELY(this != &other))
920  _Move(other, *this);
921  return *this;
922  }
923 
924 #ifndef doxygen
925  template <class T>
926  inline
927  std::enable_if_t<
928  _TypeInfoFor<T>::Type::IsLocal &&
929  _TypeInfoFor<T>::Type::HasTrivialCopy,
930  VtValue &>
931  operator=(T obj) {
932  _Clear();
933  _Init(obj);
934  return *this;
935  }
936 #endif
937 
939 #ifdef doxygen
940  template <class T>
941  VtValue&
942  operator=(T const &obj);
943 #else
944  template <class T>
945  std::enable_if_t<
946  !_TypeInfoFor<T>::Type::IsLocal ||
947  !_TypeInfoFor<T>::Type::HasTrivialCopy,
948  VtValue &>
949  operator=(T const &obj) {
950  _HoldAside tmp(this);
951  _Init(obj);
952  return *this;
953  }
954 #endif
955 
957  VtValue &operator=(char const *cstr) {
958  std::string tmp(cstr);
959  _Clear();
960  _Init(tmp);
961  return *this;
962  }
963 
965  VtValue &operator=(char *cstr) {
966  return *this = const_cast<char const *>(cstr);
967  }
968 
970  VtValue &Swap(VtValue &rhs) noexcept {
971  // Do nothing if both empty. Otherwise general swap.
972  if (!IsEmpty() || !rhs.IsEmpty()) {
973  VtValue tmp;
974  _Move(*this, tmp);
975  _Move(rhs, *this);
976  _Move(tmp, rhs);
977  }
978  return *this;
979  }
980 
982  friend void swap(VtValue &lhs, VtValue &rhs) { lhs.Swap(rhs); }
983 
985  // make an unqualified call to swap(<held-value>, rhs). If this value is
986  // not holding a T, replace the held value with a value-initialized T
987  // instance first, then swap.
988 #ifdef doxygen
989  template <class T>
990  void
991  Swap(T &rhs);
992 #else
993  template <class T>
994  std::enable_if_t<
995  std::is_same<T, typename Vt_ValueGetStored<T>::Type>::value>
996  Swap(T &rhs) {
997  if (!IsHolding<T>())
998  *this = T();
999  UncheckedSwap(rhs);
1000  }
1001 #endif
1002 
1007 #ifdef doxygen
1008  template <class T>
1009  void
1010  UncheckedSwap(T &rhs);
1011 #else
1012  template <class T>
1013  std::enable_if_t<
1014  std::is_same<T, typename Vt_ValueGetStored<T>::Type>::value>
1015  UncheckedSwap(T &rhs) {
1016  using std::swap;
1017  swap(_GetMutable<T>(), rhs);
1018  }
1019 #endif
1020 
1022  void UncheckedSwap(VtValue &rhs) { Swap(rhs); }
1023 
1027  template <class T>
1028  T Remove() {
1029  T result;
1030  Swap(result);
1031  _Clear();
1032  return result;
1033  }
1034 
1038  template <class T>
1040  T result;
1041  UncheckedSwap(result);
1042  _Clear();
1043  return result;
1044  }
1045 
1048  template <class T>
1049  bool IsHolding() const {
1050  return _info.GetLiteral() && _TypeIs<T>();
1051  }
1052 
1054  VT_API bool IsArrayValued() const;
1055 
1058  size_t GetArraySize() const { return _GetNumElements(); }
1059 
1061  VT_API std::type_info const &GetTypeid() const;
1062 
1065  VT_API std::type_info const &GetElementTypeid() const;
1066 
1068  VT_API TfType GetType() const;
1069 
1071  VT_API std::string GetTypeName() const;
1072 
1076  template <class T>
1077  T const &UncheckedGet() const & { return _Get<T>(); }
1078 
1081  template <class T>
1082  T UncheckedGet() && { return UncheckedRemove<T>(); }
1083 
1092  template <class T>
1093  T const &Get() const & {
1094  typedef Vt_DefaultValueFactory<T> Factory;
1095 
1096  // In the unlikely case that the types don't match, we obtain a default
1097  // value to return and issue an error via _FailGet.
1098  if (ARCH_UNLIKELY(!IsHolding<T>())) {
1099  return *(static_cast<T const *>(
1100  _FailGet(Factory::Invoke, typeid(T))));
1101  }
1102 
1103  return _Get<T>();
1104  }
1105 
1108  template <class T>
1109  T Get() && {
1110  typedef Vt_DefaultValueFactory<T> Factory;
1111 
1112  // In the unlikely case that the types don't match, we obtain a default
1113  // value to return and issue an error via _FailGet.
1114  if (ARCH_UNLIKELY(!IsHolding<T>())) {
1115  return *(static_cast<T const *>(
1116  _FailGet(Factory::Invoke, typeid(T))));
1117  }
1118 
1119  return UncheckedRemove<T>();
1120  }
1121 
1126  template <class T>
1127  T GetWithDefault(T const &def = T()) const {
1128  return IsHolding<T>() ? UncheckedGet<T>() : def;
1129  }
1130 
1132  template <typename From, typename To>
1133  static void RegisterCast(VtValue (*castFn)(VtValue const &)) {
1134  _RegisterCast(typeid(From), typeid(To), castFn);
1135  }
1136 
1138  // holding To.
1139  template <typename From, typename To>
1140  static void RegisterSimpleCast() {
1141  _RegisterCast(typeid(From), typeid(To), _SimpleCast<From, To>);
1142  }
1143 
1146  template <typename From, typename To>
1148  RegisterSimpleCast<From, To>();
1149  RegisterSimpleCast<To, From>();
1150  }
1151 
1159  template <typename T>
1160  static VtValue Cast(VtValue const &val) {
1161  VtValue ret = val;
1162  return ret.Cast<T>();
1163  }
1164 
1172  VT_API static VtValue
1173  CastToTypeOf(VtValue const &val, VtValue const &other);
1174 
1182  VT_API static VtValue
1183  CastToTypeid(VtValue const &val, std::type_info const &type);
1184 
1188  static bool CanCastFromTypeidToTypeid(std::type_info const &from,
1189  std::type_info const &to) {
1190  return _CanCast(from, to);
1191  }
1192 
1200  template <typename T>
1202  if (IsHolding<T>())
1203  return *this;
1204  return *this = _PerformCast(typeid(T), *this);
1205  }
1206 
1214  VtValue &CastToTypeOf(VtValue const &other) {
1215  return CastToTypeid(other.GetTypeid());
1216  }
1217 
1225  VtValue &CastToTypeid(std::type_info const &type) {
1226  if (!TfSafeTypeCompare(GetTypeid(), type)) {
1227  *this = _PerformCast(type, *this);
1228  }
1229  return *this;
1230  }
1231 
1235  template <typename T>
1236  bool CanCast() const {
1237  return _CanCast(GetTypeid(), typeid(T));
1238  }
1239 
1243  bool CanCastToTypeOf(VtValue const &other) const {
1244  return _CanCast(GetTypeid(), other.GetTypeid());
1245  }
1246 
1250  bool CanCastToTypeid(std::type_info const &type) const {
1251  return _CanCast(GetTypeid(), type);
1252  }
1253 
1255  bool IsEmpty() const { return _info.GetLiteral() == 0; }
1256 
1258  VT_API bool CanHash() const;
1259 
1261  VT_API size_t GetHash() const;
1262 
1263  friend inline size_t hash_value(VtValue const &val) {
1264  return val.GetHash();
1265  }
1266 
1268  template <typename T>
1269  friend bool operator == (VtValue const &lhs, T const &rhs) {
1270  typedef typename Vt_ValueGetStored<T>::Type Stored;
1271  return lhs.IsHolding<Stored>() && lhs.UncheckedGet<Stored>() == rhs;
1272  }
1273  template <typename T>
1274  friend bool operator == (T const &lhs, VtValue const &rhs) {
1275  return rhs == lhs;
1276  }
1277 
1279  template <typename T>
1280  friend bool operator != (VtValue const &lhs, T const &rhs) {
1281  return !(lhs == rhs);
1282  }
1283  template <typename T>
1284  friend bool operator != (T const &lhs, VtValue const &rhs) {
1285  return !(lhs == rhs);
1286  }
1287 
1289  bool operator == (const VtValue &rhs) const {
1290  bool empty = IsEmpty(), rhsEmpty = rhs.IsEmpty();
1291  if (empty || rhsEmpty) {
1292  // Either one or both empty -- only equal if both empty.
1293  return empty == rhsEmpty;
1294  }
1295  if (_info.GetLiteral() == rhs._info.GetLiteral()) {
1296  // Holding identical types -- compare directly.
1297  return _info.Get()->Equal(_storage, rhs._storage);
1298  }
1299  return _EqualityImpl(rhs);
1300  }
1301  bool operator != (const VtValue &rhs) const { return !(*this == rhs); }
1302 
1304  VT_API friend std::ostream &
1305  operator << (std::ostream &out, const VtValue &self);
1306 
1307 private:
1308  VT_API const Vt_ShapeData* _GetShapeData() const;
1309  VT_API size_t _GetNumElements() const;
1310  friend struct Vt_ValueShapeDataAccess;
1311 
1312  static inline void _Copy(VtValue const &src, VtValue &dst) {
1313  if (src.IsEmpty()) {
1314  dst._Clear();
1315  return;
1316  }
1317 
1318  _HoldAside tmp(&dst);
1319  dst._info = src._info;
1320  if (src._IsLocalAndTriviallyCopyable()) {
1321  dst._storage = src._storage;
1322  } else {
1323  dst._info->CopyInit(src._storage, dst._storage);
1324  }
1325  }
1326 
1327  static inline void _Move(VtValue &src, VtValue &dst) noexcept {
1328  if (src.IsEmpty()) {
1329  dst._Clear();
1330  return;
1331  }
1332 
1333  _HoldAside tmp(&dst);
1334  dst._info = src._info;
1335  if (src._IsLocalAndTriviallyCopyable()) {
1336  dst._storage = src._storage;
1337  } else {
1338  dst._info->Move(src._storage, dst._storage);
1339  }
1340 
1341  src._info.Set(nullptr, 0);
1342  }
1343 
1344  template <class T>
1345  inline bool _TypeIs() const {
1346  std::type_info const &t = typeid(T);
1347  bool cmp = TfSafeTypeCompare(_info->typeInfo, t);
1348  return ARCH_UNLIKELY(_IsProxy() && !cmp) ? _TypeIsImpl(t) : cmp;
1349  }
1350 
1351  VT_API bool _TypeIsImpl(std::type_info const &queriedType) const;
1352 
1353  VT_API bool _EqualityImpl(VtValue const &rhs) const;
1354 
1355  template <class Proxy>
1356  std::enable_if_t<VtIsValueProxy<Proxy>::value, Proxy &>
1357  _GetMutable() {
1358  typedef typename _TypeInfoFor<Proxy>::Type TypeInfo;
1359  return TypeInfo::GetMutableObj(_storage);
1360  }
1361 
1362  template <class T>
1363  std::enable_if_t<!VtIsValueProxy<T>::value, T &>
1364  _GetMutable() {
1365  // If we are a proxy, collapse it out to the real value first.
1366  if (ARCH_UNLIKELY(_IsProxy())) {
1367  *this = _info->GetProxiedAsVtValue(_storage);
1368  }
1369  typedef typename _TypeInfoFor<T>::Type TypeInfo;
1370  return TypeInfo::GetMutableObj(_storage);
1371  }
1372 
1373  template <class Proxy>
1374  std::enable_if_t<VtIsValueProxy<Proxy>::value, Proxy const &>
1375  _Get() const {
1376  typedef typename _TypeInfoFor<Proxy>::Type TypeInfo;
1377  return TypeInfo::GetObj(_storage);
1378  }
1379 
1380  template <class T>
1381  std::enable_if_t<!VtIsValueProxy<T>::value, T const &>
1382  _Get() const {
1383  typedef typename _TypeInfoFor<T>::Type TypeInfo;
1384  if (ARCH_UNLIKELY(_IsProxy())) {
1385  return *static_cast<T const *>(_GetProxiedObjPtr());
1386  }
1387  return TypeInfo::GetObj(_storage);
1388  }
1389 
1390  void const *_GetProxiedObjPtr() const {
1391  return _info->GetProxiedObjPtr(_storage);
1392  }
1393 
1394  // Helper invoked in case Get fails. Reports an error and returns a default
1395  // value for \a queryType.
1396  VT_API void const *
1397  _FailGet(Vt_DefaultValueHolder (*factory)(),
1398  std::type_info const &queryType) const;
1399 
1400  inline void _Clear() {
1401  // optimize for local types not to deref _info.
1402  if (_info.GetLiteral() && !_IsLocalAndTriviallyCopyable())
1403  _info.Get()->Destroy(_storage);
1404  _info.Set(nullptr, 0);
1405  }
1406 
1407  inline bool _IsLocalAndTriviallyCopyable() const {
1408  unsigned int bits = _info.BitsAs<unsigned int>();
1409  return (bits & (_LocalFlag | _TrivialCopyFlag)) ==
1410  (_LocalFlag | _TrivialCopyFlag);
1411  }
1412 
1413  inline bool _IsProxy() const {
1414  return _info.BitsAs<unsigned int>() & _ProxyFlag;
1415  }
1416 
1417  VT_API static void _RegisterCast(std::type_info const &from,
1418  std::type_info const &to,
1419  VtValue (*castFn)(VtValue const &));
1420 
1421  // Cast \p value to the type \p to. Caller must ensure that val's type is
1422  // not already \p to.
1423  VT_API static VtValue
1424  _PerformCast(std::type_info const &to, VtValue const &val);
1425 
1426  // Return true if \p from == \p to or if there is a registered cast to
1427  // convert VtValues holding \p from to \p to.
1428  VT_API static bool
1429  _CanCast(std::type_info const &from, std::type_info const &to);
1430 
1431  // helper template function for simple casts from From to To.
1432  template <typename From, typename To>
1433  static VtValue _SimpleCast(VtValue const &val) {
1434  return VtValue(To(val.UncheckedGet<From>()));
1435  }
1436 
1437  // This grants friend access to a function in the wrapper file for this
1438  // class. This lets the wrapper reach down into a value to get a
1439  // boost::python wrapped object corresponding to the held type. This
1440  // facility is necessary to get the python API we want.
1441  friend TfPyObjWrapper
1442  Vt_GetPythonObjectFromHeldValue(VtValue const &self);
1443 
1444  VT_API TfPyObjWrapper _GetPythonObject() const;
1445 
1446  _Storage _storage;
1448 };
1449 
1450 #ifndef doxygen
1451 
1452 struct Vt_ValueShapeDataAccess {
1453  static const Vt_ShapeData* _GetShapeData(const VtValue& value) {
1454  return value._GetShapeData();
1455  }
1456 
1457  static size_t _GetNumElements(const VtValue& value) {
1458  return value._GetNumElements();
1459  }
1460 };
1461 
1465 template <class T>
1466 struct Vt_DefaultValueFactory {
1467  static Vt_DefaultValueHolder Invoke();
1468 };
1469 
1470 template <class T>
1471 inline Vt_DefaultValueHolder
1472 Vt_DefaultValueFactory<T>::Invoke() {
1473  return Vt_DefaultValueHolder::Create<T>();
1474 }
1475 
1476 // For performance reasons, the default constructors for vectors,
1477 // matrices, and quaternions do *not* initialize the data of the
1478 // object. This greatly improves the performance of creating large
1479 // arrays of objects. However, for consistency and to avoid
1480 // errors complaining about uninitialized values, we use VtZero
1481 // to construct zeroed out vectors, matrices, and quaternions by
1482 // explicitly instantiating the factory for these types.
1483 //
1484 #define _VT_DECLARE_ZERO_VALUE_FACTORY(r, unused, elem) \
1485 template <> \
1486 VT_API Vt_DefaultValueHolder Vt_DefaultValueFactory<VT_TYPE(elem)>::Invoke();
1487 
1488 BOOST_PP_SEQ_FOR_EACH(_VT_DECLARE_ZERO_VALUE_FACTORY,
1489  unused,
1490  VT_VEC_VALUE_TYPES
1491  VT_MATRIX_VALUE_TYPES
1492  VT_QUATERNION_VALUE_TYPES
1493  VT_DUALQUATERNION_VALUE_TYPES)
1494 
1495 #undef _VT_DECLARE_ZERO_VALUE_FACTORY
1496 
1497 //
1498 // The Get()/IsHolding routines needs to be special-cased to handle getting a
1499 // VtValue *as* a VtValue.
1500 //
1501 
1502 template <>
1503 inline const VtValue&
1504 VtValue::Get<VtValue>() const & {
1505  return *this;
1506 }
1507 
1508 template <>
1509 inline VtValue
1510 VtValue::Get<VtValue>() && {
1511  return std::move(*this);
1512 }
1513 
1514 template <>
1515 inline const VtValue&
1516 VtValue::UncheckedGet<VtValue>() const & {
1517  return *this;
1518 }
1519 
1520 template <>
1521 inline VtValue
1522 VtValue::UncheckedGet<VtValue>() && {
1523  return std::move(*this);
1524 }
1525 
1526 template <>
1527 inline bool
1528 VtValue::IsHolding<VtValue>() const {
1529  return true;
1530 }
1531 
1532 // Specialize VtValue::IsHolding<void>() to always return false.
1533 template <>
1534 inline bool
1535 VtValue::IsHolding<void>() const {
1536  return false;
1537 }
1538 
1539 
1540 
1541 #endif // !doxygen
1542 
1543 PXR_NAMESPACE_CLOSE_SCOPE
1544 
1545 #endif // PXR_BASE_VT_VALUE_H
size_t GetArraySize() const
Return the number of elements in the held value if IsArrayValued(), return 0 otherwise.
Definition: value.h:1058
static void RegisterSimpleBidirectionalCast()
Register a two-way cast from VtValue holding From to VtValue holding To.
Definition: value.h:1147
constexpr T * Get() const noexcept
Retrieve the pointer.
Safely compare C++ RTTI type structures.
VtValue(VtValue &&other) noexcept
Move construct with other.
Definition: value.h:867
~VtValue()
Destructor.
Definition: value.h:908
T const & UncheckedGet() const &
Returns a const reference to the held object if the held object is of type T.
Definition: value.h:1077
VtValue & operator=(char const *cstr)
Assigning a char const * gives a VtValue holding a std::string.
Definition: value.h:957
VtValue & Cast()
Return this holding value type cast to T.
Definition: value.h:1201
Definitions of basic string utilities in tf.
VT_API std::string GetTypeName() const
Return the type name of the held typeid.
bool CanCastToTypeOf(VtValue const &other) const
Return if this can be cast to type.
Definition: value.h:1243
void UncheckedSwap(T &rhs)
Swap the held value with rhs.
constexpr uintptr_t GetLiteral() const noexcept
Retrieve the raw underlying value.
Compiler hints.
VtValue(VtValue const &other)
Copy construct with other.
Definition: value.h:862
VT_API bool CanHash() const
Return true if the held object provides a hash implementation.
T UncheckedRemove()
Make this value empty and return the held T instance.
Definition: value.h:1039
Demangle C++ typenames generated by the typeid() facility.
static void RegisterSimpleCast()
Register a simple cast from VtValue holding From to VtValue.
Definition: value.h:1140
static VT_API VtValue CastToTypeOf(VtValue const &val, VtValue const &other)
Return a VtValue holding val cast to same type that other is holding.
static bool CanCastFromTypeidToTypeid(std::type_info const &from, std::type_info const &to)
Return if a value of type from can be cast to type to.
Definition: value.h:1188
VtValue & CastToTypeOf(VtValue const &other)
Return this holding value type cast to same type that other is holding.
Definition: value.h:1214
static VtValue Take(T &obj)
Create a new VtValue, taking its contents from obj.
Definition: value.h:901
VT_API std::type_info const & GetTypeid() const
Returns the typeid of the type held by this value.
Convenience class for accessing the Python Global Interpreter Lock.
Definition: pyLock.h:122
void swap(UsdStageLoadRules &l, UsdStageLoadRules &r)
Swap the contents of rules l and r.
bool IsEmpty() const
Returns true iff this value is empty.
Definition: value.h:1255
friend bool operator==(VtValue const &lhs, T const &rhs)
Tests for equality.
Definition: value.h:1269
VT_API bool IsArrayValued() const
Returns true iff this is holding an array type (see VtIsArray<>).
static VtValue Cast(VtValue const &val)
Return a VtValue holding val cast to hold T.
Definition: value.h:1160
VtValue & operator=(VtValue &&other) noexcept
Move assignment from another VtValue.
Definition: value.h:918
static VT_API VtValue CastToTypeid(VtValue const &val, std::type_info const &type)
Return a VtValue holding val cast to type.
T const & Get() const &
Returns a const reference to the held object if the held object is of type T.
Definition: value.h:1093
Defines all the types "TYPED" for which Vt creates a VtTYPEDArray typedef.
A simple type-erased container that provides only destruction, moves and immutable,...
Definition: anyUniquePtr.h:43
Array concept. By default, types are not arrays.
Definition: traits.h:41
static void RegisterCast(VtValue(*castFn)(VtValue const &))
Register a cast from VtValue holding From to VtValue holding To.
Definition: value.h:1133
VtValue & operator=(char *cstr)
Assigning a char * gives a VtValue holding a std::string.
Definition: value.h:965
Boost Python object wrapper.
Definition: pyObjWrapper.h:91
VT_API std::type_info const & GetElementTypeid() const
Return the typeid of elements in a array valued type.
VtValue(T const &obj)
Construct a VtValue holding a copy of obj.
Definition: value.h:877
bool CanCast() const
Return if this can be cast to T.
Definition: value.h:1236
VtValue & Swap(VtValue &rhs) noexcept
Swap this with rhs.
Definition: value.h:970
VT_API size_t GetHash() const
Return a hash code for the held object by calling VtHashValue() on it.
void UncheckedSwap(VtValue &rhs)
Definition: value.h:1022
friend void swap(VtValue &lhs, VtValue &rhs)
Overloaded swap() for generic code/stl/etc.
Definition: value.h:982
bool CanCastToTypeid(std::type_info const &type) const
Return if this can be cast to type.
Definition: value.h:1250
T GetWithDefault(T const &def=T()) const
Return a copy of the held object if the held object is of type T.
Definition: value.h:1127
TfType represents a dynamic runtime type.
Definition: type.h:64
constexpr Integral BitsAs() const noexcept
Retrieve the stored bits as the integral type Integral.
friend bool operator !=(VtValue const &lhs, T const &rhs)
Tests for inequality.
Definition: value.h:1280
void Set(T *ptr) noexcept
Set the pointer value to ptr.
VtValue & CastToTypeid(std::type_info const &type)
Return this holding value type cast to type.
Definition: value.h:1225
VT_API friend std::ostream & operator<<(std::ostream &out, const VtValue &self)
Calls through to operator << on the held object.
VtValue()
Default ctor gives empty VtValue.
Definition: value.h:859
T Remove()
Make this value empty and return the held T instance.
Definition: value.h:1028
bool IsHolding() const
Return true if this value is holding an object of type T, false otherwise.
Definition: value.h:1049
VT_API TfType GetType() const
Returns the TfType of the type held by this value.
Provides a container which may hold any type, and provides introspection and iteration over array typ...
Definition: value.h:166
A file containing basic constants and definitions.
VtValue & operator=(VtValue const &other)
Copy assignment from another VtValue.
Definition: value.h:911
bool TfSafeTypeCompare(const std::type_info &t1, const std::type_info &t2)
Safely compare std::type_info structures.