All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 VT_VALUE_H
25 #define VT_VALUE_H
26 
27 #include "pxr/pxr.h"
28 
29 #ifdef PXR_PYTHON_SUPPORT_ENABLED
30 // XXX: Include pyLock.h after pyObjWrapper.h to work around
31 // Python include ordering issues.
32 #include "pxr/base/tf/pyObjWrapper.h"
33 #endif // PXR_PYTHON_SUPPORT_ENABLED
34 
35 #include "pxr/base/tf/pyLock.h"
36 
37 #include "pxr/base/arch/demangle.h"
38 #include "pxr/base/arch/hints.h"
39 #include "pxr/base/tf/anyUniquePtr.h"
40 #include "pxr/base/tf/pointerAndBits.h"
41 #include "pxr/base/tf/safeTypeCompare.h"
42 #include "pxr/base/tf/stringUtils.h"
43 #include "pxr/base/tf/tf.h"
44 #include "pxr/base/tf/type.h"
45 
46 #include "pxr/base/vt/api.h"
47 #include "pxr/base/vt/hash.h"
48 #include "pxr/base/vt/streamOut.h"
49 #include "pxr/base/vt/traits.h"
50 #include "pxr/base/vt/types.h"
51 
52 #include <boost/aligned_storage.hpp>
53 #include <boost/intrusive_ptr.hpp>
54 #include <boost/mpl/and.hpp>
55 #include <boost/mpl/if.hpp>
56 #include <boost/type_traits/decay.hpp>
57 #include <boost/type_traits/has_trivial_assign.hpp>
58 #include <boost/type_traits/has_trivial_constructor.hpp>
59 #include <boost/type_traits/has_trivial_copy.hpp>
60 #include <boost/type_traits/has_trivial_destructor.hpp>
61 #include <boost/type_traits/is_same.hpp>
62 #include <boost/utility/enable_if.hpp>
63 
64 #include <iosfwd>
65 #include <typeinfo>
66 #include <type_traits>
67 
68 PXR_NAMESPACE_OPEN_SCOPE
69 
73 template <class T>
74 struct Vt_DefaultValueFactory;
75 
76 // This is a helper class used by Vt_DefaultValueFactory to return a value with
77 // its type erased and only known at runtime via a std::type_info.
78 struct Vt_DefaultValueHolder
79 {
80  // Creates a value-initialized object and stores the type_info for the
81  // static type.
82  template <typename T>
83  static Vt_DefaultValueHolder Create() {
84  return Vt_DefaultValueHolder(TfAnyUniquePtr::New<T>(), typeid(T));
85  }
86 
87  // Creates a copy of the object and stores the type_info for the static
88  // type.
89  template <typename T>
90  static Vt_DefaultValueHolder Create(T const &val) {
91  return Vt_DefaultValueHolder(TfAnyUniquePtr::New(val), typeid(T));
92  }
93 
94  // Return the runtime type of the held object.
95  std::type_info const &GetType() const {
96  return *_type;
97  }
98 
99  // Return a pointer to the held object. This may be safely cast to the
100  // static type corresponding to the type_info returned by GetType.
101  void const *GetPointer() const {
102  return _ptr.Get();
103  }
104 
105 private:
106  Vt_DefaultValueHolder(TfAnyUniquePtr &&ptr, std::type_info const &type)
107  : _ptr(std::move(ptr)), _type(&type) {}
108 
109  TfAnyUniquePtr _ptr;
110  std::type_info const *_type;
111 };
112 
113 class VtValue;
114 
115 // Overload VtStreamOut for vector<VtValue>. Produces output like [value1,
116 // value2, ... valueN].
117 VT_API std::ostream &VtStreamOut(std::vector<VtValue> const &val, std::ostream &);
118 
119 // Base implementations for VtGetProxied{Type,Value}.
120 template <class T>
121 bool VtProxyHoldsType(T const &, std::type_info const &) { return false; }
122 template <class T>
123 TfType VtGetProxiedType(T const &) { return TfType(); }
124 template <class T>
125 VtValue const *VtGetProxiedValue(T const &) { return NULL; }
126 
127 #define VT_VALUE_SET_STORED_TYPE(SRC, DST) \
128  template <> struct Vt_ValueStoredType<SRC> { typedef DST Type; }
129 
130 template <class T> struct Vt_ValueStoredType { typedef T Type; };
131 VT_VALUE_SET_STORED_TYPE(char const *, std::string);
132 VT_VALUE_SET_STORED_TYPE(char *, std::string);
133 
134 #ifdef PXR_PYTHON_SUPPORT_ENABLED
135 VT_VALUE_SET_STORED_TYPE(boost::python::object, TfPyObjWrapper);
136 #endif // PXR_PYTHON_SUPPORT_ENABLED
137 
138 #undef VT_VALUE_SET_STORED_TYPE
139 
140 // A metafunction that gives the type VtValue should store for a given type T.
141 template <class T>
142 struct Vt_ValueGetStored
143  : Vt_ValueStoredType<typename boost::decay<T>::type> {};
144 
182 class VtValue
183 {
184  static const unsigned int _LocalFlag = 1 << 0;
185  static const unsigned int _TrivialCopyFlag = 1 << 1;
186  static const unsigned int _ProxyFlag = 1 << 2;
187 
188  template <class T>
189  struct _Counted {
190  explicit _Counted(T const &obj) : _obj(obj) {
191  _refCount = 0;
192  }
193  bool IsUnique() const { return _refCount == 1; }
194  T const &Get() const { return _obj; }
195  T &GetMutable() { return _obj; }
196 
197  private:
198  T _obj;
199  mutable std::atomic<int> _refCount;
200 
201  friend inline void intrusive_ptr_add_ref(_Counted const *d) {
202  d->_refCount.fetch_add(1, std::memory_order_relaxed);
203  }
204  friend inline void intrusive_ptr_release(_Counted const *d) {
205  if (d->_refCount.fetch_sub(1, std::memory_order_release) == 1) {
206  std::atomic_thread_fence(std::memory_order_acquire);
207  delete d;
208  }
209  }
210  };
211 
212  // Hold objects up to 1 word large locally. This makes the total structure
213  // 16 bytes when compiled 64 bit (1 word type-info pointer, 1 word storage
214  // space).
215  static const size_t _MaxLocalSize = sizeof(void*);
216  typedef std::aligned_storage<
217  /* size */_MaxLocalSize, /* alignment */_MaxLocalSize>::type _Storage;
218 
219  template <class T>
220  struct _IsTriviallyCopyable : boost::mpl::and_<
221  boost::has_trivial_constructor<T>,
222  boost::has_trivial_copy<T>,
223  boost::has_trivial_assign<T>,
224  boost::has_trivial_destructor<T> > {};
225 
226  // Metafunction that returns true if T should be stored locally, false if it
227  // should be stored remotely.
228  template <class T>
229  struct _UsesLocalStore : boost::mpl::bool_<
230  (sizeof(T) <= sizeof(_Storage)) &&
231  VtValueTypeHasCheapCopy<T>::value &&
232  std::is_nothrow_move_constructible<T>::value &&
233  std::is_nothrow_move_assignable<T>::value> {};
234 
235  // Type information base class.
236  struct _TypeInfo {
237  private:
238  using _CopyInitFunc = void (*)(_Storage const &, _Storage &);
239  using _DestroyFunc = void (*)(_Storage &);
240  using _MoveFunc = void (*)(_Storage &, _Storage &);
241  using _HashFunc = size_t (*)(_Storage const &);
242  using _EqualFunc = bool (*)(_Storage const &, _Storage const &);
243  using _MakeMutableFunc = void (*)(_Storage &);
244 #ifdef PXR_PYTHON_SUPPORT_ENABLED
245  using _GetPyObjFunc = TfPyObjWrapper (*)(_Storage const &);
246 #endif // PXR_PYTHON_SUPPORT_ENABLED
247  using _StreamOutFunc = std::ostream & (*)(_Storage const &, std::ostream &);
248  using _GetShapeDataFunc = const Vt_ShapeData* (*)(_Storage const &);
249  using _GetNumElementsFunc = size_t (*)(_Storage const &);
250  using _ProxyHoldsTypeFunc = bool (*)(_Storage const &, std::type_info const &);
251  using _GetProxiedTypeFunc = TfType (*)(_Storage const &);
252  using _GetProxiedValueFunc = VtValue const *(*)(_Storage const &);
253 
254  protected:
255  constexpr _TypeInfo(const std::type_info &ti,
256  const std::type_info &elementTi,
257  bool isArray,
258  bool isHashable,
259  _CopyInitFunc copyInit,
260  _DestroyFunc destroy,
261  _MoveFunc move,
262  _HashFunc hash,
263  _EqualFunc equal,
264  _MakeMutableFunc makeMutable,
265 #ifdef PXR_PYTHON_SUPPORT_ENABLED
266  _GetPyObjFunc getPyObj,
267 #endif // PXR_PYTHON_SUPPORT_ENABLED
268  _StreamOutFunc streamOut,
269  _GetShapeDataFunc getShapeData,
270  _GetNumElementsFunc getNumElements,
271  _ProxyHoldsTypeFunc proxyHoldsType,
272  _GetProxiedTypeFunc getProxiedType,
273  _GetProxiedValueFunc getProxiedValue)
274  : typeInfo(ti)
275  , elementTypeInfo(elementTi)
276  , isArray(isArray)
277  , isHashable(isHashable)
278  // Function table
279  , _copyInit(copyInit)
280  , _destroy(destroy)
281  , _move(move)
282  , _hash(hash)
283  , _equal(equal)
284  , _makeMutable(makeMutable)
285 #ifdef PXR_PYTHON_SUPPORT_ENABLED
286  , _getPyObj(getPyObj)
287 #endif // PXR_PYTHON_SUPPORT_ENABLED
288  , _streamOut(streamOut)
289  , _getShapeData(getShapeData)
290  , _getNumElements(getNumElements)
291  , _proxyHoldsType(proxyHoldsType)
292  , _getProxiedType(getProxiedType)
293  , _getProxiedValue(getProxiedValue)
294  {}
295 
296  public:
297  void CopyInit(_Storage const &src, _Storage &dst) const {
298  _copyInit(src, dst);
299  }
300  void Destroy(_Storage &storage) const {
301  _destroy(storage);
302  }
303  void Move(_Storage &src, _Storage &dst) const noexcept {
304  _move(src, dst);
305  }
306  size_t Hash(_Storage const &storage) const {
307  return _hash(storage);
308  }
309  bool Equal(_Storage const &lhs, _Storage const &rhs) const {
310  return _equal(lhs, rhs);
311  }
312  void MakeMutable(_Storage &storage) const {
313  _makeMutable(storage);
314  }
315 #ifdef PXR_PYTHON_SUPPORT_ENABLED
316  TfPyObjWrapper GetPyObj(_Storage const &storage) const {
317  return _getPyObj(storage);
318  }
319 #endif // PXR_PYTHON_SUPPORT_ENABLED
320  std::ostream & StreamOut(_Storage const &storage,
321  std::ostream &out) const {
322  return _streamOut(storage, out);
323  }
324  const Vt_ShapeData* GetShapeData(_Storage const &storage) const {
325  return _getShapeData(storage);
326  }
327  size_t GetNumElements(_Storage const &storage) const {
328  return _getNumElements(storage);
329  }
330  bool ProxyHoldsType(_Storage const &storage,
331  std::type_info const &t) const {
332  return _proxyHoldsType(storage, t);
333  }
334  TfType GetProxiedType(_Storage const &storage) const {
335  return _getProxiedType(storage);
336  }
337  VtValue const *GetProxiedValue(_Storage const &storage) const {
338  return _getProxiedValue(storage);
339  }
340 
341  const std::type_info &typeInfo;
342  const std::type_info &elementTypeInfo;
343  bool isArray;
344  bool isHashable;
345 
346  private:
347  _CopyInitFunc _copyInit;
348  _DestroyFunc _destroy;
349  _MoveFunc _move;
350  _HashFunc _hash;
351  _EqualFunc _equal;
352  _MakeMutableFunc _makeMutable;
353 #ifdef PXR_PYTHON_SUPPORT_ENABLED
354  _GetPyObjFunc _getPyObj;
355 #endif // PXR_PYTHON_SUPPORT_ENABLED
356  _StreamOutFunc _streamOut;
357  _GetShapeDataFunc _getShapeData;
358  _GetNumElementsFunc _getNumElements;
359  _ProxyHoldsTypeFunc _proxyHoldsType;
360  _GetProxiedTypeFunc _getProxiedType;
361  _GetProxiedValueFunc _getProxiedValue;
362  };
363 
364  // Type-dispatching overloads.
365 
366  // Array type helper.
367  template <class T, class Enable=void>
368  struct _ArrayHelper {
369  static const Vt_ShapeData* GetShapeData(T const &) { return NULL; }
370  static size_t GetNumElements(T const &) { return 0; }
371  constexpr static std::type_info const &GetElementTypeid() { return typeid(void); }
372  };
373  template <class Array>
374  struct _ArrayHelper<Array,
375  typename boost::enable_if<VtIsArray<Array> >::type> {
376  static const Vt_ShapeData* GetShapeData(Array const &obj) {
377  return obj._GetShapeData();
378  }
379  static size_t GetNumElements(Array const &obj) {
380  return obj.size();
381  }
382  constexpr static std::type_info const &GetElementTypeid() {
383  return typeid(typename Array::ElementType);
384  }
385  };
386 
387  // _TypeInfo implementation helper. This is a CRTP base that the
388  // _LocalTypeInfo and _RemoteTypeInfo types derive. It wraps their
389  // type-specific implementations with type-generic interfaces.
390  template <class T, class Container, class Derived>
391  struct _TypeInfoImpl : public _TypeInfo
392  {
393  static const bool IsLocal = _UsesLocalStore<T>::value;
394  static const bool HasTrivialCopy = _IsTriviallyCopyable<T>::value;
395  static const bool IsProxy = VtIsValueProxy<T>::value;
396 
397  using This = _TypeInfoImpl;
398 
399  constexpr _TypeInfoImpl()
400  : _TypeInfo(typeid(T),
401  _ArrayHelper<T>::GetElementTypeid(),
402  VtIsArray<T>::value,
403  VtIsHashable<T>(),
404  &This::_CopyInit,
405  &This::_Destroy,
406  &This::_Move,
407  &This::_Hash,
408  &This::_Equal,
409  &This::_MakeMutable,
410 #ifdef PXR_PYTHON_SUPPORT_ENABLED
411  &This::_GetPyObj,
412 #endif // PXR_PYTHON_SUPPORT_ENABLED
413  &This::_StreamOut,
414  &This::_GetShapeData,
415  &This::_GetNumElements,
416  &This::_ProxyHoldsType,
417  &This::_GetProxiedType,
418  &This::_GetProxiedValue)
419  {}
420 
422  // Typed API for client use.
423  static T const &GetObj(_Storage const &storage) {
424  return Derived::_GetObj(_Container(storage));
425  }
426 
427  static T &GetMutableObj(_Storage &storage) {
428  return Derived::_GetMutableObj(_Container(storage));
429  }
430 
431  static void CopyInitObj(T const &objSrc, _Storage &dst) {
432  Derived::_PlaceCopy(&_Container(dst), objSrc);
433  }
434 
435  private:
436  static_assert(sizeof(Container) <= sizeof(_Storage),
437  "Container size cannot exceed storage size.");
438 
440  // _TypeInfo interface function implementations.
441  static void _CopyInit(_Storage const &src, _Storage &dst) {
442  new (&_Container(dst)) Container(_Container(src));
443  }
444 
445  static void _Destroy(_Storage &storage) {
446  _Container(storage).~Container();
447  }
448 
449  static size_t _Hash(_Storage const &storage) {
450  return VtHashValue(GetObj(storage));
451  }
452 
453  static bool _Equal(_Storage const &lhs, _Storage const &rhs) {
454  // Equal is only ever invoked with an object of this specific type.
455  // That is, we only ever ask a proxy to compare to a proxy; we never
456  // ask a proxy to compare to the proxied object.
457  return GetObj(lhs) == GetObj(rhs);
458  }
459 
460  static void _Move(_Storage &src, _Storage &dst) noexcept {
461  new (&_Container(dst)) Container(std::move(_Container(src)));
462  _Destroy(src);
463  }
464 
465  static void _MakeMutable(_Storage &storage) {
466  GetMutableObj(storage);
467  }
468 
469 #ifdef PXR_PYTHON_SUPPORT_ENABLED
470  static TfPyObjWrapper _GetPyObj(_Storage const &storage) {
471  TfPyLock lock;
472  return boost::python::api::object(GetObj(storage));
473  }
474 #endif // PXR_PYTHON_SUPPORT_ENABLED
475 
476  static std::ostream &_StreamOut(
477  _Storage const &storage, std::ostream &out) {
478  return VtStreamOut(GetObj(storage), out);
479  }
480 
481  static const Vt_ShapeData* _GetShapeData(_Storage const &storage) {
482  return _ArrayHelper<T>::GetShapeData(GetObj(storage));
483  }
484 
485  static size_t _GetNumElements(_Storage const &storage) {
486  return _ArrayHelper<T>::GetNumElements(GetObj(storage));
487  }
488 
489  static bool
490  _ProxyHoldsType(_Storage const &storage, std::type_info const &t) {
491  return VtProxyHoldsType(GetObj(storage), t);
492  }
493 
494  static TfType
495  _GetProxiedType(_Storage const &storage) {
496  return VtGetProxiedType(GetObj(storage));
497  }
498 
499  static VtValue const *
500  _GetProxiedValue(_Storage const &storage) {
501  return VtGetProxiedValue(GetObj(storage));
502  }
503 
505  // Internal helper -- cast type-generic storage to type-specific
506  // container.
507  static Container &_Container(_Storage &storage) {
508  return *((Container *)&storage);
509  }
510  static Container const &_Container(_Storage const &storage) {
511  return *((Container const *)&storage);
512  }
513  };
514 
516  // Local-storage type info implementation. The container and the object are
517  // the same -- there is no distinct container.
518  template <class T>
519  struct _LocalTypeInfo : _TypeInfoImpl<
520  T, // type
521  T, // container
522  _LocalTypeInfo<T> // CRTP
523  >
524  {
525  constexpr _LocalTypeInfo()
526  : _TypeInfoImpl<T, T, _LocalTypeInfo<T>>()
527  {}
528 
529  // Get returns object directly.
530  static T &_GetMutableObj(T &obj) { return obj; }
531  static T const &_GetObj(T const &obj) { return obj; }
532  // Place placement new's object directly.
533  static void _PlaceCopy(T *dst, T const &src) { new (dst) T(src); }
534  };
535 
537  // Remote-storage type info implementation. The container is an
538  // intrusive_ptr to an object holder: _Counted<T>.
539  template <class T>
540  struct _RemoteTypeInfo : _TypeInfoImpl<
541  T, // type
542  boost::intrusive_ptr<_Counted<T> >, // container
543  _RemoteTypeInfo<T> // CRTP
544  >
545  {
546  constexpr _RemoteTypeInfo()
547  : _TypeInfoImpl<
548  T, boost::intrusive_ptr<_Counted<T>>, _RemoteTypeInfo<T>>()
549  {}
550 
551  typedef boost::intrusive_ptr<_Counted<T> > Ptr;
552  // Get returns object stored in the pointed-to _Counted<T>.
553  static T &_GetMutableObj(Ptr &ptr) {
554  if (!ptr->IsUnique())
555  ptr.reset(new _Counted<T>(ptr->Get()));
556  return ptr->GetMutable();
557  }
558  static T const &_GetObj(Ptr const &ptr) { return ptr->Get(); }
559  // PlaceCopy() allocates a new _Counted<T> with a copy of the object.
560  static void _PlaceCopy(Ptr *dst, T const &src) {
561  new (dst) Ptr(new _Counted<T>(src));
562  }
563  };
564 
565  // Metafunction that returns the specific _TypeInfo subclass for T.
566  template <class T>
567  struct _TypeInfoFor {
568  // return _UsesLocalStore(T) ? _LocalTypeInfo<T> : _RemoteTypeInfo<T>;
569  typedef typename boost::mpl::if_<_UsesLocalStore<T>,
570  _LocalTypeInfo<T>,
571  _RemoteTypeInfo<T> >::type Type;
572  };
573 
574  // Make sure char[N] is treated as a string.
575  template <size_t N>
576  struct _TypeInfoFor<char[N]> {
577  // return _UsesLocalStore(T) ? _LocalTypeInfo<T> : _RemoteTypeInfo<T>;
578  typedef typename boost::mpl::if_<_UsesLocalStore<std::string>,
579  _LocalTypeInfo<std::string>,
580  _RemoteTypeInfo<std::string> >::type Type;
581  };
582 
583  // Runtime function to return a _TypeInfo base pointer to a specific
584  // _TypeInfo subclass for type T.
585  template <class T>
586  static TfPointerAndBits<const _TypeInfo> GetTypeInfo() {
587  typedef typename _TypeInfoFor<T>::Type TI;
588  static const TI ti;
589  static constexpr unsigned int flags =
590  (TI::IsLocal ? _LocalFlag : 0) |
591  (TI::HasTrivialCopy ? _TrivialCopyFlag : 0) |
592  (TI::IsProxy ? _ProxyFlag : 0);
593  return TfPointerAndBits<const _TypeInfo>(&ti, flags);
594  }
595 
596  // A helper that moves a held value to temporary storage, but keeps it alive
597  // until the _HoldAside object is destroyed. This is used when assigning
598  // over a VtValue that might own the object being assigned. For instance,
599  // if I have a VtValue holding a map<string, VtValue>, and I reassign this
600  // VtValue with one of the elements from the map, we must ensure that the
601  // map isn't destroyed until after the assignment has taken place.
602  friend struct _HoldAside;
603  struct _HoldAside {
604  explicit _HoldAside(VtValue *val)
605  : info((val->IsEmpty() || val->_IsLocalAndTriviallyCopyable())
606  ? static_cast<_TypeInfo const *>(NULL) : val->_info.Get()) {
607  if (info)
608  info->Move(val->_storage, storage);
609  }
610  ~_HoldAside() {
611  if (info)
612  info->Destroy(storage);
613  }
614  _Storage storage;
615  _TypeInfo const *info;
616  };
617 
618  template <class T>
619  typename boost::enable_if<
620  boost::is_same<T, typename Vt_ValueGetStored<T>::Type> >::type
621  _Init(T const &obj) {
622  _info = GetTypeInfo<T>();
623  typedef typename _TypeInfoFor<T>::Type TypeInfo;
624  TypeInfo::CopyInitObj(obj, _storage);
625  }
626 
627  template <class T>
628  typename boost::disable_if<
629  boost::is_same<T, typename Vt_ValueGetStored<T>::Type> >::type
630  _Init(T const &obj) {
631  _Init(typename Vt_ValueGetStored<T>::Type(obj));
632  }
633 
634 public:
635 
637  VtValue() {}
638 
640  VtValue(VtValue const &other) {
641  _Copy(other, *this);
642  }
643 
645  VtValue(VtValue &&other) noexcept {
646  _Move(other, *this);
647  }
648 
654  template <class T>
655  explicit VtValue(T const &obj) {
656  _Init(obj);
657  }
658 
678  template <class T>
679  static VtValue Take(T &obj) {
680  VtValue ret;
681  ret.Swap(obj);
682  return ret;
683  }
684 
686  ~VtValue() { _Clear(); }
687 
689  VtValue &operator=(VtValue const &other) {
690  if (ARCH_LIKELY(this != &other))
691  _Copy(other, *this);
692  return *this;
693  }
694 
696  VtValue &operator=(VtValue &&other) noexcept {
697  if (ARCH_LIKELY(this != &other))
698  _Move(other, *this);
699  return *this;
700  }
701 
703  template <class T>
704  inline
705  typename boost::enable_if_c<
706  _TypeInfoFor<T>::Type::IsLocal &&
707  _TypeInfoFor<T>::Type::HasTrivialCopy,
708  VtValue &>::type
709  operator=(T obj) {
710  _Clear();
711  _Init(obj);
712  return *this;
713  }
714 
716  template <class T>
717  typename boost::disable_if_c<
718  _TypeInfoFor<T>::Type::IsLocal &&
719  _TypeInfoFor<T>::Type::HasTrivialCopy,
720  VtValue &>::type
721  operator=(T const &obj) {
722  _HoldAside tmp(this);
723  _Init(obj);
724  return *this;
725  }
726 
728  VtValue &operator=(char const *cstr) {
729  std::string tmp(cstr);
730  _Clear();
731  _Init(tmp);
732  return *this;
733  }
734 
736  VtValue &operator=(char *cstr) {
737  return *this = const_cast<char const *>(cstr);
738  }
739 
741  VtValue &Swap(VtValue &rhs) noexcept {
742  // Do nothing if both empty. Otherwise general swap.
743  if (!IsEmpty() || !rhs.IsEmpty()) {
744  VtValue tmp;
745  _Move(*this, tmp);
746  _Move(rhs, *this);
747  _Move(tmp, rhs);
748  }
749  return *this;
750  }
751 
753  friend void swap(VtValue &lhs, VtValue &rhs) { lhs.Swap(rhs); }
754 
756  // make an unqualified call to swap(<held-value>, rhs). If this value is
757  // not holding a T, replace the held value with a value-initialized T
758  // instance first, then swap.
759  template <class T>
760  typename boost::enable_if<
761  boost::is_same<T, typename Vt_ValueGetStored<T>::Type> >::type
762  Swap(T &rhs) {
763  if (!IsHolding<T>())
764  *this = T();
765  UncheckedSwap(rhs);
766  }
767 
772  template <class T>
773  typename boost::enable_if<
774  boost::is_same<T, typename Vt_ValueGetStored<T>::Type> >::type
775  UncheckedSwap(T &rhs) {
776  using std::swap;
777  swap(_GetMutable<T>(), rhs);
778  }
779 
781  void UncheckedSwap(VtValue &rhs) { Swap(rhs); }
782 
786  template <class T>
787  T Remove() {
788  T result;
789  Swap(result);
790  _Clear();
791  return result;
792  }
793 
797  template <class T>
799  T result;
800  UncheckedSwap(result);
801  _Clear();
802  return result;
803  }
804 
807  template <class T>
808  bool IsHolding() const {
809  return _info.GetLiteral() && _TypeIs<T>();
810  }
811 
813  VT_API bool IsArrayValued() const;
814 
817  size_t GetArraySize() const { return _GetNumElements(); }
818 
820  VT_API std::type_info const &GetTypeid() const;
821 
824  VT_API std::type_info const &GetElementTypeid() const;
825 
827  VT_API TfType GetType() const;
828 
830  VT_API std::string GetTypeName() const;
831 
835  template <class T>
836  T const &UncheckedGet() const { return _Get<T>(); }
837 
846  template <class T>
847  T const &Get() const {
848  typedef Vt_DefaultValueFactory<T> Factory;
849 
850  // In the unlikely case that the types don't match, we obtain a default
851  // value to return and issue an error via _FailGet.
852  if (ARCH_UNLIKELY(!IsHolding<T>())) {
853  return *(static_cast<T const *>(
854  _FailGet(Factory::Invoke, typeid(T))));
855  }
856 
857  return _Get<T>();
858  }
859 
864  template <class T>
865  T GetWithDefault(T const &def = T()) const {
866  return IsHolding<T>() ? UncheckedGet<T>() : def;
867  }
868 
870  template <typename From, typename To>
871  static void RegisterCast(VtValue (*castFn)(VtValue const &)) {
872  _RegisterCast(typeid(From), typeid(To), castFn);
873  }
874 
876  // holding To.
877  template <typename From, typename To>
878  static void RegisterSimpleCast() {
879  _RegisterCast(typeid(From), typeid(To), _SimpleCast<From, To>);
880  }
881 
884  template <typename From, typename To>
886  RegisterSimpleCast<From, To>();
887  RegisterSimpleCast<To, From>();
888  }
889 
897  template <typename T>
898  static VtValue Cast(VtValue const &val) {
899  VtValue ret = val;
900  return ret.Cast<T>();
901  }
902 
910  VT_API static VtValue
911  CastToTypeOf(VtValue const &val, VtValue const &other);
912 
920  VT_API static VtValue
921  CastToTypeid(VtValue const &val, std::type_info const &type);
922 
926  static bool CanCastFromTypeidToTypeid(std::type_info const &from,
927  std::type_info const &to) {
928  return _CanCast(from, to);
929  }
930 
938  template <typename T>
940  if (IsHolding<T>())
941  return *this;
942  return *this = _PerformCast(typeid(T), *this);
943  }
944 
952  VtValue &CastToTypeOf(VtValue const &other) {
953  return *this = _PerformCast(other.GetTypeid(), *this);
954  }
955 
963  VtValue &CastToTypeid(std::type_info const &type) {
964  return *this = _PerformCast(type, *this);
965  }
966 
970  template <typename T>
971  bool CanCast() const {
972  return _CanCast(GetTypeid(), typeid(T));
973  }
974 
978  bool CanCastToTypeOf(VtValue const &other) const {
979  return _CanCast(GetTypeid(), other.GetTypeid());
980  }
981 
985  bool CanCastToTypeid(std::type_info const &type) const {
986  return _CanCast(GetTypeid(), type);
987  }
988 
990  bool IsEmpty() const { return _info.GetLiteral() == 0; }
991 
993  VT_API bool CanHash() const;
994 
996  VT_API size_t GetHash() const;
997 
998  friend inline size_t hash_value(VtValue const &val) {
999  return val.GetHash();
1000  }
1001 
1003  template <typename T>
1004  friend bool operator == (VtValue const &lhs, T const &rhs) {
1005  typedef typename Vt_ValueGetStored<T>::Type Stored;
1006  return lhs.IsHolding<Stored>() && lhs.UncheckedGet<Stored>() == rhs;
1007  }
1008  template <typename T>
1009  friend bool operator == (T const &lhs, VtValue const &rhs) {
1010  return rhs == lhs;
1011  }
1012 
1014  template <typename T>
1015  friend bool operator != (VtValue const &lhs, T const &rhs) {
1016  return !(lhs == rhs);
1017  }
1018  template <typename T>
1019  friend bool operator != (T const &lhs, VtValue const &rhs) {
1020  return !(lhs == rhs);
1021  }
1022 
1024  bool operator == (const VtValue &rhs) const {
1025  bool empty = IsEmpty(), rhsEmpty = rhs.IsEmpty();
1026  if (empty || rhsEmpty)
1027  return empty == rhsEmpty;
1028  if (_info.GetLiteral() == rhs._info.GetLiteral())
1029  return _info.Get()->Equal(_storage, rhs._storage);
1030  return _EqualityImpl(rhs);
1031  }
1032  bool operator != (const VtValue &rhs) const { return !(*this == rhs); }
1033 
1035  VT_API friend std::ostream &
1036  operator << (std::ostream &out, const VtValue &self);
1037 
1038 private:
1039  VT_API const Vt_ShapeData* _GetShapeData() const;
1040  VT_API size_t _GetNumElements() const;
1041  friend struct Vt_ValueShapeDataAccess;
1042 
1043  static inline void _Copy(VtValue const &src, VtValue &dst) {
1044  if (src.IsEmpty()) {
1045  dst._Clear();
1046  return;
1047  }
1048 
1049  _HoldAside tmp(&dst);
1050  dst._info = src._info;
1051  if (src._IsLocalAndTriviallyCopyable()) {
1052  dst._storage = src._storage;
1053  } else {
1054  dst._info->CopyInit(src._storage, dst._storage);
1055  }
1056  }
1057 
1058  static inline void _Move(VtValue &src, VtValue &dst) noexcept {
1059  if (src.IsEmpty()) {
1060  dst._Clear();
1061  return;
1062  }
1063 
1064  _HoldAside tmp(&dst);
1065  dst._info = src._info;
1066  if (src._IsLocalAndTriviallyCopyable()) {
1067  dst._storage = src._storage;
1068  } else {
1069  dst._info->Move(src._storage, dst._storage);
1070  }
1071 
1072  src._info.Set(nullptr, 0);
1073  }
1074 
1075  VtValue const *_ResolveProxy() const {
1076  return ARCH_UNLIKELY(_IsProxy()) ?
1077  _info->GetProxiedValue(_storage) : this;
1078  }
1079 
1080  template <class T>
1081  inline bool _TypeIs() const {
1082  std::type_info const &t = typeid(T);
1083  bool cmp = TfSafeTypeCompare(_info->typeInfo, t);
1084  return ARCH_UNLIKELY(_IsProxy() && !cmp) ? _TypeIsImpl(t) : cmp;
1085  }
1086 
1087  VT_API bool _TypeIsImpl(std::type_info const &queriedType) const;
1088 
1089  VT_API bool _EqualityImpl(VtValue const &rhs) const;
1090 
1091  template <class Proxy>
1092  typename boost::enable_if<VtIsValueProxy<Proxy>, Proxy &>::type
1093  _GetMutable() {
1094  typedef typename _TypeInfoFor<Proxy>::Type TypeInfo;
1095  return TypeInfo::GetMutableObj(_storage);
1096  }
1097 
1098  template <class T>
1099  typename boost::disable_if<VtIsValueProxy<T>, T &>::type
1100  _GetMutable() {
1101  // If we are a proxy, collapse it out to the real value first.
1102  if (ARCH_UNLIKELY(_IsProxy()))
1103  *this = _info->GetProxiedValue(_storage);
1104  typedef typename _TypeInfoFor<T>::Type TypeInfo;
1105  return TypeInfo::GetMutableObj(_storage);
1106  }
1107 
1108  template <class Proxy>
1109  typename boost::enable_if<VtIsValueProxy<Proxy>, Proxy const &>::type
1110  _Get() const {
1111  typedef typename _TypeInfoFor<Proxy>::Type TypeInfo;
1112  return TypeInfo::GetObj(_storage);
1113  }
1114 
1115  template <class T>
1116  typename boost::disable_if<VtIsValueProxy<T>, T const &>::type
1117  _Get() const {
1118  typedef typename _TypeInfoFor<T>::Type TypeInfo;
1119  return TypeInfo::GetObj(_ResolveProxy()->_storage);
1120  }
1121 
1122  // Helper invoked in case Get fails. Reports an error and returns a default
1123  // value for \a queryType.
1124  VT_API void const *
1125  _FailGet(Vt_DefaultValueHolder (*factory)(),
1126  std::type_info const &queryType) const;
1127 
1128  inline void _Clear() {
1129  // optimize for local types not to deref _info.
1130  if (_info.GetLiteral() && !_IsLocalAndTriviallyCopyable())
1131  _info.Get()->Destroy(_storage);
1132  _info.Set(nullptr, 0);
1133  }
1134 
1135  inline bool _IsLocalAndTriviallyCopyable() const {
1136  unsigned int bits = _info.BitsAs<unsigned int>();
1137  return (bits & (_LocalFlag | _TrivialCopyFlag)) ==
1138  (_LocalFlag | _TrivialCopyFlag);
1139  }
1140 
1141  inline bool _IsProxy() const {
1142  return _info.BitsAs<unsigned int>() & _ProxyFlag;
1143  }
1144 
1145  VT_API static void _RegisterCast(std::type_info const &from,
1146  std::type_info const &to,
1147  VtValue (*castFn)(VtValue const &));
1148 
1149  VT_API static VtValue
1150  _PerformCast(std::type_info const &to, VtValue const &val);
1151 
1152  VT_API static bool
1153  _CanCast(std::type_info const &from, std::type_info const &to);
1154 
1155  // helper template function for simple casts from From to To.
1156  template <typename From, typename To>
1157  static VtValue _SimpleCast(VtValue const &val) {
1158  return VtValue(To(val.UncheckedGet<From>()));
1159  }
1160 
1161 #ifdef PXR_PYTHON_SUPPORT_ENABLED
1162  // This grants friend access to a function in the wrapper file for this
1163  // class. This lets the wrapper reach down into a value to get a
1164  // boost::python wrapped object corresponding to the held type. This
1165  // facility is necessary to get the python API we want.
1166  friend TfPyObjWrapper
1167  Vt_GetPythonObjectFromHeldValue(VtValue const &self);
1168 
1169  VT_API TfPyObjWrapper _GetPythonObject() const;
1170 #endif // PXR_PYTHON_SUPPORT_ENABLED
1171 
1172  _Storage _storage;
1174 };
1175 
1176 #if !defined(doxygen)
1177 
1181 template <class T>
1182 struct Vt_DefaultValueFactory {
1184  static Vt_DefaultValueHolder Invoke() {
1185  return Vt_DefaultValueHolder::Create<T>();
1186  }
1187 };
1188 
1189 struct Vt_ValueShapeDataAccess {
1190  static const Vt_ShapeData* _GetShapeData(const VtValue& value) {
1191  return value._GetShapeData();
1192  }
1193 
1194  static size_t _GetNumElements(const VtValue& value) {
1195  return value._GetNumElements();
1196  }
1197 };
1198 
1199 // For performance reasons, the default constructors for vectors,
1200 // matrices, and quaternions do *not* initialize the data of the
1201 // object. This greatly improves the performance of creating large
1202 // arrays of objects. However, boost::value_initialized<T>() no
1203 // longer fills the memory of the object with 0 bytes before invoking
1204 // the constructor so we started getting errors complaining about
1205 // uninitialized values. So, we now use VtZero to construct zeroed
1206 // out vectors, matrices, and quaternions by explicitly instantiating
1207 // the factory for these types.
1208 //
1209 #define _VT_DECLARE_ZERO_VALUE_FACTORY(r, unused, elem) \
1210 template <> \
1211 VT_API Vt_DefaultValueHolder Vt_DefaultValueFactory<VT_TYPE(elem)>::Invoke();
1212 
1213 BOOST_PP_SEQ_FOR_EACH(_VT_DECLARE_ZERO_VALUE_FACTORY,
1214  unused,
1215  VT_VEC_VALUE_TYPES
1216  VT_MATRIX_VALUE_TYPES
1217  VT_QUATERNION_VALUE_TYPES)
1218 
1219 #undef _VT_DECLARE_ZERO_VALUE_FACTORY
1220 
1221 //
1222 // The Get()/IsHolding routines needs to be special-cased to handle getting a
1223 // VtValue *as* a VtValue.
1224 //
1225 
1226 template <>
1227 inline const VtValue&
1228 VtValue::Get<VtValue>() const {
1229  return *this;
1230 }
1231 
1232 template <>
1233 inline const VtValue&
1234 VtValue::UncheckedGet<VtValue>() const {
1235  return *this;
1236 }
1237 
1238 template <>
1239 inline bool
1240 VtValue::IsHolding<VtValue>() const {
1241  return true;
1242 }
1243 
1244 // Specialize VtValue::IsHolding<void>() to always return false.
1245 template <>
1246 inline bool
1247 VtValue::IsHolding<void>() const {
1248  return false;
1249 }
1250 
1251 #endif // !doxygen
1252 
1253 PXR_NAMESPACE_CLOSE_SCOPE
1254 
1255 #endif // VT_VALUE_H
boost::enable_if< boost::is_same< T, typename Vt_ValueGetStored< T >::Type > >::type Swap(T &rhs)
Swap the held value with rhs. If this value is holding a T,.
Definition: value.h:762
void swap(ArAssetInfo &lhs, ArAssetInfo &rhs)
Definition: assetInfo.h:60
static void RegisterSimpleBidirectionalCast()
Register a two-way cast from VtValue holding From to VtValue holding To.
Definition: value.h:885
T const & UncheckedGet() const
Returns a const reference to the held object if the held object is of type T.
Definition: value.h:836
VtValue(VtValue &&other) noexcept
Move construct with other.
Definition: value.h:645
~VtValue()
Destructor.
Definition: value.h:686
VtValue & operator=(char const *cstr)
Assigning a char const * gives a VtValue holding a std::string.
Definition: value.h:728
bool CanCastToTypeOf(VtValue const &other) const
Return if this can be cast to type.
Definition: value.h:978
VtValue & Cast()
Return this holding value type cast to T.
Definition: value.h:939
bool CanCast() const
Return if this can be cast to T.
Definition: value.h:971
size_t GetArraySize() const
Return the number of elements in the held value if IsArrayValued(), return 0 otherwise.
Definition: value.h:817
boost::enable_if_c< _TypeInfoFor< T >::Type::IsLocal &&_TypeInfoFor< T >::Type::HasTrivialCopy, VtValue & >::type operator=(T obj)
Assignment operator from any type.
Definition: value.h:709
AR_API bool operator!=(const ArAssetInfo &lhs, const ArAssetInfo &rhs)
bool IsHolding() const
Return true if this value is holding an object of type T, false otherwise.
Definition: value.h:808
AR_API bool operator==(const ArAssetInfo &lhs, const ArAssetInfo &rhs)
constexpr uintptr_t GetLiteral() const noexcept
Retrieve the raw underlying value.
VtValue(VtValue const &other)
Copy construct with other.
Definition: value.h:640
T const & Get() const
Returns a const reference to the held object if the held object is of type T.
Definition: value.h:847
T UncheckedRemove()
Make this value empty and return the held T instance.
Definition: value.h:798
static void RegisterSimpleCast()
Register a simple cast from VtValue holding From to VtValue.
Definition: value.h:878
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:926
VtValue & CastToTypeOf(VtValue const &other)
Return this holding value type cast to same type that other is holding.
Definition: value.h:952
boost::enable_if< boost::is_same< T, typename Vt_ValueGetStored< T >::Type > >::type UncheckedSwap(T &rhs)
Swap the held value with rhs.
Definition: value.h:775
static VtValue Take(T &obj)
Create a new VtValue, taking its contents from obj.
Definition: value.h:679
boost::disable_if_c< _TypeInfoFor< T >::Type::IsLocal &&_TypeInfoFor< T >::Type::HasTrivialCopy, VtValue & >::type operator=(T const &obj)
Assignment operator from any type.
Definition: value.h:721
void swap(UsdStageLoadRules &l, UsdStageLoadRules &r)
Swap the contents of rules l and r.
bool CanCastToTypeid(std::type_info const &type) const
Return if this can be cast to type.
Definition: value.h:985
VT_API std::type_info const & GetTypeid() const
Returns the typeid of the type held by this value.
static VtValue Cast(VtValue const &val)
Return a VtValue holding val cast to hold T.
Definition: value.h:898
VtValue & operator=(VtValue &&other) noexcept
Move assignment from another VtValue.
Definition: value.h:696
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:865
A simple type-erased container that provides only destruction, moves and immutable, untyped access to the held value.
Definition: anyUniquePtr.h:43
GF_API std::ostream & operator<<(std::ostream &, const GfBBox3d &)
Output a GfBBox3d using the format [(range) matrix zeroArea].
static void RegisterCast(VtValue(*castFn)(VtValue const &))
Register a cast from VtValue holding From to VtValue holding To.
Definition: value.h:871
VtValue & operator=(char *cstr)
Assigning a char * gives a VtValue holding a std::string.
Definition: value.h:736
Boost Python object wrapper.
Definition: pyObjWrapper.h:66
VtValue(T const &obj)
Construct a VtValue holding a copy of obj.
Definition: value.h:655
VT_API size_t GetHash() const
Return a hash code for the held object by calling VtHashValue() on it.
VtValue & Swap(VtValue &rhs) noexcept
Swap this with rhs.
Definition: value.h:741
void UncheckedSwap(VtValue &rhs)
Definition: value.h:781
friend void swap(VtValue &lhs, VtValue &rhs)
Overloaded swap() for generic code/stl/etc.
Definition: value.h:753
TfType represents a dynamic runtime type.
Definition: type.h:70
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:963
VtValue()
Default ctor gives empty VtValue.
Definition: value.h:637
T Remove()
Make this value empty and return the held T instance.
Definition: value.h:787
bool IsEmpty() const
Returns true iff this value is empty.
Definition: value.h:990
Provides a container which may hold any type, and provides introspection and iteration over array typ...
Definition: value.h:182
VtValue & operator=(VtValue const &other)
Copy assignment from another VtValue.
Definition: value.h:689
bool TfSafeTypeCompare(const std::type_info &t1, const std::type_info &t2)
Safely compare std::type_info structures.