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 
25 #include "pxr/pxr.h"
26 
27 #include "pxr/base/tf/type.h"
28 
29 #include "pxr/base/arch/demangle.h"
30 #include "pxr/base/tf/hash.h"
31 #include "pxr/base/tf/hashmap.h"
32 #include "pxr/base/tf/instantiateSingleton.h"
33 #include "pxr/base/tf/iterator.h"
34 #include "pxr/base/tf/mallocTag.h"
35 #include "pxr/base/tf/scopeDescription.h"
36 #include "pxr/base/tf/singleton.h"
37 #include "pxr/base/tf/stl.h"
38 #include "pxr/base/tf/stringUtils.h"
39 #include "pxr/base/tf/typeInfoMap.h"
40 #include "pxr/base/tf/typeNotice.h"
41 
42 #ifdef PXR_PYTHON_SUPPORT_ENABLED
43 // XXX: This include is a hack to avoid build errors due to
44 // incompatible macro definitions in pyport.h on macOS.
45 #include <locale>
46 #include "pxr/base/tf/cxxCast.h"
47 #include "pxr/base/tf/pyLock.h"
48 #include "pxr/base/tf/pyObjWrapper.h"
49 #include "pxr/base/tf/pyObjectFinder.h"
50 #include "pxr/base/tf/pyUtils.h"
51 #endif // PXR_PYTHON_SUPPORT_ENABLED
52 
53 #include <boost/noncopyable.hpp>
54 #include <boost/optional.hpp>
55 #include <boost/utility/in_place_factory.hpp>
56 
57 #include <tbb/spin_rw_mutex.h>
58 
59 #include <atomic>
60 #include <algorithm>
61 #include <iostream>
62 #include <map>
63 #include <memory>
64 #include <vector>
65 
66 #include <thread>
67 
68 using std::map;
69 using std::pair;
70 using std::string;
71 using std::vector;
72 
73 PXR_NAMESPACE_OPEN_SCOPE
74 
75 typedef vector<TfType> TypeVector;
76 
77 using RWMutex = tbb::spin_rw_mutex;
78 using ScopedLock = tbb::spin_rw_mutex::scoped_lock;
79 
~FactoryBase()80 TfType::FactoryBase::~FactoryBase()
81 {
82 }
83 
84 #ifdef PXR_PYTHON_SUPPORT_ENABLED
~PyPolymorphicBase()85 TfType::PyPolymorphicBase::~PyPolymorphicBase()
86 {
87 }
88 #endif // PXR_PYTHON_SUPPORT_ENABLED
89 
90 // Stored data for a TfType.
91 // A unique instance of _TypeInfo is allocated for every type declared.
92 //
93 struct TfType::_TypeInfo : boost::noncopyable
94 {
95     typedef TfHashMap<string, TfType::_TypeInfo*, TfHash> NameToTypeMap;
96     typedef TfHashMap<
97         TfType::_TypeInfo*, vector<string>, TfHash> TypeToNamesMap;
98     typedef TfHashMap<string, TfType, TfHash> DerivedByNameCache;
99 
100     // Unique TfType instance, for returning const references to.
101     TfType canonicalTfType;
102 
103     // Unique type name.
104     const string typeName;
105 
106     // Callback invoked to define this type when first required.
107     TfType::DefinitionCallback definitionCallback;
108 
109     // C++ type_info.  NULL if no C++ type has been defined.
110     std::atomic<std::type_info const *> typeInfo;
111 
112     // The size returned by sizeof(type).
113     size_t sizeofType;
114 
115 #ifdef PXR_PYTHON_SUPPORT_ENABLED
116     // Python class handle.
117     // We use handle<> rather than boost::python::object in case Python
118     // has not yet been initialized.
119     boost::python::handle<> pyClass;
120 #endif // PXR_PYTHON_SUPPORT_ENABLED
121 
122     // Direct base types.
123     TypeVector baseTypes;
124 
125     // Direct derived types.
126     TypeVector derivedTypes;
127 
128     // Factory.
129     std::unique_ptr<TfType::FactoryBase> factory;
130 
131     // Map of derived type aliases to derived types.
132     boost::optional<NameToTypeMap> aliasToDerivedTypeMap;
133     // Reverse map of derived types to their aliases.
134     boost::optional<TypeToNamesMap> derivedTypeToAliasesMap;
135 
136     // Map of functions for converting to other types.
137     // This map is keyed by type_info and not TfType because the TfTypes
138     // may not have been defined yet at the time we are adding castFuncs.
139     // It is expected that the entries here will ultimately have matching
140     // entries in our baseTypes, although that is not enforced.
141     vector<pair<std::type_info const *, TfType::_CastFunction> > castFuncs;
142 
143     std::unique_ptr<DerivedByNameCache> derivedByNameCache;
144 
145     // Traits about the static type.
146     bool isPodType;
147     bool isEnumType;
148 
149     // True if we have sent a TfTypeWasDeclaredNotice for this type.
150     bool hasSentNotice;
151 
152     mutable RWMutex mutex;
153 
154     ////////////////////////////////////////////////////////////////////////
155 
156     // A type is "defined" as soon as it has either type_info or a
157     // Python class object.
IsDefinedTfType::_TypeInfo158     inline bool IsDefined() {
159 #ifdef PXR_PYTHON_SUPPORT_ENABLED
160         return typeInfo.load() != nullptr || pyClass.get();
161 #else
162         return typeInfo.load() != nullptr;
163 #endif // PXR_PYTHON_SUPPORT_ENABLED
164     }
165 
166     // Caller must hold a write lock on mutex.
SetCastFuncTfType::_TypeInfo167     void SetCastFunc(std::type_info const &baseType,
168                      TfType::_CastFunction const &func) {
169         // check for existing func.
170         for (size_t i = 0; i < castFuncs.size(); ++i) {
171             if (baseType == *castFuncs[i].first) {
172                 castFuncs[i].second = func;
173                 return;
174             }
175         }
176         // need to add a new func.
177         castFuncs.push_back(std::make_pair(&baseType, func));
178     }
179 
180     // Caller must hold at least a read lock on mutex.
GetCastFuncTfType::_TypeInfo181     TfType::_CastFunction *GetCastFunc(std::type_info const &baseType) {
182         for (size_t i = 0; i < castFuncs.size(); ++i)
183             if (TfSafeTypeCompare(baseType, *castFuncs[i].first))
184                 return &castFuncs[i].second;
185         return 0;
186     }
187 
188     // Caller must hold at least a read lock on mutex.
FindByAliasTfType::_TypeInfo189     _TypeInfo *FindByAlias(std::string const &alias) const {
190         if (aliasToDerivedTypeMap) {
191             auto it = aliasToDerivedTypeMap->find(alias);
192             return it != aliasToDerivedTypeMap->end() ? it->second : nullptr;
193         }
194         return nullptr;
195     }
196 
197     // Allocate an empty (undefined) _TypeInfo with the given typeName.
_TypeInfoTfType::_TypeInfo198     _TypeInfo(const string &newTypeName) :
199         canonicalTfType(this),
200         typeName(newTypeName),
201         definitionCallback(nullptr),
202         typeInfo(nullptr),
203         sizeofType(0),
204         isPodType(false),
205         isEnumType(false),
206         hasSentNotice(false)
207     {
208     }
209 };
210 
211 #ifdef PXR_PYTHON_SUPPORT_ENABLED
212 // Comparison for boost::python::handle.
213 struct Tf_PyHandleLess
214 {
operator ()Tf_PyHandleLess215     bool operator()(const boost::python::handle<> &lhs,
216                     const boost::python::handle<> &rhs) const {
217         return lhs.get() < rhs.get();
218     }
219 };
220 #endif // PXR_PYTHON_SUPPORT_ENABLED
221 
222 // Registry for _TypeInfos.
223 //
224 class Tf_TypeRegistry : boost::noncopyable
225 {
226 public:
GetInstance()227     static Tf_TypeRegistry& GetInstance() {
228         return TfSingleton<Tf_TypeRegistry>::GetInstance();
229     }
230 
GetMutex() const231     RWMutex &GetMutex() const { return _mutex; }
232 
WaitForInitializingThread() const233     inline void WaitForInitializingThread() const {
234         // If we are the initializing thread or if the registry is initialized,
235         // we don't have to wait.
236         std::thread::id initId = _initializingThread;
237         if (initId == std::thread::id() ||
238             initId == std::this_thread::get_id()) {
239             return;
240         }
241 
242         // Otherwise spin until initialization is complete.
243         while (_initializingThread != std::thread::id()) {
244             std::this_thread::yield();
245         }
246     }
247 
248     // Note, callers must hold the registry lock for writing, and base's lock
249     // for writing, but need not hold derived's lock.
AddTypeAlias(TfType::_TypeInfo * base,TfType::_TypeInfo * derived,const string & alias,string * errMsg)250     void AddTypeAlias(TfType::_TypeInfo *base, TfType::_TypeInfo *derived,
251                       const string &alias, string *errMsg) {
252         // Aliases cannot conflict with other aliases under the same base.
253         if (base->aliasToDerivedTypeMap) {
254             TfType::_TypeInfo::NameToTypeMap::const_iterator it =
255                 base->aliasToDerivedTypeMap->find(alias);
256             if (it != base->aliasToDerivedTypeMap->end()) {
257                 if (it->second == derived) {
258                     // Alias already exists; no change.
259                     return;
260                 } else {
261                     *errMsg = TfStringPrintf(
262                         "Cannot set alias '%s' under '%s', because "
263                         "it is already set to '%s', not '%s'.",
264                         alias.c_str(),
265                         base->typeName.c_str(),
266                         it->second->typeName.c_str(),
267                         derived->typeName.c_str());
268                     return;
269                 }
270             }
271         }
272         // Aliases cannot conflict with typeNames that are derived from the
273         // same base, either.
274         const auto it = _typeNameToTypeMap.find(alias);
275         if (it != _typeNameToTypeMap.end() &&
276             it->second->canonicalTfType._IsAImpl(base->canonicalTfType)) {
277             *errMsg = TfStringPrintf(
278                 "There already is a type named '%s' derived from base "
279                 "type '%s'; cannot create an alias of the same name.",
280                 alias.c_str(), base->typeName.c_str());
281             return;
282         }
283 
284         if (!base->aliasToDerivedTypeMap)
285             base->aliasToDerivedTypeMap = boost::in_place(0);
286         (*base->aliasToDerivedTypeMap)[alias] = derived;
287 
288         if (!base->derivedTypeToAliasesMap)
289             base->derivedTypeToAliasesMap = boost::in_place(0);
290         (*base->derivedTypeToAliasesMap)[derived].push_back(alias);
291     }
292 
NewTypeInfo(const string & typeName)293     TfType::_TypeInfo *NewTypeInfo(const string &typeName) {
294         TfType::_TypeInfo *info = new TfType::_TypeInfo(typeName);
295         _typeNameToTypeMap[typeName] = info;
296         return info;
297     }
298 
SetTypeInfo(TfType::_TypeInfo * info,const std::type_info & typeInfo,size_t sizeofType,bool isPodType,bool isEnumType)299     void SetTypeInfo(TfType::_TypeInfo *info, const std::type_info & typeInfo,
300                      size_t sizeofType, bool isPodType, bool isEnumType) {
301         info->typeInfo = &typeInfo;
302         info->sizeofType = sizeofType;
303         info->isPodType = isPodType;
304         info->isEnumType = isEnumType;
305         _typeInfoMap.Set(typeInfo, info);
306     }
307 
308 #ifdef PXR_PYTHON_SUPPORT_ENABLED
SetPythonClass(TfType::_TypeInfo * info,const boost::python::object & classObj)309     void SetPythonClass(TfType::_TypeInfo *info,
310                         const boost::python::object & classObj) {
311         // Hold a reference to this PyObject in our map.
312         boost::python::handle<> handle(
313             boost::python::borrowed(classObj.ptr()));
314 
315         info->pyClass = handle;
316         _pyClassMap[handle] = info;
317 
318         // Do not overwrite the size of a C++ type.
319         if (!info->sizeofType) {
320             info->sizeofType = TfSizeofType<boost::python::object>::value;
321         }
322     }
323 #endif // PXR_PYTHON_SUPPORT_ENABLED
324 
GetUnknownType() const325     TfType::_TypeInfo *GetUnknownType() const { return _unknownTypeInfo; }
326 
GetRoot() const327     TfType::_TypeInfo *GetRoot() const { return _rootTypeInfo; }
328 
FindByName(const string & name) const329     TfType::_TypeInfo *FindByName(const string &name) const {
330         auto it = _typeNameToTypeMap.find(name);
331         return it != _typeNameToTypeMap.end() ? it->second : nullptr;
332     }
333 
334     template <class Upgrader>
335     TfType::_TypeInfo *
FindByTypeid(const std::type_info & typeInfo,Upgrader upgrader)336     FindByTypeid(const std::type_info &typeInfo, Upgrader upgrader) {
337         TfType::_TypeInfo **info = _typeInfoMap.Find(typeInfo, upgrader);
338         return info ? *info : nullptr;
339     }
340 
341 #ifdef PXR_PYTHON_SUPPORT_ENABLED
342     TfType::_TypeInfo *
FindByPythonClass(const boost::python::object & classObj) const343     FindByPythonClass(const boost::python::object &classObj) const {
344         boost::python::handle<> handle(
345             boost::python::borrowed(classObj.ptr()));
346         auto it = _pyClassMap.find(handle);
347         return it != _pyClassMap.end() ? it->second : nullptr;
348     }
349 #endif // PXR_PYTHON_SUPPORT_ENABLED
350 
351 private:
352     Tf_TypeRegistry();
353 
354     mutable RWMutex _mutex;
355 
356     // The thread that is currently performing initialization.  This is set to a
357     // default-constructed thread::id when initialization is complete.
358     mutable std::atomic<std::thread::id> _initializingThread;
359 
360     // Map of typeName to _TypeInfo*.
361     // This holds all declared types, by unique typename.
362     TfType::_TypeInfo::NameToTypeMap _typeNameToTypeMap;
363 
364     // Map of type_info to _TypeInfo*.
365     // This holds info for types that have been defined as C++ types.
366     // XXX: change this to regular hash table?
367     TfTypeInfoMap<TfType::_TypeInfo*> _typeInfoMap;
368 
369 #ifdef PXR_PYTHON_SUPPORT_ENABLED
370     // Map of python class handles to _TypeInfo*.
371     typedef map<boost::python::handle<>,
372                 TfType::_TypeInfo *, Tf_PyHandleLess> PyClassMap;
373     PyClassMap _pyClassMap;
374 #endif // PXR_PYTHON_SUPPORT_ENABLED
375 
376     // _TypeInfo for Unknown type
377     TfType::_TypeInfo *_unknownTypeInfo;
378     // _TypeInfo for Root type
379     TfType::_TypeInfo *_rootTypeInfo;
380 
381     // Set true if we should send notification.
382     bool _sendDeclaredNotification;
383 
384     friend class TfSingleton<Tf_TypeRegistry>;
385     friend class TfType;
386 };
387 
388 TF_INSTANTIATE_SINGLETON(Tf_TypeRegistry);
389 
390 // This type is used as the unknown type. Previously, 'void' was used for
391 // that purpose, but clients want to call TfType::Find<void>();.
392 struct _TfUnknownType {};
393 
Tf_TypeRegistry()394 Tf_TypeRegistry::Tf_TypeRegistry() :
395     _unknownTypeInfo(0),
396     _rootTypeInfo(0),
397     _sendDeclaredNotification(false)
398 {
399     // Register root type
400     _rootTypeInfo = NewTypeInfo("TfType::_Root");
401 
402     // Register unknown type
403     _unknownTypeInfo = NewTypeInfo("TfType::_Unknown");
404     SetTypeInfo(_unknownTypeInfo, typeid(_TfUnknownType),
405                 /*sizeofType=*/0, /*isPodType=*/false, /*isEnumType=*/false);
406 
407     // Put the registry into an "initializing" state so that racing to get the
408     // singleton instance (which will start happening immediately after calling
409     // SetInstanceConstructed) will wait until initial type registrations are
410     // completed.  Note that we only allow *this* thread to query the registry
411     // until initialization is finished.  Others will wait.
412     _initializingThread = std::this_thread::get_id();
413     TfSingleton<Tf_TypeRegistry>::SetInstanceConstructed(*this);
414 
415     // We send TfTypeWasDeclaredNotice() when a type is first declared with
416     // bases.  Because TfNotice delivery uses TfType, we first register both
417     // TfNotice and TfTypeWasDeclaredNotice -- without sending
418     // TfTypeWasDeclaredNotice for them -- before subscribing to the TfType
419     // registry.
420     TfType::Define<TfNotice>();
421     TfType::Define<TfTypeWasDeclaredNotice, TfType::Bases<TfNotice> >();
422 
423     // From this point on, we'll send notices as new types are discovered.
424     _sendDeclaredNotification = true;
425 
426     try {
427         TfRegistryManager::GetInstance().SubscribeTo<TfType>();
428         _initializingThread = std::thread::id();
429     } catch (...) {
430         // Ensure we mark initialization completed in the face of an exception.
431         _initializingThread = std::thread::id();
432         throw;
433     }
434 }
435 
436 ////////////////////////////////////////////////////////////////////////
437 
TfType()438 TfType::TfType() : _info(Tf_TypeRegistry::GetInstance().GetUnknownType())
439 {
440 }
441 
442 TfType const&
GetRoot()443 TfType::GetRoot()
444 {
445     return Tf_TypeRegistry::GetInstance().GetRoot()->canonicalTfType;
446 }
447 
448 TfType const&
GetCanonicalType() const449 TfType::GetCanonicalType() const
450 {
451     return _info->canonicalTfType;
452 }
453 
454 TfType const&
FindByName(const string & name)455 TfType::FindByName(const string &name)
456 {
457     return GetRoot().FindDerivedByName(name);
458 }
459 
460 TfType const&
FindDerivedByName(const string & name) const461 TfType::FindDerivedByName(const string &name) const
462 {
463     if (IsUnknown())
464         return GetUnknownType();
465 
466     TfType result;
467 
468     // Note that we cache results in derivedByNameCache, and we never invalidate
469     // this cache.  This works because 1) we never remove types and type
470     // information from TfType's data structures and 2) we only cache if we find
471     // a valid type.
472     ScopedLock thisInfoLock(_info->mutex, /*write=*/false);
473     if (ARCH_LIKELY(_info->derivedByNameCache &&
474                     TfMapLookup(*(_info->derivedByNameCache), name, &result))) {
475         // Cache hit.  We're done.
476         return result._info->canonicalTfType;
477     }
478     // Look for a type derived from *this, and has the given name as an alias.
479     if (TfType::_TypeInfo *foundInfo = _info->FindByAlias(name)) {
480         result = TfType(foundInfo);
481     }
482     // Finished reading _info data.
483     thisInfoLock.release();
484 
485     // If we didn't find an alias we now look in the registry.
486     if (!result) {
487         const auto &r = Tf_TypeRegistry::GetInstance();
488         r.WaitForInitializingThread();
489         ScopedLock regLock(r.GetMutex(), /*write=*/false);
490         TfType::_TypeInfo *foundInfo = r.FindByName(name);
491         regLock.release();
492         if (foundInfo) {
493             // Next look for a type with the given typename.  If a type was
494             // found, verify that it derives from *this.
495             result = TfType(foundInfo);
496             if (!result.IsA(*this))
497                 result = TfType();
498         }
499     }
500 
501     // Populate cache.
502     if (result) {
503         // It's possible that some other thread has done this already, but it
504         // will be the same result so it's okay to do redundantly in that case.
505         thisInfoLock.acquire(_info->mutex, /*write=*/true);
506         if (!_info->derivedByNameCache) {
507             _info->derivedByNameCache.
508                 reset(new _TypeInfo::DerivedByNameCache(0));
509         }
510         _info->derivedByNameCache->insert(make_pair(name, result));
511     }
512 
513     return result._info->canonicalTfType;
514 }
515 
516 TfType const&
GetUnknownType()517 TfType::GetUnknownType()
518 {
519     return Tf_TypeRegistry::GetInstance().GetUnknownType()->canonicalTfType;
520 }
521 
522 TfType const&
_FindByTypeid(const std::type_info & typeInfo)523 TfType::_FindByTypeid(const std::type_info &typeInfo)
524 {
525     // Functor to upgrade the read lock to a write lock.
526     struct WriteUpgrader {
527         WriteUpgrader(ScopedLock& lock) : lock(lock) { }
528         void operator()() { lock.upgrade_to_writer(); }
529         ScopedLock& lock;
530     };
531 
532     auto &r = Tf_TypeRegistry::GetInstance();
533     r.WaitForInitializingThread();
534 
535     ScopedLock readLock(r.GetMutex(), /*write=*/false);
536     TfType::_TypeInfo *info = r.FindByTypeid(typeInfo, WriteUpgrader(readLock));
537 
538     if (ARCH_LIKELY(info)) {
539         return info->canonicalTfType;
540     }
541     // It's possible that this type is only declared and not yet defined.  In
542     // that case we will fail to find it by type_info, so attempt to find the
543     // type by name instead.
544     return FindByName(GetCanonicalTypeName(typeInfo));
545 }
546 
547 #ifdef PXR_PYTHON_SUPPORT_ENABLED
548 TfType const&
FindByPythonClass(const TfPyObjWrapper & classObj)549 TfType::FindByPythonClass(const TfPyObjWrapper & classObj)
550 {
551     const auto &r = Tf_TypeRegistry::GetInstance();
552     r.WaitForInitializingThread();
553 
554     ScopedLock readLock(r.GetMutex(), /*write=*/false);
555     TfType::_TypeInfo *info = r.FindByPythonClass(classObj.Get());
556 
557     return info ? info->canonicalTfType : GetUnknownType();
558 }
559 #endif // PXR_PYTHON_SUPPORT_ENABLED
560 
561 const string &
GetTypeName() const562 TfType::GetTypeName() const
563 {
564     return _info->typeName;
565 }
566 
567 const std::type_info &
GetTypeid() const568 TfType::GetTypeid() const
569 {
570     std::type_info const *typeInfo = _info->typeInfo;
571     return typeInfo ? *typeInfo : typeid(void);
572 }
573 
574 #ifdef PXR_PYTHON_SUPPORT_ENABLED
575 TfPyObjWrapper
GetPythonClass() const576 TfType::GetPythonClass() const
577 {
578     if (!TfPyIsInitialized())
579         TF_CODING_ERROR("Python has not been initialized");
580 
581     ScopedLock lock(_info->mutex, /*write=*/false);
582     if (_info->pyClass.get())
583         return TfPyObjWrapper(boost::python::object(_info->pyClass));
584     return TfPyObjWrapper();
585 }
586 #endif // PXR_PYTHON_SUPPORT_ENABLED
587 
588 vector<string>
GetAliases(TfType derivedType) const589 TfType::GetAliases(TfType derivedType) const
590 {
591     ScopedLock lock(_info->mutex, /*write=*/false);
592     if (_info->derivedTypeToAliasesMap) {
593         auto i = _info->derivedTypeToAliasesMap->find(derivedType._info);
594         if (i != _info->derivedTypeToAliasesMap->end())
595             return i->second;
596     }
597     return vector<string>();
598 }
599 
600 vector<TfType>
GetBaseTypes() const601 TfType::GetBaseTypes() const
602 {
603     ScopedLock lock(_info->mutex, /*write=*/false);
604     return _info->baseTypes;
605 }
606 
607 size_t
GetNBaseTypes(TfType * out,size_t maxBases) const608 TfType::GetNBaseTypes(TfType *out, size_t maxBases) const
609 {
610     ScopedLock lock(_info->mutex, /*write=*/false);
611     size_t numBases = _info->baseTypes.size();
612     auto b = _info->baseTypes.begin();
613     auto e = b + std::min<size_t>(maxBases, numBases);
614     std::copy(b, e, out);
615     return numBases;
616 }
617 
618 vector<TfType>
GetDirectlyDerivedTypes() const619 TfType::GetDirectlyDerivedTypes() const
620 {
621     ScopedLock lock(_info->mutex, /*write=*/false);
622     return _info->derivedTypes;
623 }
624 
625 void
GetAllDerivedTypes(std::set<TfType> * result) const626 TfType::GetAllDerivedTypes(std::set<TfType> *result) const
627 {
628     ScopedLock lock(_info->mutex, /*write=*/false);
629     for (auto derivedType: _info->derivedTypes) {
630         result->insert(derivedType);
631         derivedType.GetAllDerivedTypes(result);
632     }
633 }
634 
635 // Helper for resolving ancestor order in the case of multiple inheritance.
636 static bool
_MergeAncestors(vector<TypeVector> * seqs,TypeVector * result)637 _MergeAncestors(vector<TypeVector> *seqs, TypeVector *result)
638 {
639     while(true)
640     {
641         // Find a candidate for the next type.
642         TfType cand;
643 
644         // Try the first element of each non-empty sequence, in order.
645         bool anyLeft = false;
646         TF_FOR_ALL(candSeq, *seqs)
647         {
648             if (candSeq->empty())
649                 continue;
650 
651             anyLeft = true;
652             cand = candSeq->front();
653 
654             // Check that the candidate does not occur in the tail
655             // ("cdr", in lisp terms) of any of the sequences.
656             TF_FOR_ALL(checkSeq, *seqs)
657             {
658                 if (checkSeq->size() <= 1)
659                     continue;
660 
661                 if (std::find( ++(checkSeq->begin()), checkSeq->end(), cand )
662                     != checkSeq->end())
663                 {
664                     // Reject this candidate.
665                     cand = TfType();
666                     break;
667                 }
668             }
669 
670             if (!cand.IsUnknown()) {
671                 // Found a candidate
672                 break;
673             }
674         }
675 
676 
677         if (cand.IsUnknown()) {
678             // If we were unable to find a candidate, we're done.
679             // If we've consumed all the inputs, then we've succeeded.
680             // Otherwise, the inheritance hierarchy is inconsistent.
681             return !anyLeft;
682         }
683 
684         result->push_back(cand);
685 
686         // Remove candidate from input sequences.
687         TF_FOR_ALL(seqIt, *seqs) {
688             if (!seqIt->empty() && seqIt->front() == cand)
689                 seqIt->erase( seqIt->begin() );
690         }
691     }
692 }
693 
694 void
GetAllAncestorTypes(vector<TfType> * result) const695 TfType::GetAllAncestorTypes(vector<TfType> *result) const
696 {
697     if (IsUnknown()) {
698         TF_CODING_ERROR("Cannot ask for ancestor types of Unknown type");
699         return;
700     }
701 
702     const vector<TfType> &baseTypes = GetBaseTypes();
703     const size_t numBaseTypes = baseTypes.size();
704 
705     // Simple case: single (or no) inheritance
706     if (numBaseTypes <= 1) {
707         result->push_back(*this);
708         if (numBaseTypes == 1)
709             baseTypes.front().GetAllAncestorTypes(result);
710         return;
711     }
712 
713     // Use the C3 algorithm for resolving multiple inheritance;
714     // see motivating comments in header.  If this turns out to be a
715     // performance problem, consider memoizing this algorithm.
716 
717     vector<TypeVector> seqs;
718     seqs.reserve(2 + numBaseTypes);
719 
720     // 1st input sequence: This class.
721     seqs.push_back( TypeVector() );
722     seqs.back().push_back(*this);
723 
724     // 2nd input sequence: Direct bases, in order.
725     seqs.push_back( baseTypes );
726 
727     // Remaining sequences: Inherited types for each direct base.
728     TF_FOR_ALL(it, baseTypes) {
729         // Populate the base's ancestor types directly into a new vector on
730         // the back of seqs.
731         seqs.push_back( TypeVector() );
732         TypeVector &baseSeq = seqs.back();
733         it->GetAllAncestorTypes(&baseSeq);
734     }
735 
736     // Merge the input sequences to resolve final inheritance order.
737     bool ok = _MergeAncestors( &seqs, result );
738 
739     if (!ok) {
740         TF_CODING_ERROR("Cannot resolve ancestor classes for '%s' "
741                         "because the inheritance hierarchy is "
742                         "inconsistent.  Please check that multiply-"
743                         "inherited types are inherited in the same order "
744                         "throughout the inherited hierarchy.",
745                         GetTypeName().c_str());
746     }
747 }
748 
749 #ifdef PXR_PYTHON_SUPPORT_ENABLED
750 TfType const &
_FindImplPyPolymorphic(PyPolymorphicBase const * ptr)751 TfType::_FindImplPyPolymorphic(PyPolymorphicBase const *ptr) {
752     using namespace boost::python;
753     TfType ret;
754     if (TfPyIsInitialized()) {
755         TfPyLock lock;
756         // See if we can find a polymorphic python object...
757         object pyObj = Tf_FindPythonObject(
758             TfCastToMostDerivedType(ptr), typeid(*ptr));
759         if (!TfPyIsNone(pyObj))
760             ret = FindByPythonClass(
761                 TfPyObjWrapper(pyObj.attr("__class__")));
762     }
763     return !ret.IsUnknown() ? ret.GetCanonicalType() : Find(typeid(*ptr));
764 }
765 #endif // PXR_PYTHON_SUPPORT_ENABLED
766 
767 bool
_IsAImpl(TfType queryType) const768 TfType::_IsAImpl(TfType queryType) const
769 {
770     // Iterate until we reach more than one parent.
771     for (TfType t = *this; ; ) {
772         if (t == queryType)
773             return true;
774 
775         ScopedLock lock(t._info->mutex, /*write=*/false);
776         if (t._info->baseTypes.size() == 1) {
777             t = t._info->baseTypes[0];
778             continue;
779         }
780         for (size_t i = 0; i != t._info->baseTypes.size(); i++)
781             if (t._info->baseTypes[i]._IsAImpl(queryType))
782                 return true;
783         return false;
784     }
785 }
786 
787 bool
IsA(TfType queryType) const788 TfType::IsA(TfType queryType) const
789 {
790     if (queryType.IsUnknown()) {
791         // If queryType is unknown, it almost always means a previous
792         // type lookup failed, and went unchecked.
793         TF_RUNTIME_ERROR("IsA() was given an Unknown base type.  "
794                          "This probably means the attempt to look up the "
795                          "base type failed.  (Note: to explicitly check if a "
796                          "type is unknown, use IsUnknown() instead.)");
797         return false;
798     }
799     if (IsUnknown()) {
800         return false;
801     }
802 
803     if (*this == queryType || queryType.IsRoot()) {
804         return true;
805     }
806 
807     // If the query type doesn't have any child types, then iterating over all
808     // our base types wastes time.
809     ScopedLock queryLock(queryType._info->mutex, /*write=*/false);
810     if (queryType._info->derivedTypes.empty()) {
811         return false;
812     }
813     queryLock.release();
814 
815     // printf("--- %s IsA %s { ",
816     //        GetTypeName().c_str(), queryType.GetTypeName().c_str());
817 
818     bool ret = _IsAImpl(queryType);
819 
820     // printf(" } = %d\n", ret);
821 
822     return ret;
823 }
824 
825 TfType const &
Declare(const string & typeName)826 TfType::Declare(const string &typeName)
827 {
828     TfAutoMallocTag2 tag("Tf", "TfType::Declare");
829 
830     TfType t = FindByName(typeName);
831     if (t.IsUnknown()) {
832         auto &r = Tf_TypeRegistry::GetInstance();
833         ScopedLock lock(r.GetMutex(), /*write=*/true);
834         t = TfType(r.NewTypeInfo(typeName));
835         TF_AXIOM(!t._info->IsDefined());
836     }
837     return t.GetCanonicalType();
838 }
839 
840 TfType const&
Declare(const string & typeName,const vector<TfType> & newBases,DefinitionCallback definitionCallback)841 TfType::Declare(const string &typeName,
842                 const vector<TfType> &newBases,
843                 DefinitionCallback definitionCallback)
844 {
845     TfAutoMallocTag2 tag("Tf", "TfType::Declare");
846     TF_DESCRIBE_SCOPE(typeName);
847 
848     TfType const& t = Declare(typeName);
849 
850     // Check that t does not appear in newBases.  This is not comprehensive: t
851     // could be a base of one of the types in newBases, but doing an exhaustive
852     // search is not cheap, and getting it wrong will cause deadlock at
853     // registration time (so it will get noticed and fixed).  But this limited
854     // check helps debugging & fixing the most common case of getting this
855     // wrong.
856     auto iter = std::find(newBases.begin(), newBases.end(), t);
857     if (iter != newBases.end()) {
858         TF_FATAL_ERROR("TfType '%s' declares itself as a base.",
859                        typeName.c_str());
860     }
861 
862     bool sendNotice = false;
863     vector<string> errorsToEmit;
864     {
865         auto &r = Tf_TypeRegistry::GetInstance();
866         ScopedLock regLock(r.GetMutex(), /*write=*/true);
867         ScopedLock typeLock(t._info->mutex, /*write=*/true);
868 
869         if (t.IsUnknown() || t.IsRoot()) {
870             errorsToEmit.push_back(
871                 TfStringPrintf("Cannot declare the type '%s'",
872                                t.GetTypeName().c_str()));
873             goto errorOut;
874         }
875 
876         // Update base types.
877         const vector<TfType> &haveBases = t._info->baseTypes;
878 
879         // If this type already directly inherits from root, then
880         // prohibit adding any new bases.
881         if (!newBases.empty() &&
882             haveBases.size() == 1 && haveBases.front() == GetRoot()) {
883             errorsToEmit.push_back(
884                 TfStringPrintf("Type '%s' has been declared to have 0 bases, "
885                                "and therefore inherits directly from the root "
886                                "type.  Cannot add bases.",
887                                t.GetTypeName().c_str()));
888             goto errorOut;
889         }
890 
891         if (newBases.empty()) {
892             if (haveBases.empty()) {
893                 // If we don't have any bases yet, add the root type.
894                 t._AddBases(TypeVector(1, GetRoot()), &errorsToEmit);
895             }
896         } else {
897             // Otherwise, add the new bases.
898             t._AddBases(newBases, &errorsToEmit);
899         }
900 
901         if (definitionCallback) {
902             // Prohibit re-declaration of definitionCallback.
903             if (t._info->definitionCallback) {
904                 errorsToEmit.push_back(
905                     TfStringPrintf("TfType '%s' has already had its "
906                                    "definitionCallback set; ignoring 2nd "
907                                    "declaration", typeName.c_str()));
908                 goto errorOut;
909             }
910             t._info->definitionCallback = definitionCallback;
911         }
912 
913         // Send a notice about this type if we have not done so yet.
914         if (r._sendDeclaredNotification && !t._info->hasSentNotice) {
915             t._info->hasSentNotice = sendNotice = true;
916         }
917     }
918 
919     if (sendNotice)
920         TfTypeWasDeclaredNotice(t).Send();
921 
922 errorOut:
923 
924     // Emit any errors.
925     for (auto const &msg: errorsToEmit)
926         TF_CODING_ERROR(msg);
927 
928     return t;
929 }
930 
931 #ifdef PXR_PYTHON_SUPPORT_ENABLED
932 void
DefinePythonClass(const TfPyObjWrapper & classObj) const933 TfType::DefinePythonClass(const TfPyObjWrapper & classObj) const
934 {
935     if (IsUnknown() || IsRoot()) {
936         TF_CODING_ERROR("cannot define Python class because type is unknown");
937         return;
938     }
939     auto &r = Tf_TypeRegistry::GetInstance();
940     ScopedLock infoLock(_info->mutex, /*write=*/true);
941     ScopedLock regLock(r.GetMutex(), /*write=*/true);
942     if (!TfPyIsNone(_info->pyClass)) {
943         infoLock.release();
944         regLock.release();
945         TF_CODING_ERROR("TfType '%s' already has a defined Python type; "
946                         "cannot redefine", GetTypeName().c_str());
947         return;
948     }
949     r.SetPythonClass(_info, classObj.Get());
950 }
951 #endif // PXR_PYTHON_SUPPORT_ENABLED
952 
953 void
_DefineCppType(const std::type_info & typeInfo,size_t sizeofType,bool isPodType,bool isEnumType) const954 TfType::_DefineCppType(const std::type_info & typeInfo,
955                        size_t sizeofType, bool isPodType, bool isEnumType) const
956 {
957     auto &r = Tf_TypeRegistry::GetInstance();
958     ScopedLock infoLock(_info->mutex, /*write=*/true);
959     ScopedLock regLock(r.GetMutex(), /*write=*/true);
960     if (_info->typeInfo.load() != nullptr) {
961         infoLock.release();
962         regLock.release();
963         TF_CODING_ERROR("TfType '%s' already has a defined C++ type; "
964                         "cannot redefine", GetTypeName().c_str());
965         return;
966     }
967     r.SetTypeInfo(_info, typeInfo, sizeofType, isPodType, isEnumType);
968 }
969 
970 void
_AddBases(const TypeVector & newBases,vector<string> * errorsToEmit) const971 TfType::_AddBases(
972     const TypeVector &newBases, vector<string> *errorsToEmit) const
973 {
974     // Callers must hold _info write lock.
975     TypeVector &haveBases = _info->baseTypes;
976 
977     // Also we check that all previously-declared bases are included and make
978     // sure that a subsequent registration of base types doesn't change the
979     // order.
980     TypeVector::const_iterator lastNewBaseIter = newBases.begin();
981 
982     for(const TfType &haveBase : haveBases) {
983 
984         const TypeVector::const_iterator newIter =
985             std::find(newBases.begin(), newBases.end(), haveBase);
986 
987         // Repeated base declaration must include all previous bases.
988         if (newIter == newBases.end()) {
989 
990             string newBasesStr;
991             for(const TfType &newBase : newBases) {
992                 newBasesStr += newBasesStr.empty() ? "" : ", ";
993                 newBasesStr += newBase.GetTypeName();
994             }
995 
996             errorsToEmit->push_back(TfStringPrintf(
997                 "TfType '%s' was previously declared to have '%s' as a base, "
998                 "but a subsequent declaration does not include this as a base.  "
999                 "The newly given bases were: (%s).  If this is a type declared "
1000                 "in a plugin, check that the plugin metadata is correct.",
1001                 GetTypeName().c_str(),
1002                 haveBase.GetTypeName().c_str(),
1003                 newBasesStr.c_str()));
1004 
1005         } else {
1006 
1007             // Make sure the new bases are also ordered strictly monotonically
1008             // increasing so that it matches the old order.
1009 
1010             if (lastNewBaseIter > newIter) {
1011 
1012                 std::string haveStr, newStr;
1013                 for(const TfType &t : haveBases) {
1014                     haveStr += haveStr.empty() ? "" : ", ";
1015                     haveStr += t.GetTypeName();
1016                 }
1017                 for(const TfType &t : newBases) {
1018                     newStr += newStr.empty() ? "" : ", ";
1019                     newStr += t.GetTypeName();
1020                 }
1021                 errorsToEmit->push_back(TfStringPrintf(
1022                     "Specified base type order differs for %s: had (%s), now "
1023                     "(%s).  If this is a type declared in a plugin, check that "
1024                     "the plugin metadata is correct.",
1025                     GetTypeName().c_str(), haveStr.c_str(), newStr.c_str()));
1026             }
1027 
1028             lastNewBaseIter = newIter;
1029         }
1030     }
1031 
1032     // If we now have more base types, we use the new, longer vector of base
1033     // types to define the order.  Note that we don't need to register any
1034     // derived types in that case, because we just ensured we only expanding
1035     // the set of bases.
1036 
1037     if (newBases.size() > haveBases.size()) {
1038 
1039         for(const TfType &newBase : newBases) {
1040             if (newBase.IsUnknown()) {
1041                 errorsToEmit->push_back(
1042                     "Specified base type is unknown, skipping.");
1043                 continue;
1044             }
1045             if (std::find(haveBases.begin(), haveBases.end(), newBase) ==
1046                 haveBases.end()) {
1047 
1048                 // Tell the new base that it has a new derived type.
1049                 ScopedLock baseLock(newBase._info->mutex, /*write=*/true);
1050                 newBase._info->derivedTypes.push_back(*this);
1051             }
1052         }
1053 
1054         // Fully replace the list of existing bases if needed.  This is so that
1055         // we set the order even if we register bases for a type (partially)
1056         // multiple times.
1057         _info->baseTypes = newBases;
1058     }
1059 }
1060 
1061 void
_AddCppCastFunc(const std::type_info & baseTypeInfo,_CastFunction func) const1062 TfType::_AddCppCastFunc( const std::type_info & baseTypeInfo,
1063                          _CastFunction func ) const
1064 {
1065     ScopedLock infoLock(_info->mutex, /*write=*/true);
1066     _info->SetCastFunc(baseTypeInfo, func);
1067 }
1068 
1069 void*
CastToAncestor(TfType ancestor,void * addr) const1070 TfType::CastToAncestor(TfType ancestor, void* addr) const
1071 {
1072     if (IsUnknown() || ancestor.IsUnknown())
1073         return 0;
1074 
1075     // Iterate until we reach more than one parent.
1076     for (TfType t = *this; ; ) {
1077         if (t == ancestor)
1078             return addr;
1079         ScopedLock lock(t._info->mutex, /*write=*/false);
1080         if (t._info->baseTypes.size() == 1) {
1081             _CastFunction *castFunc =
1082                 t._info->GetCastFunc(t._info->baseTypes[0].GetTypeid());
1083             if (castFunc) {
1084                 addr = (*castFunc)(addr, true);
1085                 t = t._info->baseTypes[0];
1086                 continue;
1087             } else {
1088                 return nullptr;
1089             }
1090         }
1091         for (size_t i = 0; i < t._info->baseTypes.size(); i++) {
1092             _CastFunction *castFunc =
1093                 t._info->GetCastFunc(t._info->baseTypes[i].GetTypeid());
1094             if (castFunc) {
1095                 void *pAddr = (*castFunc)(addr, true);
1096                 if (void *final =
1097                     t._info->baseTypes[i].CastToAncestor(ancestor, pAddr))
1098                     return final;
1099             }
1100         }
1101         return nullptr;
1102     }
1103 }
1104 
1105 void*
CastFromAncestor(TfType ancestor,void * addr) const1106 TfType::CastFromAncestor(TfType ancestor, void* addr) const
1107 {
1108     if (IsUnknown() || ancestor.IsUnknown())
1109         return 0;
1110 
1111     // No iteration: we have to do the purely recursively, because
1112     // each cast has to happen on the way back *down* the type tree.
1113     if (*this == ancestor)
1114         return addr;
1115 
1116     ScopedLock lock(_info->mutex, /*write=*/false);
1117     TF_FOR_ALL(it, _info->baseTypes) {
1118         if (void* tmp = it->CastFromAncestor(ancestor, addr)) {
1119             if (_CastFunction *castFunc = _info->GetCastFunc(it->GetTypeid()))
1120                 return (*castFunc)(tmp, false);
1121         }
1122     }
1123 
1124     return nullptr;
1125 }
1126 
1127 void
SetFactory(std::unique_ptr<FactoryBase> factory) const1128 TfType::SetFactory(std::unique_ptr<FactoryBase> factory) const
1129 {
1130     if (IsUnknown() || IsRoot()) {
1131         TF_CODING_ERROR("Cannot set factory of %s\n",
1132                         GetTypeName().c_str());
1133         return;
1134     }
1135 
1136     ScopedLock infoLock(_info->mutex, /*write=*/true);
1137     if (_info->factory) {
1138         infoLock.release();
1139         TF_CODING_ERROR("Cannot change the factory of %s\n",
1140                         GetTypeName().c_str());
1141         return;
1142     }
1143 
1144     _info->factory = std::move(factory);
1145 }
1146 
1147 TfType::FactoryBase*
_GetFactory() const1148 TfType::_GetFactory() const
1149 {
1150     if (IsUnknown() || IsRoot()) {
1151         TF_CODING_ERROR("Cannot manufacture type %s", GetTypeName().c_str());
1152         return NULL;
1153     }
1154 
1155     _ExecuteDefinitionCallback();
1156 
1157     ScopedLock infoLock(_info->mutex, /*write=*/false);
1158     return _info->factory.get();
1159 }
1160 
1161 void
_ExecuteDefinitionCallback() const1162 TfType::_ExecuteDefinitionCallback() const
1163 {
1164     // We don't want to call the definition callback while holding the
1165     // registry's lock, so first copy it with the lock held then
1166     // execute it.
1167     ScopedLock infoLock(_info->mutex, /*write=*/false);
1168     if (DefinitionCallback definitionCallback = _info->definitionCallback) {
1169         infoLock.release();
1170         definitionCallback(*this);
1171     }
1172 }
1173 
1174 string
GetCanonicalTypeName(const std::type_info & t)1175 TfType::GetCanonicalTypeName(const std::type_info &t)
1176 {
1177     TfAutoMallocTag2 tag("Tf", "TfType::GetCanonicalTypeName");
1178 
1179     using LookupMap =
1180         TfHashMap<std::type_index, std::string, std::hash<std::type_index>>;
1181     static LookupMap lookupMap;
1182 
1183     static RWMutex mutex;
1184     ScopedLock lock(mutex, /* write = */ false);
1185 
1186     const std::type_index typeIndex(t);
1187     const LookupMap &map = lookupMap;
1188     const LookupMap::const_iterator iter = map.find(typeIndex);
1189     if (iter != lookupMap.end()) {
1190         return iter->second;
1191     }
1192 
1193     lock.upgrade_to_writer();
1194     return lookupMap.insert({typeIndex, ArchGetDemangled(t)}).first->second;
1195 }
1196 
1197 void
AddAlias(TfType base,const string & name) const1198 TfType::AddAlias(TfType base, const string & name) const
1199 {
1200     std::string errMsg;
1201     {
1202         auto &r = Tf_TypeRegistry::GetInstance();
1203         ScopedLock infoLock(base._info->mutex, /*write=*/true);
1204         ScopedLock regLock(r.GetMutex(), /*write=*/true);
1205         // We do not need to hold our own lock here.
1206         r.AddTypeAlias(base._info, this->_info, name, &errMsg);
1207     }
1208 
1209     if (!errMsg.empty())
1210         TF_CODING_ERROR(errMsg);
1211 }
1212 
1213 bool
IsEnumType() const1214 TfType::IsEnumType() const
1215 {
1216     ScopedLock lock(_info->mutex, /*write=*/false);
1217     return _info->isEnumType;
1218 }
1219 
1220 bool
IsPlainOldDataType() const1221 TfType::IsPlainOldDataType() const
1222 {
1223     ScopedLock lock(_info->mutex, /*write=*/false);
1224     return _info->isPodType;
1225 }
1226 
1227 size_t
GetSizeof() const1228 TfType::GetSizeof() const
1229 {
1230     ScopedLock lock(_info->mutex, /*write=*/false);
1231     return _info->sizeofType;
1232 }
1233 
1234 
TF_REGISTRY_FUNCTION(TfType)1235 TF_REGISTRY_FUNCTION(TfType)
1236 {
1237     TfType::Define<void>();
1238     TfType::Define<bool>();
1239     TfType::Define<char>();
1240     TfType::Define<signed char>();
1241     TfType::Define<unsigned char>();
1242     TfType::Define<short>();
1243     TfType::Define<unsigned short>();
1244     TfType::Define<int>();
1245     TfType::Define<unsigned int>();
1246     TfType::Define<long>();
1247     TfType::Define<unsigned long>().AddAlias( TfType::GetRoot(), "size_t" );
1248     TfType::Define<long long>();
1249     TfType::Define<unsigned long long>();
1250     TfType::Define<float>();
1251     TfType::Define<double>();
1252     TfType::Define<string>();
1253 
1254     TfType::Define< vector<bool> >()
1255         .AddAlias( TfType::GetRoot(), "vector<bool>" );
1256     TfType::Define< vector<char> >()
1257         .AddAlias( TfType::GetRoot(), "vector<char>" );
1258     TfType::Define< vector<unsigned char> >()
1259         .AddAlias( TfType::GetRoot(), "vector<unsigned char>" );
1260     TfType::Define< vector<short> >()
1261         .AddAlias( TfType::GetRoot(), "vector<short>" );
1262     TfType::Define< vector<unsigned short> >()
1263         .AddAlias( TfType::GetRoot(), "vector<unsigned short>" );
1264     TfType::Define< vector<int> >()
1265         .AddAlias( TfType::GetRoot(), "vector<int>" );
1266     TfType::Define< vector<unsigned int> >()
1267         .AddAlias( TfType::GetRoot(), "vector<unsigned int>" );
1268     TfType::Define< vector<long> >()
1269         .AddAlias( TfType::GetRoot(), "vector<long>" );
1270 
1271     TfType ulvec = TfType::Define< vector<unsigned long> >();
1272     ulvec.AddAlias( TfType::GetRoot(), "vector<unsigned long>" );
1273     ulvec.AddAlias( TfType::GetRoot(), "vector<size_t>" );
1274 
1275     TfType::Define< vector<long long> >()
1276         .AddAlias( TfType::GetRoot(), "vector<long long>" );
1277     TfType::Define< vector<unsigned long long> >()
1278         .AddAlias( TfType::GetRoot(), "vector<unsigned long long>" );
1279 
1280     TfType::Define< vector<float> >()
1281         .AddAlias( TfType::GetRoot(), "vector<float>" );
1282     TfType::Define< vector<double> >()
1283         .AddAlias( TfType::GetRoot(), "vector<double>" );
1284     TfType::Define< vector<string> >()
1285         .AddAlias( TfType::GetRoot(), "vector<string>" );
1286 
1287     // Register TfType itself.
1288     TfType::Define<TfType>();
1289 }
1290 
1291 std::ostream &
operator <<(std::ostream & out,const TfType & t)1292 operator<<(std::ostream& out, const TfType& t)
1293 {
1294     return out << t.GetTypeName();
1295 }
1296 
1297 PXR_NAMESPACE_CLOSE_SCOPE
1298