// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "uLang/Common/Common.h" // for int32_t #include "uLang/Common/Containers/SharedPointer.h" #include "uLang/Common/Misc/Optional.h" #include "uLang/Toolchain/ModularFeature.h" #include "uLang/Common/Text/Symbol.h" #include "uLang/Common/Containers/SharedPointerSet.h" namespace uLang { /* TModularFeatureRegHandle<> -- Definitions ******************************************************************************/ namespace Private { using RegistryId = SymbolId; class IModularFeatureRegistry : public CSharedMix { private: friend class CModularFeatureRegistry; IModularFeatureRegistry() {} }; /** Private base class for sharing registration functionality only with our templatized RAII handles. */ class CModularFeatureRegistrar { public: // intended to be private, to limit access, but clang apparently doesn't follow templatized friend decls template friend class TModularFeatureRegHandle; VERSECOMPILER_API static const TSRef& GetRegistry(); VERSECOMPILER_API static void SetRegistry(const TSRef& NewRegistry); VERSECOMPILER_API static void Register(const TSRef& NewFeature, const RegistryId FeatureId); VERSECOMPILER_API static bool Unregister(const TSRef& Feature); VERSECOMPILER_API static RegistryId GetRegistryId(const char* FeatureName); }; /** * SFINAE utility helpers for catching mis-implemented ModularFeature classes. */ template struct VoidType { using Type = void; }; template struct TFeatureHasUid { enum { Value = false }; }; template struct TFeatureHasUid::Type> { using CFeatureType = typename FeatureType::CFeatureType; enum { Value = true }; }; template RegistryId GetUidForFeature() { static_assert(Private::TFeatureHasUid::Value, "Your ModularFeature class is missing its UID -- You must add ULANG_FEATURE_ID_DECL() to the class body."); return CModularFeatureRegistrar::GetRegistryId(FeatureType::FeatureName); } } template template ULANG_FORCEINLINE TModularFeatureRegHandle::TModularFeatureRegHandle(Args_t&&... Args) : _ModularFeatureRef(TSRef::New(uLang::ForwardArg(Args)...)) { Private::CModularFeatureRegistrar::Register(_ModularFeatureRef, Private::GetUidForFeature()); } template ULANG_FORCEINLINE uLang::TModularFeatureRegHandle::~TModularFeatureRegHandle() { Private::CModularFeatureRegistrar::Unregister(_ModularFeatureRef); } /* ModularFeatureManager API -- Definitions ******************************************************************************/ namespace Private { VERSECOMPILER_API int32_t GetModularFeatureCount(const RegistryId FeatureId); VERSECOMPILER_API TSPtr GetModularFeature(const RegistryId FeatureId, const int32_t Index); template RegistryId GetUidForFeatureQuery() { RegistryId RegId = GetUidForFeature(); static_assert(std::is_same_v, "You cannot use sub-classes when querying for specific ModularFeatures. You must use the base feature class."); return RegId; } } template ULANG_FORCEINLINE int32_t GetModularFeatureCount() { return Private::GetModularFeatureCount(Private::GetUidForFeatureQuery()); } template TOptional< TSRef > GetModularFeature(const int32_t Index) { TOptional< TSRef > Result; TSPtr RegisteredFeature = Private::GetModularFeature(Private::GetUidForFeatureQuery(), Index); if (RegisteredFeature.IsValid()) { // Noteworthy downcast (normally ill advised) -- required since we're storing base IModularFeature pointers // Okay, because we're indexing using a class unique identifier, and we strictly control allocation & registration Result = RegisteredFeature.As().AsRef(); } return Result; } template TSRefArray GetModularFeaturesOfType() { TSRefArray OutArray; for (TModularFeatureIterator FeatureIt; FeatureIt; ++FeatureIt) { OutArray.Add(FeatureIt.Get()); } return OutArray; } /* TModularFeatureIterator - Definitions ******************************************************************************/ template ULANG_FORCEINLINE TModularFeatureIterator::operator bool() const { return GetModularFeature(_Index).IsSet(); } template ULANG_FORCEINLINE bool TModularFeatureIterator::operator!() const { return !(bool)*this; } template ULANG_FORCEINLINE TSRef TModularFeatureIterator::Get() const { TOptional< TSRef > Optional = GetModularFeature(_Index); ULANG_ASSERTF(Optional.IsSet(), "Dereferencing an invalid feature iterator -- check validity first."); return Optional.GetValue(); } template ULANG_FORCEINLINE FeatureType& TModularFeatureIterator::operator*() const { return *Get(); } template ULANG_FORCEINLINE FeatureType* TModularFeatureIterator::operator->() const { return this->Get().Get(); } template ULANG_FORCEINLINE void TModularFeatureIterator::operator++() { ++_Index; } } // namespace uLang