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