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