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