/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. // Description : Part of CryEngine's extension framework. #ifndef CRYINCLUDE_CRYEXTENSION_IMPL_CLASSWEAVER_H #define CRYINCLUDE_CRYEXTENSION_IMPL_CLASSWEAVER_H #pragma once #include "TypeList.h" #include "Conversion.h" #include "RegFactoryNode.h" #include "../ICryUnknown.h" #include "../ICryFactory.h" #include namespace CW { namespace Internal { template struct InterfaceCast; template struct InterfaceCast { template static void* Op(T* p) { return (Dst*) p; } }; template <> struct InterfaceCast { template static void* Op(T* p) { return const_cast(static_cast(static_cast(p))); } }; } template struct InterfaceCast; template <> struct InterfaceCast { template static void* Op(T*, const CryInterfaceID&) { return 0; } }; template struct InterfaceCast > { template static void* Op(T* p, const CryInterfaceID& iid) { if (cryiidof() == iid) { return Internal::InterfaceCast::Op(p); } return InterfaceCast::Op(p, iid); } }; template struct FillIIDs; template <> struct FillIIDs { static void Op(CryInterfaceID*) { } }; template struct FillIIDs > { static void Op(CryInterfaceID* p) { *p++ = cryiidof(); FillIIDs::Op(p); } }; namespace Internal { template struct PickList; template struct PickList { typedef TL::BuildTypelist<>::Result Result; }; template struct PickList { typedef typename S::FullCompositeList Result; }; } template struct ProbeFullCompositeList { private: typedef char y[1]; typedef char n[2]; template static y& test(typename S::FullCompositeList*); template static n& test(...); public: enum { listFound = sizeof(test(0)) == sizeof(y) }; typedef typename Internal::PickList::Result ListType; }; namespace Internal { template struct CompositeQuery; template <> struct CompositeQuery { template static void* Op(const T&, const char*) { return 0; } }; template struct CompositeQuery > { template static void* Op(const T& ref, const char* name) { void* p = ref.Head::CompositeQueryImpl(name); return p ? p : CompositeQuery::Op(ref, name); } }; } struct CompositeQuery { template static void* Op(const T& ref, const char* name) { return Internal::CompositeQuery::ListType>::Op(ref, name); } }; inline bool NameMatch(const char* name, const char* compositeName) { if (!name || !compositeName) { return false; } size_t i = 0; for (; name[i] && name[i] == compositeName[i]; ++i) { } return name[i] == compositeName[i]; } template void* CheckCompositeMatch(const char* name, const AZStd::shared_ptr& composite, const char* compositeName) { typedef TC::SuperSubClass Rel; COMPILE_TIME_ASSERT(Rel::exists); return NameMatch(name, compositeName) ? const_cast(static_cast(&composite)) : 0; } } // namespace CW #define CRYINTERFACE_BEGIN() \ private: \ typedef TL::BuildTypelist < ICryUnknown #define CRYINTERFACE_ADD(iname) , iname #define CRYINTERFACE_END() > ::Result _UserDefinedPartialInterfaceList; \ protected: \ typedef TL::NoDuplicates<_UserDefinedPartialInterfaceList>::Result FullInterfaceList; #define _CRY_TPL_APPEND0(base) TL::Append::Result #define _CRY_TPL_APPEND(base, intermediate) TL::Append::Result #define CRYINTERFACE_ENDWITHBASE(base) > ::Result _UserDefinedPartialInterfaceList; \ protected: \ typedef TL::NoDuplicates<_CRY_TPL_APPEND0(base)>::Result FullInterfaceList; #define CRYINTERFACE_ENDWITHBASE2(base0, base1) > ::Result _UserDefinedPartialInterfaceList; \ protected: \ typedef TL::NoDuplicates<_CRY_TPL_APPEND(base0, _CRY_TPL_APPEND0(base1))>::Result FullInterfaceList; #define CRYINTERFACE_ENDWITHBASE3(base0, base1, base2) > ::Result _UserDefinedPartialInterfaceList; \ protected: \ typedef TL::NoDuplicates<_CRY_TPL_APPEND(base0, _CRY_TPL_APPEND(base1, _CRY_TPL_APPEND0(base2)))>::Result FullInterfaceList; #define CRYINTERFACE_SIMPLE(iname) \ CRYINTERFACE_BEGIN() \ CRYINTERFACE_ADD(iname) \ CRYINTERFACE_END() #define CRYCOMPOSITE_BEGIN() \ private: \ void* CompositeQueryImpl(const char* name) const \ { \ (void)(name); \ void* res = 0; (void)(res); \ #define CRYCOMPOSITE_ADD(member, membername) \ COMPILE_TIME_ASSERT((sizeof(membername) / sizeof(membername[0])) > 1); \ if ((res = CW::CheckCompositeMatch(name, member, membername)) != 0) { \ return res; } #define _CRYCOMPOSITE_END(implclassname) \ return 0; \ }; \ protected: \ typedef TL::BuildTypelist::Result _PartialCompositeList; \ \ template \ friend struct CW::Internal::PickList; #define CRYCOMPOSITE_END(implclassname) \ _CRYCOMPOSITE_END(implclassname) \ protected: \ typedef _PartialCompositeList FullCompositeList; #define _CRYCOMPOSITE_APPEND0(base) TL::Append<_PartialCompositeList, CW::ProbeFullCompositeList::ListType>::Result #define _CRYCOMPOSITE_APPEND(base, intermediate) TL::Append::ListType>::Result #define CRYCOMPOSITE_ENDWITHBASE(implclassname, base) \ _CRYCOMPOSITE_END(implclassname) \ protected: \ typedef _CRYCOMPOSITE_APPEND0 (base) FullCompositeList; #define CRYCOMPOSITE_ENDWITHBASE2(implclassname, base0, base1) \ _CRYCOMPOSITE_END(implclassname) \ protected: \ typedef TL::NoDuplicates<_CRYCOMPOSITE_APPEND(base1, _CRYCOMPOSITE_APPEND0(base0))>::Result FullCompositeList; #define CRYCOMPOSITE_ENDWITHBASE3(implclassname, base0, base1, base2) \ _CRYCOMPOSITE_END(implclassname) \ protected: \ typedef TL::NoDuplicates<_CRYCOMPOSITE_APPEND(base2, _CRYCOMPOSITE_APPEND(base1, _CRYCOMPOSITE_APPEND0(base0)))>::Result FullCompositeList; template class CFactory : public ICryFactory { public: virtual const char* GetName() const { return T::GetCName(); } virtual const CryClassID& GetClassID() const { return T::GetCID(); } virtual bool ClassSupports(const CryInterfaceID& iid) const { for (size_t i = 0; i < m_numIIDs; ++i) { if (iid == m_pIIDs[i]) { return true; } } return false; } virtual void ClassSupports(const CryInterfaceID*& pIIDs, size_t& numIIDs) const { pIIDs = m_pIIDs; numIIDs = m_numIIDs; } public: virtual ICryUnknownPtr CreateClassInstance() const { AZStd::shared_ptr p = AZStd::make_shared(); return cryinterface_cast (p); } CFactory() : m_numIIDs(0) , m_pIIDs(0) , m_regFactory() { static CryInterfaceID supportedIIDs[TL::Length < typename T::FullInterfaceList > ::value]; CW::FillIIDs::Op(supportedIIDs); m_pIIDs = &supportedIIDs[0]; m_numIIDs = TL::Length::value; new(&m_regFactory)SRegFactoryNode(this); } protected: CFactory(const CFactory&); CFactory& operator =(const CFactory&); size_t m_numIIDs; CryInterfaceID* m_pIIDs; SRegFactoryNode m_regFactory; }; template class CSingletonFactory : public CFactory { public: CSingletonFactory() : CFactory() , m_csCreateClassInstance() { } virtual ICryUnknownPtr CreateClassInstance() const { CryAutoLock lock(m_csCreateClassInstance); // override the allocator. These function static instances are being destroyed after the AZ alloctor has been deleted. // On win, TerminateProcess() prevents these destructors from being called, but that is not the case on OSX. static typename AZStd::aligned_storage,SingletonAllocator>), AZStd::alignment_of::value>::type m_storage; static ICryUnknownPtr p = AZStd::allocate_shared(SingletonAllocator(AZStd::addressof(m_storage))); return p; } mutable CryCriticalSection m_csCreateClassInstance; struct SingletonAllocator { SingletonAllocator(void* ptr) : m_data(ptr) {} void* allocate(size_t /*byteSize*/, size_t /*alignment*/, int /*flags*/ = 0) { return m_data; } void deallocate(void* /*ptr*/, size_t /*byteSize*/, size_t /*alignment*/) { // nothing to see here } void* m_data; }; }; #define _CRYFACTORY_DECLARE(implclassname) \ private: \ friend class CFactory; \ static CFactory s_factory; #define _CRYFACTORY_DECLARE_SINGLETON(implclassname) \ private: \ friend class CFactory; \ static CSingletonFactory s_factory; #define _IMPLEMENT_ICRYUNKNOWN() \ public: \ virtual ICryFactory* GetFactory() const \ { \ return &s_factory; \ } \ \ protected: \ virtual void* QueryInterface(const CryInterfaceID&iid) const \ { \ return CW::InterfaceCast::Op(this, iid); \ } \ \ template \ friend struct CW::Internal::CompositeQuery; \ \ virtual void* QueryComposite(const char* name) const \ { \ return CW::CompositeQuery::Op(*this, name); \ } #define _ENFORCE_CRYFACTORY_USAGE(implclassname, cname, cidHigh, cidLow) \ public: \ static const char* GetCName() \ { \ return cname; \ } \ static const CryClassID& GetCID() \ { \ static const CryClassID cid = {(uint64) cidHigh##LL, (uint64) cidLow##LL}; \ return cid; \ } \ static AZStd::shared_ptr CreateClassInstance() \ { \ ICryUnknownPtr p = s_factory.CreateClassInstance(); \ return AZStd::shared_ptr(*static_cast*>(static_cast(&p))); \ } \ \ protected: \ implclassname(); \ virtual ~implclassname(); #define _BEFRIEND_OPS() \ _BEFRIEND_CRYINTERFACE_CAST() \ _BEFRIEND_CRYCOMPOSITE_QUERY() \ _BEFRIEND_MAKE_SHARED() #define CRYGENERATE_CLASS(implclassname, cname, cidHigh, cidLow) \ _CRYFACTORY_DECLARE(implclassname) \ _BEFRIEND_OPS() \ _IMPLEMENT_ICRYUNKNOWN() \ _ENFORCE_CRYFACTORY_USAGE(implclassname, cname, cidHigh, cidLow) #define CRYGENERATE_SINGLETONCLASS(implclassname, cname, cidHigh, cidLow) \ _CRYFACTORY_DECLARE_SINGLETON(implclassname) \ _BEFRIEND_OPS() \ _IMPLEMENT_ICRYUNKNOWN() \ _ENFORCE_CRYFACTORY_USAGE(implclassname, cname, cidHigh, cidLow) #define CRYREGISTER_CLASS(implclassname) \ CFactory implclassname::s_factory; #define CRYREGISTER_SINGLETON_CLASS(implclassname) \ CSingletonFactory implclassname::s_factory; #endif // CRYINCLUDE_CRYEXTENSION_IMPL_CLASSWEAVER_H