Files
UnrealEngine/Engine/Source/Developer/DerivedDataCache/Private/DerivedDataBuildFunctionRegistry.cpp
2025-05-18 13:04:45 +08:00

156 lines
5.3 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "DerivedDataBuildFunctionRegistry.h"
#include "Containers/Map.h"
#include "Containers/SharedString.h"
#include "DerivedDataBuildFunction.h"
#include "DerivedDataBuildFunctionFactory.h"
#include "DerivedDataBuildPrivate.h"
#include "Features/IModularFeatures.h"
#include "HAL/CriticalSection.h"
#include "Misc/AsciiSet.h"
#include "Misc/Guid.h"
#include "Misc/ScopeRWLock.h"
#include "Misc/StringBuilder.h"
namespace UE::DerivedData::Private
{
class FBuildFunctionRegistry : public IBuildFunctionRegistry
{
public:
FBuildFunctionRegistry();
~FBuildFunctionRegistry();
const IBuildFunction* FindFunction(FUtf8StringView Function) const;
FGuid FindFunctionVersion(FUtf8StringView Function) const;
void IterateFunctionVersions(TFunctionRef<void(FUtf8StringView Function, const FGuid& Version)> Visitor) const;
private:
void OnModularFeatureRegistered(const FName& Type, IModularFeature* ModularFeature);
void OnModularFeatureUnregistered(const FName& Type, IModularFeature* ModularFeature);
void AddFunctionNoLock(IBuildFunctionFactory* Factory);
void RemoveFunction(IBuildFunctionFactory* Factory);
private:
mutable FRWLock Lock;
TMap<FUtf8SharedString, IBuildFunctionFactory*> Functions;
};
FBuildFunctionRegistry::FBuildFunctionRegistry()
{
IModularFeatures& ModularFeatures = IModularFeatures::Get();
for (IBuildFunctionFactory* Factory : ModularFeatures.GetModularFeatureImplementations<IBuildFunctionFactory>(IBuildFunctionFactory::FeatureName))
{
AddFunctionNoLock(Factory);
}
ModularFeatures.OnModularFeatureRegistered().AddRaw(this, &FBuildFunctionRegistry::OnModularFeatureRegistered);
ModularFeatures.OnModularFeatureUnregistered().AddRaw(this, &FBuildFunctionRegistry::OnModularFeatureUnregistered);
}
FBuildFunctionRegistry::~FBuildFunctionRegistry()
{
IModularFeatures& ModularFeatures = IModularFeatures::Get();
ModularFeatures.OnModularFeatureUnregistered().RemoveAll(this);
ModularFeatures.OnModularFeatureRegistered().RemoveAll(this);
}
void FBuildFunctionRegistry::OnModularFeatureRegistered(const FName& Type, IModularFeature* ModularFeature)
{
if (Type == IBuildFunctionFactory::FeatureName)
{
FWriteScopeLock WriteLock(Lock);
AddFunctionNoLock(static_cast<IBuildFunctionFactory*>(ModularFeature));
}
}
void FBuildFunctionRegistry::OnModularFeatureUnregistered(const FName& Type, IModularFeature* ModularFeature)
{
if (Type == IBuildFunctionFactory::FeatureName)
{
RemoveFunction(static_cast<IBuildFunctionFactory*>(ModularFeature));
}
}
void FBuildFunctionRegistry::AddFunctionNoLock(IBuildFunctionFactory* Factory)
{
const IBuildFunction& Function = Factory->GetFunction();
const FUtf8SharedString& FunctionName = Function.GetName();
const uint32 FunctionHash = GetTypeHash(FunctionName);
UE_CLOG(!Function.GetVersion().IsValid(), LogDerivedDataBuild, Error,
TEXT("Version of zero is not allowed in build function with the name %s."), *WriteToString<32>(FunctionName));
UE_CLOG(Functions.FindByHash(FunctionHash, FunctionName), LogDerivedDataBuild, Error,
TEXT("More than one build function has been registered with the name %s."), *WriteToString<32>(FunctionName));
Functions.EmplaceByHash(FunctionHash, FunctionName, Factory);
}
void FBuildFunctionRegistry::RemoveFunction(IBuildFunctionFactory* Factory)
{
const FUtf8SharedString& Function = Factory->GetFunction().GetName();
const uint32 FunctionHash = GetTypeHash(Function);
FWriteScopeLock WriteLock(Lock);
Functions.RemoveByHash(FunctionHash, Function);
}
const IBuildFunction* FBuildFunctionRegistry::FindFunction(FUtf8StringView Function) const
{
const uint32 FunctionHash = GetTypeHash(Function);
FReadScopeLock ReadLock(Lock);
if (IBuildFunctionFactory* const* Factory = Functions.FindByHash(FunctionHash, Function))
{
return &(**Factory).GetFunction();
}
return nullptr;
}
FGuid FBuildFunctionRegistry::FindFunctionVersion(FUtf8StringView Function) const
{
const uint32 FunctionHash = GetTypeHash(Function);
FReadScopeLock ReadLock(Lock);
if (IBuildFunctionFactory* const* Factory = Functions.FindByHash(FunctionHash, Function))
{
return (**Factory).GetFunction().GetVersion();
}
return FGuid();
}
void FBuildFunctionRegistry::IterateFunctionVersions(TFunctionRef<void(FUtf8StringView Function, const FGuid& Version)> Visitor) const
{
TArray<TPair<FUtf8SharedString, FGuid>> FunctionVersions;
{
FReadScopeLock ReadLock(Lock);
FunctionVersions.Reserve(Functions.Num());
for (const TPair<FUtf8SharedString, IBuildFunctionFactory*>& Function : Functions)
{
FunctionVersions.Emplace(Function.Key, Function.Value->GetFunction().GetVersion());
}
}
for (const TPair<FUtf8SharedString, FGuid>& Function : FunctionVersions)
{
Visitor(Function.Key, Function.Value);
}
}
IBuildFunctionRegistry* CreateBuildFunctionRegistry()
{
return new FBuildFunctionRegistry();
}
bool IsValidBuildFunctionName(FUtf8StringView Function)
{
constexpr FAsciiSet Valid("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
return !Function.IsEmpty() && FAsciiSet::HasOnly(Function, Valid);
}
void AssertValidBuildFunctionName(FUtf8StringView Function, FStringView Name)
{
checkf(IsValidBuildFunctionName(Function),
TEXT("A build function name must be alphanumeric and non-empty for build of '%.*s' by '%s'."),
Name.Len(), Name.GetData(), *WriteToString<32>(Function));
}
} // UE::DerivedData::Private