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  int knownTypeIndex,
250  bool isArray,
251  bool isHashable,
252  bool isProxy,
253  _CopyInitFunc copyInit,
254  _DestroyFunc destroy,
255  _MoveFunc move,
256  _CanHashFunc canHash,
257  _HashFunc hash,
258  _EqualFunc equal,
259  _EqualPtrFunc equalPtr,
260  _MakeMutableFunc makeMutable,
261  _GetPyObjFunc getPyObj,
262  _StreamOutFunc streamOut,
263  _GetTypeidFunc getTypeid,
264  _IsArrayValuedFunc isArrayValued,
265  _GetElementTypeidFunc getElementTypeid,
266  _GetShapeDataFunc getShapeData,
267  _GetNumElementsFunc getNumElements,
268  _ProxyHoldsTypeFunc proxyHoldsType,
269  _GetProxiedTypeFunc getProxiedType,
270  _GetProxiedTypeidFunc getProxiedTypeid,
271  _GetProxiedObjPtrFunc getProxiedObjPtr,
272  _GetProxiedAsVtValueFunc getProxiedAsVtValue)
273  : typeInfo(ti)
274  , elementTypeInfo(elementTi)
275  , knownTypeIndex(knownTypeIndex)
276  , isProxy(isProxy)
277  , isArray(isArray)
278  , isHashable(isHashable)
279  // Function table
280  , _copyInit(copyInit)
281  , _destroy(destroy)
282  , _move(move)
283  , _canHash(canHash)
284  , _hash(hash)
285  , _equal(equal)
286  , _equalPtr(equalPtr)
287  , _makeMutable(makeMutable)
288  , _getPyObj(getPyObj)
289  , _streamOut(streamOut)
290  , _getTypeid(getTypeid)
291  , _isArrayValued(isArrayValued)
292  , _getElementTypeid(getElementTypeid)
293  , _getShapeData(getShapeData)
294  , _getNumElements(getNumElements)
295  , _proxyHoldsType(proxyHoldsType)
296  , _getProxiedType(getProxiedType)
297  , _getProxiedTypeid(getProxiedTypeid)
298  , _getProxiedObjPtr(getProxiedObjPtr)
299  , _getProxiedAsVtValue(getProxiedAsVtValue)
300  {}
301 
302  public:
303  void CopyInit(_Storage const &src, _Storage &dst) const {
304  _copyInit(src, dst);
305  }
306  void Destroy(_Storage &storage) const {
307  _destroy(storage);
308  }
309  void Move(_Storage &src, _Storage &dst) const noexcept {
310  _move(src, dst);
311  }
312  bool CanHash(_Storage const &storage) const {
313  return _canHash(storage);
314  }
315  size_t Hash(_Storage const &storage) const {
316  return _hash(storage);
317  }
318  bool Equal(_Storage const &lhs, _Storage const &rhs) const {
319  return _equal(lhs, rhs);
320  }
321  bool EqualPtr(_Storage const &lhs, void const *rhs) const {
322  return _equalPtr(lhs, rhs);
323  }
324  void MakeMutable(_Storage &storage) const {
325  _makeMutable(storage);
326  }
327  TfPyObjWrapper GetPyObj(_Storage const &storage) const {
328  return _getPyObj(storage);
329  }
330  std::ostream &StreamOut(_Storage const &storage,
331  std::ostream &out) const {
332  return _streamOut(storage, out);
333  }
334  bool IsArrayValued(_Storage const &storage) const {
335  return _isArrayValued(storage);
336  }
337  std::type_info const &GetElementTypeid(_Storage const &storage) const {
338  return _getElementTypeid(storage);
339  }
340  std::type_info const &GetTypeid(_Storage const &storage) const {
341  return _getTypeid(storage);
342  }
343  const Vt_ShapeData* GetShapeData(_Storage const &storage) const {
344  return _getShapeData(storage);
345  }
346  size_t GetNumElements(_Storage const &storage) const {
347  return _getNumElements(storage);
348  }
349  bool ProxyHoldsType(_Storage const &storage,
350  std::type_info const &t) const {
351  return _proxyHoldsType(storage, t);
352  }
353  TfType GetProxiedType(_Storage const &storage) const {
354  return _getProxiedType(storage);
355  }
356  std::type_info const &GetProxiedTypeid(_Storage const &storage) const {
357  return _getProxiedTypeid(storage);
358  }
359  VtValue GetProxiedAsVtValue(_Storage const &storage) const {
360  return _getProxiedAsVtValue(storage);
361  }
362  void const *GetProxiedObjPtr(_Storage const &storage) const {
363  return _getProxiedObjPtr(storage);
364  }
365 
366  const std::type_info &typeInfo;
367  const std::type_info &elementTypeInfo;
368  int knownTypeIndex;
369  bool isProxy;
370  bool isArray;
371  bool isHashable;
372 
373  private:
374  _CopyInitFunc _copyInit;
375  _DestroyFunc _destroy;
376  _MoveFunc _move;
377  _CanHashFunc _canHash;
378  _HashFunc _hash;
379  _EqualFunc _equal;
380  _EqualPtrFunc _equalPtr;
381  _MakeMutableFunc _makeMutable;
382  _GetPyObjFunc _getPyObj;
383  _StreamOutFunc _streamOut;
384  _GetTypeidFunc _getTypeid;
385  _IsArrayValuedFunc _isArrayValued;
386  _GetElementTypeidFunc _getElementTypeid;
387  _GetShapeDataFunc _getShapeData;
388  _GetNumElementsFunc _getNumElements;
389  _ProxyHoldsTypeFunc _proxyHoldsType;
390  _GetProxiedTypeFunc _getProxiedType;
391  _GetProxiedTypeidFunc _getProxiedTypeid;
392  _GetProxiedObjPtrFunc _getProxiedObjPtr;
393  _GetProxiedAsVtValueFunc _getProxiedAsVtValue;
394  };
395 
396  // Type-dispatching overloads.
397 
398  // Array type helper.
399  template <class T, class Enable=void>
400  struct _ArrayHelper
401  {
402  static const Vt_ShapeData* GetShapeData(T const &) { return NULL; }
403  static size_t GetNumElements(T const &) { return 0; }
404  constexpr static std::type_info const &GetElementTypeid() {
405  return typeid(void);
406  }
407  };
408  template <class Array>
409  struct _ArrayHelper<
410  Array, typename std::enable_if<VtIsArray<Array>::value>::type>
411  {
412  static const Vt_ShapeData* GetShapeData(Array const &obj) {
413  return obj._GetShapeData();
414  }
415  static size_t GetNumElements(Array const &obj) {
416  return obj.size();
417  }
418  constexpr static std::type_info const &GetElementTypeid() {
419  return typeid(typename Array::ElementType);
420  }
421  };
422 
423  // Function used in case T has equality comparison.
424  template <class T>
425  static inline auto
426  _TypedProxyEqualityImpl(T const &a, T const &b, int) -> decltype(a == b) {
427  return a == b;
428  }
429  // Function used in case T does not have equality comparison.
430  template <class NoEqual>
431  static inline bool
432  _TypedProxyEqualityImpl(NoEqual const &a, NoEqual const &b, long) {
433  return VtGetProxiedObject(a) == VtGetProxiedObject(b);
434  }
435 
436  template <class T>
437  static inline auto
438  _ErasedProxyEqualityImpl(T const &a, T const &b, int) -> decltype(a == b) {
439  return a == b;
440  }
441  // Function used in case T does not have equality comparison.
442  template <class NoEqual>
443  static inline bool
444  _ErasedProxyEqualityImpl(NoEqual const &a, NoEqual const &b, long) {
445  return *VtGetErasedProxiedVtValue(a) == *VtGetErasedProxiedVtValue(b);
446  }
447 
448  // Proxy type helper. Base case handles non-proxies and typed proxies.
449  template <class T, class Enable = void>
450  struct _ProxyHelper
451  {
452  using ProxiedType = typename VtGetProxiedType<T>::type;
453 
454  static bool CanHash(T const &) { return VtIsHashable<ProxiedType>(); }
455  static size_t Hash(T const &obj) {
456  return VtHashValue(VtGetProxiedObject(obj));
457  }
458  static bool Equal(T const &a, T const &b) {
459  // We use the traditional int/long = 0 arg technique to disambiguate
460  // overloads, so we can invoke equality comparison on the *proxy*
461  // type if it provides one, or if it doesn't then invoke equality
462  // comparison on the *proxied* type instead.
463  return _TypedProxyEqualityImpl(a, b, 0);
464  }
465  static TfPyObjWrapper GetPyObj(T const &obj) {
466 #ifdef PXR_PYTHON_SUPPORT_ENABLED
467  ProxiedType const &p = VtGetProxiedObject(obj);
468  TfPyLock lock;
469  return boost::python::api::object(p);
470 #else
471  return {};
472 #endif //PXR_PYTHON_SUPPORT_ENABLED
473  }
474  static std::ostream &StreamOut(T const &obj, std::ostream &out) {
475  return VtStreamOut(VtGetProxiedObject(obj), out);
476  }
477  static Vt_ShapeData const *GetShapeData(T const &obj) {
478  return _ArrayHelper<ProxiedType>::GetShapeData(
479  VtGetProxiedObject(obj));
480  }
481  static size_t GetNumElements(T const &obj) {
482  return _ArrayHelper<ProxiedType>::GetNumElements(
483  VtGetProxiedObject(obj));
484  }
485  static bool IsArrayValued(T const &) {
487  }
488  static std::type_info const &GetTypeid(T const &) {
489  return typeid(ProxiedType);
490  }
491  static std::type_info const &GetElementTypeid(T const &) {
492  return _ArrayHelper<ProxiedType>::GetElementTypeid();
493  }
494  static VtValue GetProxiedAsVtValue(T const &obj) {
495  return VtValue(VtGetProxiedObject(obj));
496  }
497  static bool HoldsType(T const &tp, std::type_info const &query) {
498  return TfSafeTypeCompare(typeid(ProxiedType), query);
499  }
500  static TfType GetTfType(T const &tp) {
501  return TfType::Find<ProxiedType>();
502  }
503  static void const *GetObjPtr(T const &tp) {
504  return static_cast<void const *>(&VtGetProxiedObject(tp));
505  }
506  };
507 
508  template <class ErasedProxy>
509  struct _ProxyHelper<
510  ErasedProxy, typename std::enable_if<
511  VtIsErasedValueProxy<ErasedProxy>::value>::type>
512  {
513  static bool CanHash(ErasedProxy const &proxy) {
514  return VtGetErasedProxiedVtValue(proxy)->CanHash();
515  }
516  static size_t Hash(ErasedProxy const &proxy) {
517  return VtGetErasedProxiedVtValue(proxy)->GetHash();
518  }
519  static bool Equal(ErasedProxy const &a, ErasedProxy const &b) {
520  // We use the traditional int/long = 0 arg technique to disambiguate
521  // overloads, so we can invoke equality comparison on the *proxy*
522  // type if it provides one, or if it doesn't then invoke equality
523  // comparison on the VtValue containing the *proxied* type instead.
524  return _ErasedProxyEqualityImpl(a, b, 0);
525  }
526  static TfPyObjWrapper GetPyObj(ErasedProxy const &obj) {
527 #ifdef PXR_PYTHON_SUPPORT_ENABLED
528  VtValue const *val = VtGetErasedProxiedVtValue(obj);
529  TfPyLock lock;
530  return boost::python::api::object(*val);
531 #else
532  return {};
533 #endif //PXR_PYTHON_SUPPORT_ENABLED
534  }
535  static std::ostream &
536  StreamOut(ErasedProxy const &obj, std::ostream &out) {
537  return VtStreamOut(obj, out);
538  }
539  static Vt_ShapeData const *GetShapeData(ErasedProxy const &obj) {
540  return VtGetErasedProxiedVtValue(obj)->_GetShapeData();
541  }
542  static size_t GetNumElements(ErasedProxy const &obj) {
543  return VtGetErasedProxiedVtValue(obj)->_GetNumElements();
544  }
545  static bool IsArrayValued(ErasedProxy const &obj) {
546  return VtGetErasedProxiedVtValue(obj)->IsArrayValued();
547  }
548  static std::type_info const &GetTypeid(ErasedProxy const &obj) {
549  return VtGetErasedProxiedVtValue(obj)->GetTypeid();
550  }
551  static std::type_info const &GetElementTypeid(ErasedProxy const &obj) {
552  return VtGetErasedProxiedVtValue(obj)->GetElementTypeid();
553  }
554  static VtValue GetProxiedAsVtValue(ErasedProxy const &ep) {
555  return *VtGetErasedProxiedVtValue(ep);
556  }
557  static bool
558  HoldsType(ErasedProxy const &ep, std::type_info const &query) {
559  return VtErasedProxyHoldsType(ep, query);
560  }
561  static TfType GetTfType(ErasedProxy const &ep) {
562  return VtGetErasedProxiedTfType(ep);
563  }
564  static void const *GetObjPtr(ErasedProxy const &ep) {
565  VtValue const *val = VtGetErasedProxiedVtValue(ep);
566  return val ? val->_GetProxiedObjPtr() : nullptr;
567  }
568  };
569 
570  // _TypeInfo implementation helper. This is a CRTP base that the
571  // _LocalTypeInfo and _RemoteTypeInfo types derive. It wraps their
572  // type-specific implementations with type-generic interfaces.
573  template <class T, class Container, class Derived>
574  struct _TypeInfoImpl : public _TypeInfo
575  {
576  static const bool IsLocal = _UsesLocalStore<T>::value;
577  static const bool HasTrivialCopy = _IsTriviallyCopyable<T>::value;
578  static const bool IsProxy = VtIsValueProxy<T>::value;
579 
580  using ProxyHelper = _ProxyHelper<T>;
581 
582  using This = _TypeInfoImpl;
583 
584  constexpr _TypeInfoImpl()
585  : _TypeInfo(typeid(T),
586  _ArrayHelper<T>::GetElementTypeid(),
587  Vt_KnownValueTypeDetail::GetIndex<T>(),
589  VtIsHashable<T>(),
590  IsProxy,
591  &This::_CopyInit,
592  &This::_Destroy,
593  &This::_Move,
594  &This::_CanHash,
595  &This::_Hash,
596  &This::_Equal,
597  &This::_EqualPtr,
598  &This::_MakeMutable,
599  &This::_GetPyObj,
600  &This::_StreamOut,
601 
602  &This::_GetTypeid,
603 
604  // Array support.
605  &This::_IsArrayValued,
606  &This::_GetElementTypeid,
607  &This::_GetShapeData,
608  &This::_GetNumElements,
609 
610  // Proxy support.
611  &This::_ProxyHoldsType,
612  &This::_GetProxiedType,
613  &This::_GetProxiedTypeid,
614  &This::_GetProxiedObjPtr,
615  &This::_GetProxiedAsVtValue)
616  {}
617 
619  // Typed API for client use.
620  static T const &GetObj(_Storage const &storage) {
621  return Derived::_GetObj(_Container(storage));
622  }
623 
624  static T &GetMutableObj(_Storage &storage) {
625  return Derived::_GetMutableObj(_Container(storage));
626  }
627 
628  static void CopyInitObj(T const &objSrc, _Storage &dst) {
629  Derived::_PlaceCopy(&_Container(dst), objSrc);
630  }
631 
632  private:
633  static_assert(sizeof(Container) <= sizeof(_Storage),
634  "Container size cannot exceed storage size.");
635 
637  // _TypeInfo interface function implementations.
638  static void _CopyInit(_Storage const &src, _Storage &dst) {
639  new (&_Container(dst)) Container(_Container(src));
640  }
641 
642  static void _Destroy(_Storage &storage) {
643  _Container(storage).~Container();
644  }
645 
646  static bool _CanHash(_Storage const &storage) {
647  return ProxyHelper::CanHash(GetObj(storage));
648  }
649 
650  static size_t _Hash(_Storage const &storage) {
651  return ProxyHelper::Hash(GetObj(storage));
652  }
653 
654  static bool _Equal(_Storage const &lhs, _Storage const &rhs) {
655  // Equal is only ever invoked with an object of this specific type.
656  // That is, we only ever ask a proxy to compare to a proxy; we never
657  // ask a proxy to compare to the proxied object.
658  return ProxyHelper::Equal(GetObj(lhs), GetObj(rhs));
659  }
660 
661  static bool _EqualPtr(_Storage const &lhs, void const *rhs) {
662  // Equal is only ever invoked with an object of this specific type.
663  // That is, we only ever ask a proxy to compare to a proxy; we never
664  // ask a proxy to compare to the proxied object.
665  return ProxyHelper::Equal(
666  GetObj(lhs), *static_cast<T const *>(rhs));
667  }
668 
669  static void _Move(_Storage &src, _Storage &dst) noexcept {
670  new (&_Container(dst)) Container(std::move(_Container(src)));
671  _Destroy(src);
672  }
673 
674  static void _MakeMutable(_Storage &storage) {
675  GetMutableObj(storage);
676  }
677 
678  static TfPyObjWrapper _GetPyObj(_Storage const &storage) {
679  return ProxyHelper::GetPyObj(GetObj(storage));
680  }
681 
682  static std::ostream &_StreamOut(
683  _Storage const &storage, std::ostream &out) {
684  return ProxyHelper::StreamOut(GetObj(storage), out);
685  }
686 
687  static std::type_info const &_GetTypeid(_Storage const &storage) {
688  return ProxyHelper::GetTypeid(GetObj(storage));
689  }
690 
691  static bool _IsArrayValued(_Storage const &storage) {
692  return ProxyHelper::IsArrayValued(GetObj(storage));
693  }
694 
695  static std::type_info const &
696  _GetElementTypeid(_Storage const &storage) {
697  return ProxyHelper::GetElementTypeid(GetObj(storage));
698  }
699 
700  static const Vt_ShapeData* _GetShapeData(_Storage const &storage) {
701  return ProxyHelper::GetShapeData(GetObj(storage));
702  }
703 
704  static size_t _GetNumElements(_Storage const &storage) {
705  return ProxyHelper::GetNumElements(GetObj(storage));
706  }
707 
708  static bool
709  _ProxyHoldsType(_Storage const &storage, std::type_info const &t) {
710  return ProxyHelper::HoldsType(GetObj(storage), t);
711  }
712 
713  static TfType
714  _GetProxiedType(_Storage const &storage) {
715  return ProxyHelper::GetTfType(GetObj(storage));
716  }
717 
718  static std::type_info const &
719  _GetProxiedTypeid(_Storage const &storage) {
720  return ProxyHelper::GetTypeid(GetObj(storage));
721  }
722 
723  static void const *
724  _GetProxiedObjPtr(_Storage const &storage) {
725  return ProxyHelper::GetObjPtr(GetObj(storage));
726  }
727 
728  static VtValue
729  _GetProxiedAsVtValue(_Storage const &storage) {
730  return ProxyHelper::GetProxiedAsVtValue(GetObj(storage));
731  }
732 
734  // Internal helper -- cast type-generic storage to type-specific
735  // container.
736  static Container &_Container(_Storage &storage) {
737  // XXX Will need std::launder in c++17.
738  return *reinterpret_cast<Container *>(&storage);
739  }
740  static Container const &_Container(_Storage const &storage) {
741  // XXX Will need std::launder in c++17.
742  return *reinterpret_cast<Container const *>(&storage);
743  }
744  };
745 
747  // Local-storage type info implementation. The container and the object are
748  // the same -- there is no distinct container.
749  template <class T>
750  struct _LocalTypeInfo : _TypeInfoImpl<
751  T, // type
752  T, // container
753  _LocalTypeInfo<T> // CRTP
754  >
755  {
756  constexpr _LocalTypeInfo()
757  : _TypeInfoImpl<T, T, _LocalTypeInfo<T>>()
758  {}
759 
760  // Get returns object directly.
761  static T &_GetMutableObj(T &obj) { return obj; }
762  static T const &_GetObj(T const &obj) { return obj; }
763  // Place placement new's object directly.
764  static void _PlaceCopy(T *dst, T const &src) { new (dst) T(src); }
765  };
766 
768  // Remote-storage type info implementation. The container is an
769  // intrusive_ptr to an object holder: _Counted<T>.
770  template <class T>
771  struct _RemoteTypeInfo : _TypeInfoImpl<
772  T, // type
773  boost::intrusive_ptr<_Counted<T> >, // container
774  _RemoteTypeInfo<T> // CRTP
775  >
776  {
777  constexpr _RemoteTypeInfo()
778  : _TypeInfoImpl<
779  T, boost::intrusive_ptr<_Counted<T>>, _RemoteTypeInfo<T>>()
780  {}
781 
782  typedef boost::intrusive_ptr<_Counted<T> > Ptr;
783  // Get returns object stored in the pointed-to _Counted<T>.
784  static T &_GetMutableObj(Ptr &ptr) {
785  if (!ptr->IsUnique())
786  ptr.reset(new _Counted<T>(ptr->Get()));
787  return ptr->GetMutable();
788  }
789  static T const &_GetObj(Ptr const &ptr) { return ptr->Get(); }
790  // PlaceCopy() allocates a new _Counted<T> with a copy of the object.
791  static void _PlaceCopy(Ptr *dst, T const &src) {
792  new (dst) Ptr(new _Counted<T>(src));
793  }
794  };
795 
796  // Metafunction that returns the specific _TypeInfo subclass for T.
797  template <class T>
798  struct _TypeInfoFor {
799  // return _UsesLocalStore(T) ? _LocalTypeInfo<T> : _RemoteTypeInfo<T>;
800  typedef std::conditional_t<_UsesLocalStore<T>::value,
801  _LocalTypeInfo<T>,
802  _RemoteTypeInfo<T>> Type;
803  };
804 
805  // Make sure char[N] is treated as a string.
806  template <size_t N>
807  struct _TypeInfoFor<char[N]> : _TypeInfoFor<std::string> {};
808 
809  // Runtime function to return a _TypeInfo base pointer to a specific
810  // _TypeInfo subclass for type T.
811  template <class T>
812  static TfPointerAndBits<const _TypeInfo> GetTypeInfo() {
813  typedef typename _TypeInfoFor<T>::Type TI;
814  static const TI ti;
815  static constexpr unsigned int flags =
816  (TI::IsLocal ? _LocalFlag : 0) |
817  (TI::HasTrivialCopy ? _TrivialCopyFlag : 0) |
818  (TI::IsProxy ? _ProxyFlag : 0);
819  return TfPointerAndBits<const _TypeInfo>(&ti, flags);
820  }
821 
822  // A helper that moves a held value to temporary storage, but keeps it alive
823  // until the _HoldAside object is destroyed. This is used when assigning
824  // over a VtValue that might own the object being assigned. For instance,
825  // if I have a VtValue holding a map<string, VtValue>, and I reassign this
826  // VtValue with one of the elements from the map, we must ensure that the
827  // map isn't destroyed until after the assignment has taken place.
828  friend struct _HoldAside;
829  struct _HoldAside {
830  explicit _HoldAside(VtValue *val)
831  : info((val->IsEmpty() || val->_IsLocalAndTriviallyCopyable())
832  ? static_cast<_TypeInfo const *>(NULL) : val->_info.Get()) {
833  if (info)
834  info->Move(val->_storage, storage);
835  }
836  ~_HoldAside() {
837  if (info)
838  info->Destroy(storage);
839  }
840  _Storage storage;
841  _TypeInfo const *info;
842  };
843 
844  template <class T>
845  std::enable_if_t<
846  std::is_same<T, typename Vt_ValueGetStored<T>::Type>::value>
847  _Init(T const &obj) {
848  _info = GetTypeInfo<T>();
849  typedef typename _TypeInfoFor<T>::Type TypeInfo;
850  TypeInfo::CopyInitObj(obj, _storage);
851  }
852 
853  template <class T>
854  std::enable_if_t<
855  !std::is_same<T, typename Vt_ValueGetStored<T>::Type>::value>
856  _Init(T const &obj) {
857  _Init(typename Vt_ValueGetStored<T>::Type(obj));
858  }
859 
860 public:
861 
863  VtValue() {}
864 
866  VtValue(VtValue const &other) {
867  _Copy(other, *this);
868  }
869 
871  VtValue(VtValue &&other) noexcept {
872  _Move(other, *this);
873  }
874 
880  template <class T>
881  explicit VtValue(T const &obj) {
882  _Init(obj);
883  }
884 
904  template <class T>
905  static VtValue Take(T &obj) {
906  VtValue ret;
907  ret.Swap(obj);
908  return ret;
909  }
910 
912  ~VtValue() { _Clear(); }
913 
915  VtValue &operator=(VtValue const &other) {
916  if (ARCH_LIKELY(this != &other))
917  _Copy(other, *this);
918  return *this;
919  }
920 
922  VtValue &operator=(VtValue &&other) noexcept {
923  if (ARCH_LIKELY(this != &other))
924  _Move(other, *this);
925  return *this;
926  }
927 
928 #ifndef doxygen
929  template <class T>
930  inline
931  std::enable_if_t<
932  _TypeInfoFor<T>::Type::IsLocal &&
933  _TypeInfoFor<T>::Type::HasTrivialCopy,
934  VtValue &>
935  operator=(T obj) {
936  _Clear();
937  _Init(obj);
938  return *this;
939  }
940 #endif
941 
943 #ifdef doxygen
944  template <class T>
945  VtValue&
946  operator=(T const &obj);
947 #else
948  template <class T>
949  std::enable_if_t<
950  !_TypeInfoFor<T>::Type::IsLocal ||
951  !_TypeInfoFor<T>::Type::HasTrivialCopy,
952  VtValue &>
953  operator=(T const &obj) {
954  _HoldAside tmp(this);
955  _Init(obj);
956  return *this;
957  }
958 #endif
959 
961  VtValue &operator=(char const *cstr) {
962  std::string tmp(cstr);
963  _Clear();
964  _Init(tmp);
965  return *this;
966  }
967 
969  VtValue &operator=(char *cstr) {
970  return *this = const_cast<char const *>(cstr);
971  }
972 
974  VtValue &Swap(VtValue &rhs) noexcept {
975  // Do nothing if both empty. Otherwise general swap.
976  if (!IsEmpty() || !rhs.IsEmpty()) {
977  VtValue tmp;
978  _Move(*this, tmp);
979  _Move(rhs, *this);
980  _Move(tmp, rhs);
981  }
982  return *this;
983  }
984 
986  friend void swap(VtValue &lhs, VtValue &rhs) { lhs.Swap(rhs); }
987 
989  // make an unqualified call to swap(<held-value>, rhs). If this value is
990  // not holding a T, replace the held value with a value-initialized T
991  // instance first, then swap.
992 #ifdef doxygen
993  template <class T>
994  void
995  Swap(T &rhs);
996 #else
997  template <class T>
998  std::enable_if_t<
999  std::is_same<T, typename Vt_ValueGetStored<T>::Type>::value>
1000  Swap(T &rhs) {
1001  if (!IsHolding<T>())
1002  *this = T();
1003  UncheckedSwap(rhs);
1004  }
1005 #endif
1006 
1011 #ifdef doxygen
1012  template <class T>
1013  void
1014  UncheckedSwap(T &rhs);
1015 #else
1016  template <class T>
1017  std::enable_if_t<
1018  std::is_same<T, typename Vt_ValueGetStored<T>::Type>::value>
1019  UncheckedSwap(T &rhs) {
1020  using std::swap;
1021  swap(_GetMutable<T>(), rhs);
1022  }
1023 #endif
1024 
1026  void UncheckedSwap(VtValue &rhs) { Swap(rhs); }
1027 
1031  template <class T>
1032  T Remove() {
1033  T result;
1034  Swap(result);
1035  _Clear();
1036  return result;
1037  }
1038 
1042  template <class T>
1044  T result;
1045  UncheckedSwap(result);
1046  _Clear();
1047  return result;
1048  }
1049 
1052  template <class T>
1053  bool IsHolding() const {
1054  return _info.GetLiteral() && _TypeIs<T>();
1055  }
1056 
1058  VT_API bool IsArrayValued() const;
1059 
1062  size_t GetArraySize() const { return _GetNumElements(); }
1063 
1065  VT_API std::type_info const &GetTypeid() const;
1066 
1069  VT_API std::type_info const &GetElementTypeid() const;
1070 
1072  VT_API TfType GetType() const;
1073 
1075  VT_API std::string GetTypeName() const;
1076 
1082  if (ARCH_UNLIKELY(_IsProxy())) {
1083  return _info->GetProxiedAsVtValue(
1084  _storage).GetKnownValueTypeIndex();
1085  }
1086  return _info.GetLiteral() ? _info->knownTypeIndex : -1;
1087  }
1088 
1092  template <class T>
1093  T const &UncheckedGet() const & { return _Get<T>(); }
1094 
1097  template <class T>
1098  T UncheckedGet() && { return UncheckedRemove<T>(); }
1099 
1108  template <class T>
1109  T const &Get() const & {
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 _Get<T>();
1120  }
1121 
1124  template <class T>
1125  T Get() && {
1126  typedef Vt_DefaultValueFactory<T> Factory;
1127 
1128  // In the unlikely case that the types don't match, we obtain a default
1129  // value to return and issue an error via _FailGet.
1130  if (ARCH_UNLIKELY(!IsHolding<T>())) {
1131  return *(static_cast<T const *>(
1132  _FailGet(Factory::Invoke, typeid(T))));
1133  }
1134 
1135  return UncheckedRemove<T>();
1136  }
1137 
1142  template <class T>
1143  T GetWithDefault(T const &def = T()) const {
1144  return IsHolding<T>() ? UncheckedGet<T>() : def;
1145  }
1146 
1148  template <typename From, typename To>
1149  static void RegisterCast(VtValue (*castFn)(VtValue const &)) {
1150  _RegisterCast(typeid(From), typeid(To), castFn);
1151  }
1152 
1154  // holding To.
1155  template <typename From, typename To>
1156  static void RegisterSimpleCast() {
1157  _RegisterCast(typeid(From), typeid(To), _SimpleCast<From, To>);
1158  }
1159 
1162  template <typename From, typename To>
1164  RegisterSimpleCast<From, To>();
1165  RegisterSimpleCast<To, From>();
1166  }
1167 
1175  template <typename T>
1176  static VtValue Cast(VtValue const &val) {
1177  VtValue ret = val;
1178  return ret.Cast<T>();
1179  }
1180 
1188  VT_API static VtValue
1189  CastToTypeOf(VtValue const &val, VtValue const &other);
1190 
1198  VT_API static VtValue
1199  CastToTypeid(VtValue const &val, std::type_info const &type);
1200 
1204  static bool CanCastFromTypeidToTypeid(std::type_info const &from,
1205  std::type_info const &to) {
1206  return _CanCast(from, to);
1207  }
1208 
1216  template <typename T>
1218  if (IsHolding<T>())
1219  return *this;
1220  return *this = _PerformCast(typeid(T), *this);
1221  }
1222 
1230  VtValue &CastToTypeOf(VtValue const &other) {
1231  return CastToTypeid(other.GetTypeid());
1232  }
1233 
1241  VtValue &CastToTypeid(std::type_info const &type) {
1242  if (!TfSafeTypeCompare(GetTypeid(), type)) {
1243  *this = _PerformCast(type, *this);
1244  }
1245  return *this;
1246  }
1247 
1251  template <typename T>
1252  bool CanCast() const {
1253  return _CanCast(GetTypeid(), typeid(T));
1254  }
1255 
1259  bool CanCastToTypeOf(VtValue const &other) const {
1260  return _CanCast(GetTypeid(), other.GetTypeid());
1261  }
1262 
1266  bool CanCastToTypeid(std::type_info const &type) const {
1267  return _CanCast(GetTypeid(), type);
1268  }
1269 
1271  bool IsEmpty() const { return _info.GetLiteral() == 0; }
1272 
1274  VT_API bool CanHash() const;
1275 
1277  VT_API size_t GetHash() const;
1278 
1279  friend inline size_t hash_value(VtValue const &val) {
1280  return val.GetHash();
1281  }
1282 
1284  template <typename T>
1285  friend bool operator == (VtValue const &lhs, T const &rhs) {
1286  typedef typename Vt_ValueGetStored<T>::Type Stored;
1287  return lhs.IsHolding<Stored>() && lhs.UncheckedGet<Stored>() == rhs;
1288  }
1289  template <typename T>
1290  friend bool operator == (T const &lhs, VtValue const &rhs) {
1291  return rhs == lhs;
1292  }
1293 
1295  template <typename T>
1296  friend bool operator != (VtValue const &lhs, T const &rhs) {
1297  return !(lhs == rhs);
1298  }
1299  template <typename T>
1300  friend bool operator != (T const &lhs, VtValue const &rhs) {
1301  return !(lhs == rhs);
1302  }
1303 
1305  bool operator == (const VtValue &rhs) const {
1306  bool empty = IsEmpty(), rhsEmpty = rhs.IsEmpty();
1307  if (empty || rhsEmpty) {
1308  // Either one or both empty -- only equal if both empty.
1309  return empty == rhsEmpty;
1310  }
1311  if (_info.GetLiteral() == rhs._info.GetLiteral()) {
1312  // Holding identical types -- compare directly.
1313  return _info.Get()->Equal(_storage, rhs._storage);
1314  }
1315  return _EqualityImpl(rhs);
1316  }
1317  bool operator != (const VtValue &rhs) const { return !(*this == rhs); }
1318 
1320  VT_API friend std::ostream &
1321  operator << (std::ostream &out, const VtValue &self);
1322 
1323 private:
1324  VT_API const Vt_ShapeData* _GetShapeData() const;
1325  VT_API size_t _GetNumElements() const;
1326  friend struct Vt_ValueShapeDataAccess;
1327 
1328  static inline void _Copy(VtValue const &src, VtValue &dst) {
1329  if (src.IsEmpty()) {
1330  dst._Clear();
1331  return;
1332  }
1333 
1334  _HoldAside tmp(&dst);
1335  dst._info = src._info;
1336  if (src._IsLocalAndTriviallyCopyable()) {
1337  dst._storage = src._storage;
1338  } else {
1339  dst._info->CopyInit(src._storage, dst._storage);
1340  }
1341  }
1342 
1343  static inline void _Move(VtValue &src, VtValue &dst) noexcept {
1344  if (src.IsEmpty()) {
1345  dst._Clear();
1346  return;
1347  }
1348 
1349  _HoldAside tmp(&dst);
1350  dst._info = src._info;
1351  if (src._IsLocalAndTriviallyCopyable()) {
1352  dst._storage = src._storage;
1353  } else {
1354  dst._info->Move(src._storage, dst._storage);
1355  }
1356 
1357  src._info.Set(nullptr, 0);
1358  }
1359 
1360  template <class T>
1361  inline std::enable_if_t<VtIsKnownValueType_Workaround<T>::value, bool>
1362  _TypeIs() const {
1363  return _info->knownTypeIndex == VtGetKnownValueTypeIndex<T>() ||
1364  ARCH_UNLIKELY(_IsProxy() && _TypeIsImpl(typeid(T)));
1365  }
1366 
1367  template <class T>
1368  inline std::enable_if_t<!VtIsKnownValueType_Workaround<T>::value, bool>
1369  _TypeIs() const {
1370  std::type_info const &t = typeid(T);
1371  return TfSafeTypeCompare(_info->typeInfo, t) ||
1372  ARCH_UNLIKELY(_IsProxy() && _TypeIsImpl(t));
1373  }
1374 
1375  VT_API bool _TypeIsImpl(std::type_info const &queriedType) const;
1376 
1377  VT_API bool _EqualityImpl(VtValue const &rhs) const;
1378 
1379  template <class Proxy>
1380  std::enable_if_t<VtIsValueProxy<Proxy>::value, Proxy &>
1381  _GetMutable() {
1382  typedef typename _TypeInfoFor<Proxy>::Type TypeInfo;
1383  return TypeInfo::GetMutableObj(_storage);
1384  }
1385 
1386  template <class T>
1387  std::enable_if_t<!VtIsValueProxy<T>::value, T &>
1388  _GetMutable() {
1389  // If we are a proxy, collapse it out to the real value first.
1390  if (ARCH_UNLIKELY(_IsProxy())) {
1391  *this = _info->GetProxiedAsVtValue(_storage);
1392  }
1393  typedef typename _TypeInfoFor<T>::Type TypeInfo;
1394  return TypeInfo::GetMutableObj(_storage);
1395  }
1396 
1397  template <class Proxy>
1398  std::enable_if_t<VtIsValueProxy<Proxy>::value, Proxy const &>
1399  _Get() const {
1400  typedef typename _TypeInfoFor<Proxy>::Type TypeInfo;
1401  return TypeInfo::GetObj(_storage);
1402  }
1403 
1404  template <class T>
1405  std::enable_if_t<!VtIsValueProxy<T>::value, T const &>
1406  _Get() const {
1407  typedef typename _TypeInfoFor<T>::Type TypeInfo;
1408  if (ARCH_UNLIKELY(_IsProxy())) {
1409  return *static_cast<T const *>(_GetProxiedObjPtr());
1410  }
1411  return TypeInfo::GetObj(_storage);
1412  }
1413 
1414  void const *_GetProxiedObjPtr() const {
1415  return _info->GetProxiedObjPtr(_storage);
1416  }
1417 
1418  // Helper invoked in case Get fails. Reports an error and returns a default
1419  // value for \a queryType.
1420  VT_API void const *
1421  _FailGet(Vt_DefaultValueHolder (*factory)(),
1422  std::type_info const &queryType) const;
1423 
1424  inline void _Clear() {
1425  // optimize for local types not to deref _info.
1426  if (_info.GetLiteral() && !_IsLocalAndTriviallyCopyable())
1427  _info.Get()->Destroy(_storage);
1428  _info.Set(nullptr, 0);
1429  }
1430 
1431  inline bool _IsLocalAndTriviallyCopyable() const {
1432  unsigned int bits = _info.BitsAs<unsigned int>();
1433  return (bits & (_LocalFlag | _TrivialCopyFlag)) ==
1434  (_LocalFlag | _TrivialCopyFlag);
1435  }
1436 
1437  inline bool _IsProxy() const {
1438  return _info.BitsAs<unsigned int>() & _ProxyFlag;
1439  }
1440 
1441  VT_API static void _RegisterCast(std::type_info const &from,
1442  std::type_info const &to,
1443  VtValue (*castFn)(VtValue const &));
1444 
1445  // Cast \p value to the type \p to. Caller must ensure that val's type is
1446  // not already \p to.
1447  VT_API static VtValue
1448  _PerformCast(std::type_info const &to, VtValue const &val);
1449 
1450  // Return true if \p from == \p to or if there is a registered cast to
1451  // convert VtValues holding \p from to \p to.
1452  VT_API static bool
1453  _CanCast(std::type_info const &from, std::type_info const &to);
1454 
1455  // helper template function for simple casts from From to To.
1456  template <typename From, typename To>
1457  static VtValue _SimpleCast(VtValue const &val) {
1458  return VtValue(To(val.UncheckedGet<From>()));
1459  }
1460 
1461  // This grants friend access to a function in the wrapper file for this
1462  // class. This lets the wrapper reach down into a value to get a
1463  // boost::python wrapped object corresponding to the held type. This
1464  // facility is necessary to get the python API we want.
1465  friend TfPyObjWrapper
1466  Vt_GetPythonObjectFromHeldValue(VtValue const &self);
1467 
1468  VT_API TfPyObjWrapper _GetPythonObject() const;
1469 
1470  _Storage _storage;
1472 };
1473 
1474 #ifndef doxygen
1475 
1476 struct Vt_ValueShapeDataAccess {
1477  static const Vt_ShapeData* _GetShapeData(const VtValue& value) {
1478  return value._GetShapeData();
1479  }
1480 
1481  static size_t _GetNumElements(const VtValue& value) {
1482  return value._GetNumElements();
1483  }
1484 };
1485 
1489 template <class T>
1490 struct Vt_DefaultValueFactory {
1491  static Vt_DefaultValueHolder Invoke();
1492 };
1493 
1494 template <class T>
1495 inline Vt_DefaultValueHolder
1496 Vt_DefaultValueFactory<T>::Invoke() {
1497  return Vt_DefaultValueHolder::Create<T>();
1498 }
1499 
1500 // For performance reasons, the default constructors for vectors,
1501 // matrices, and quaternions do *not* initialize the data of the
1502 // object. This greatly improves the performance of creating large
1503 // arrays of objects. However, for consistency and to avoid
1504 // errors complaining about uninitialized values, we use VtZero
1505 // to construct zeroed out vectors, matrices, and quaternions by
1506 // explicitly instantiating the factory for these types.
1507 //
1508 #define _VT_DECLARE_ZERO_VALUE_FACTORY(r, unused, elem) \
1509 template <> \
1510 VT_API Vt_DefaultValueHolder Vt_DefaultValueFactory<VT_TYPE(elem)>::Invoke();
1511 
1512 BOOST_PP_SEQ_FOR_EACH(_VT_DECLARE_ZERO_VALUE_FACTORY,
1513  unused,
1514  VT_VEC_VALUE_TYPES
1515  VT_MATRIX_VALUE_TYPES
1516  VT_QUATERNION_VALUE_TYPES
1517  VT_DUALQUATERNION_VALUE_TYPES)
1518 
1519 #undef _VT_DECLARE_ZERO_VALUE_FACTORY
1520 
1521 //
1522 // The Get()/IsHolding routines needs to be special-cased to handle getting a
1523 // VtValue *as* a VtValue.
1524 //
1525 
1526 template <>
1527 inline const VtValue&
1528 VtValue::Get<VtValue>() const & {
1529  return *this;
1530 }
1531 
1532 template <>
1533 inline VtValue
1534 VtValue::Get<VtValue>() && {
1535  return std::move(*this);
1536 }
1537 
1538 template <>
1539 inline const VtValue&
1540 VtValue::UncheckedGet<VtValue>() const & {
1541  return *this;
1542 }
1543 
1544 template <>
1545 inline VtValue
1546 VtValue::UncheckedGet<VtValue>() && {
1547  return std::move(*this);
1548 }
1549 
1550 template <>
1551 inline bool
1552 VtValue::IsHolding<VtValue>() const {
1553  return true;
1554 }
1555 
1556 // Specialize VtValue::IsHolding<void>() to always return false.
1557 template <>
1558 inline bool
1559 VtValue::IsHolding<void>() const {
1560  return false;
1561 }
1562 
1563 
1564 
1565 #endif // !doxygen
1566 
1567 PXR_NAMESPACE_CLOSE_SCOPE
1568 
1569 #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:1062
static void RegisterSimpleBidirectionalCast()
Register a two-way cast from VtValue holding From to VtValue holding To.
Definition: value.h:1163
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:871
~VtValue()
Destructor.
Definition: value.h:912
T const & UncheckedGet() const &
Returns a const reference to the held object if the held object is of type T.
Definition: value.h:1093
VtValue & operator=(char const *cstr)
Assigning a char const * gives a VtValue holding a std::string.
Definition: value.h:961
VtValue & Cast()
Return this holding value type cast to T.
Definition: value.h:1217
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:1259
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:866
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:1043
Demangle C++ typenames generated by the typeid() facility.
static void RegisterSimpleCast()
Register a simple cast from VtValue holding From to VtValue.
Definition: value.h:1156
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:1204
VtValue & CastToTypeOf(VtValue const &other)
Return this holding value type cast to same type that other is holding.
Definition: value.h:1230
static VtValue Take(T &obj)
Create a new VtValue, taking its contents from obj.
Definition: value.h:905
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:1271
friend bool operator==(VtValue const &lhs, T const &rhs)
Tests for equality.
Definition: value.h:1285
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:1176
VtValue & operator=(VtValue &&other) noexcept
Move assignment from another VtValue.
Definition: value.h:922
int GetKnownValueTypeIndex() const
Return VtKnownValueTypeIndex<T> for the held type T.
Definition: value.h:1081
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:1109
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:1149
VtValue & operator=(char *cstr)
Assigning a char * gives a VtValue holding a std::string.
Definition: value.h:969
Boost Python object wrapper.
Definition: pyObjWrapper.h:95
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:881
bool CanCast() const
Return if this can be cast to T.
Definition: value.h:1252
VtValue & Swap(VtValue &rhs) noexcept
Swap this with rhs.
Definition: value.h:974
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:1026
friend void swap(VtValue &lhs, VtValue &rhs)
Overloaded swap() for generic code/stl/etc.
Definition: value.h:986
bool CanCastToTypeid(std::type_info const &type) const
Return if this can be cast to type.
Definition: value.h:1266
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:1143
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:1296
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:1241
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:863
T Remove()
Make this value empty and return the held T instance.
Definition: value.h:1032
bool IsHolding() const
Return true if this value is holding an object of type T, false otherwise.
Definition: value.h:1053
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:915
bool TfSafeTypeCompare(const std::type_info &t1, const std::type_info &t2)
Safely compare std::type_info structures.