// // Copyright 2016 Pixar // // Licensed under the Apache License, Version 2.0 (the "Apache License") // with the following modification; you may not use this file except in // compliance with the Apache License and the following modification to it: // Section 6. Trademarks. is deleted and replaced with: // // 6. Trademarks. This License does not grant permission to use the trade // names, trademarks, service marks, or product names of the Licensor // and its affiliates, except as required to comply with Section 4(c) of // the License and to reproduce the content of the NOTICE file. // // You may obtain a copy of the Apache License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the Apache License with the above modification is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // #ifndef PXR_USD_SDF_DECLARE_HANDLES_H #define PXR_USD_SDF_DECLARE_HANDLES_H /// \file sdf/declareHandles.h #include "pxr/pxr.h" #include "pxr/usd/sdf/api.h" #include "pxr/base/arch/demangle.h" #include "pxr/base/arch/hints.h" #include "pxr/base/tf/diagnostic.h" #include "pxr/base/tf/weakPtrFacade.h" #include "pxr/base/tf/declarePtrs.h" #include #include #include #include #include #include PXR_NAMESPACE_OPEN_SCOPE class SdfLayer; class SdfSpec; template class TfRefPtr; class Sdf_Identity; // Sdf_Identities are held via intrusive_ptr so that we can carefully // manage the ref-count to avoid race conditions -- see // Sdf_IdentityRegistry::Identify(). typedef boost::intrusive_ptr Sdf_IdentityRefPtr; /// \class SdfHandle /// /// SdfHandle is a smart ptr that calls IsDormant() on the pointed-to /// object as an extra expiration check so that dormant objects appear to /// be expired. /// template class SdfHandle : private boost::totally_ordered > { public: typedef SdfHandle This; typedef T SpecType; typedef typename std::remove_const::type NonConstSpecType; typedef SdfHandle NonConstThis; SdfHandle() { } SdfHandle(TfNullPtrType) { } explicit SdfHandle(const Sdf_IdentityRefPtr& id) : _spec(id) { } SdfHandle(const SpecType& spec) : _spec(spec) { } template SdfHandle(const SdfHandle& x) : _spec(x._spec) { } This& operator=(const This& x) { const_cast(_spec) = x._spec; return *this; } template This& operator=(const SdfHandle& x) { const_cast(_spec) = x._spec; return *this; } /// Dereference. Raises a fatal error if the object is invalid or /// dormant. SpecType* operator->() const { if (ARCH_UNLIKELY(_spec.IsDormant())) { TF_FATAL_ERROR("Dereferenced an invalid %s", ArchGetDemangled(typeid(SpecType)).c_str()); return 0; } return const_cast(&_spec); } const SpecType & GetSpec() const { return _spec; } void Reset() { const_cast(_spec) = SpecType(); } #if !defined(doxygen) typedef SpecType This::*UnspecifiedBoolType; #endif /// Returns \c true in a boolean context if the object is valid, /// \c false otherwise. operator UnspecifiedBoolType() const { return _spec.IsDormant() ? 0 : &This::_spec; } /// Returns \c false in a boolean context if the object is valid, /// \c true otherwise. bool operator!() const { return _spec.IsDormant(); } /// Compares handles for equality. template bool operator==(const SdfHandle& other) const { return _spec == other._spec; } /// Arranges handles in an arbitrary strict weak ordering. Note that /// this ordering is stable across path changes. template bool operator<(const SdfHandle& other) const { return _spec < other._spec; } /// Hash. friend size_t hash_value(const This &x) { return hash_value(x._spec); } private: friend inline SpecType *get_pointer(const SdfHandle &x) { return ARCH_UNLIKELY(x._spec.IsDormant()) ? nullptr : const_cast(&x._spec); } SpecType _spec; template friend class SdfHandle; }; PXR_NAMESPACE_CLOSE_SCOPE namespace boost { using PXR_NS::get_pointer; } PXR_NAMESPACE_OPEN_SCOPE template struct SdfHandleTo { typedef SdfHandle Handle; typedef SdfHandle ConstHandle; typedef std::vector Vector; typedef std::vector ConstVector; }; template <> struct SdfHandleTo { typedef TfWeakPtr Handle; typedef TfWeakPtr ConstHandle; typedef std::vector Vector; typedef std::vector ConstVector; }; template typename SdfHandleTo::Handle SdfCreateHandle(T *p) { return typename SdfHandleTo::Handle(p ? *p : T()); } template <> SDF_API SdfHandleTo::Handle SdfCreateHandle(SdfLayer *p); template typename SdfHandleTo::Handle SdfCreateNonConstHandle(T const *p) { return SdfCreateHandle(const_cast(p)); } struct Sdf_CastAccess { template static DST CastSpec(const SRC& spec) { return DST(spec); } }; SDF_API bool Sdf_CanCastToType( const SdfSpec& srcSpec, const std::type_info& destType); SDF_API bool Sdf_CanCastToTypeCheckSchema( const SdfSpec& srcSpec, const std::type_info& destType); template struct Sdf_SpecTypesAreDirectlyRelated : std::integral_constant::value || std::is_base_of::value> { }; /// Convert SdfHandle \p x to an SdfHandle. This function /// behaves similar to a dynamic_cast. If class DST cannot represent /// the spec pointed to be \p x, or if the classes DST and SRC are /// not directly related to each other in the C++ type hierarchy, /// the conversion fails and an invalid handle is returned. /// /// XXX: The second condition in the above statement is currently untrue. /// This function will allow casting between spec classes even if /// they are not directly related. Doing so could lead to schema /// mismatches and other buggy behavior. template inline SdfHandle TfDynamic_cast(const SdfHandle& x) { typedef typename DST::SpecType Spec; typedef SdfHandle Handle; if (Sdf_CanCastToType(x.GetSpec(), typeid(Spec))) { return Handle(Sdf_CastAccess::CastSpec(x.GetSpec())); } return Handle(); } template inline SdfHandle TfSafeDynamic_cast(const SdfHandle& x) { return TfDynamic_cast(x); } /// Convert SdfHandle \p x to an SdfHandle. This function /// behaves similar to a static_cast. No runtime checks are performed /// to ensure the conversion is valid; it is up to the consumer to /// ensure this. template inline SdfHandle TfStatic_cast(const SdfHandle& x) { typedef typename DST::SpecType Spec; typedef SdfHandle Handle; static_assert(Sdf_SpecTypesAreDirectlyRelated::value, "Spec and SRC must be directly related."); return Handle(Sdf_CastAccess::CastSpec(x.GetSpec())); } template inline SdfHandle TfConst_cast(const SdfHandle& x) { return TfStatic_cast(x); } /// Convert SdfHandle \p x to an SdfHandle. This function is /// similar to TfDynamic_cast, but it allows the SRC and DST spec to be /// indirectly related, so long as the schema associated with the DST /// spec type is a subclass of the schema associated with \p x. template inline SdfHandle SdfSpecDynamic_cast(const SdfHandle& x) { typedef typename DST::SpecType Spec; typedef SdfHandle Handle; if (Sdf_CanCastToTypeCheckSchema(x.GetSpec(), typeid(Spec))) { return Handle(Sdf_CastAccess::CastSpec(x.GetSpec())); } return Handle(); } /// Convert SdfHandle \p x to an SdfHandle. This function is /// similar to TfStatic_cast, but it allows the SRC and DST spec to be /// indirectly related. template inline SdfHandle SdfSpecStatic_cast(const SdfHandle& x) { typedef typename DST::SpecType Spec; typedef SdfHandle Handle; return Handle(Sdf_CastAccess::CastSpec(x.GetSpec())); } /// Convert SRC_SPEC to a DST_SPEC. template inline DST_SPEC SdfSpecStatic_cast(const SRC_SPEC& x) { return Sdf_CastAccess::CastSpec(x); } typedef TfRefPtr SdfLayerRefPtr; typedef std::vector > SdfLayerRefPtrVector; typedef std::set::Handle> SdfLayerHandleSet; #define SDF_DECLARE_HANDLES(cls) \ typedef SdfHandleTo::Handle cls##Handle; \ typedef SdfHandleTo::ConstHandle cls##ConstHandle; \ typedef SdfHandleTo::Vector cls##HandleVector; \ typedef SdfHandleTo::ConstVector cls##ConstHandleVector PXR_NAMESPACE_CLOSE_SCOPE #endif // PXR_USD_SDF_DECLARE_HANDLES_H