Files
UnrealEngineUWP/Engine/Source/Developer/DerivedDataCache/Private/DerivedDataBuildDefinition.cpp
Devin Doucette 0baafa125a DDC: Added the start of the new build interface UE::DerivedData::IBuild
This only includes the functionality required to create a build definition, and does not include the functionalty required to execute a build from the build definition.

#rb Zousar.Shaker
#rnx
#preflight 608cf5ef7343ea00016e58f4

[CL 16183533 by Devin Doucette in ue5-main branch]
2021-05-03 09:25:48 -04:00

327 lines
9.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "DerivedDataBuildDefinition.h"
#include "Algo/AllOf.h"
#include "Containers/Map.h"
#include "Containers/StringConv.h"
#include "Containers/StringView.h"
#include "Containers/UnrealString.h"
#include "DerivedDataBuildKey.h"
#include "DerivedDataBuildPrivate.h"
#include "Misc/Guid.h"
#include "Misc/TVariant.h"
#include "Serialization/CompactBinary.h"
#include "Serialization/CompactBinaryWriter.h"
#include "Templates/Function.h"
#include <atomic>
namespace UE::DerivedData::Private
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class FBuildDefinitionBuilderInternal final : public IBuildDefinitionBuilderInternal
{
public:
inline FBuildDefinitionBuilderInternal(FStringView InName, FStringView InFunction)
: Name(InName)
, Function(InFunction)
{
checkf(!Name.IsEmpty(), TEXT("A build definition requires a non-empty name."));
checkf(!Function.IsEmpty(), TEXT("A build definition requires a non-empty function name."));
checkf(Algo::AllOf(Function, FChar::IsAlnum), TEXT("A build definition requires an alphanumeric function name. ")
TEXT("Definition: %s; Function: %s"), *Name, *Function);
}
~FBuildDefinitionBuilderInternal() final = default;
void AddConstant(FStringView Key, const FCbObject& Value) final
{
Add<FCbObject>(Key, Value);
}
void AddInputBuild(FStringView Key, const FBuildPayloadKey& PayloadKey) final
{
Add<FBuildPayloadKey>(Key, PayloadKey);
}
void AddInputBulkData(FStringView Key, const FGuid& BulkDataId) final
{
Add<FGuid>(Key, BulkDataId);
}
void AddInputFile(FStringView Key, FStringView Path) final
{
Add<FString>(Key, Path);
}
void AddInputHash(FStringView Key, const FIoHash& RawHash) final
{
Add<FIoHash>(Key, RawHash);
}
IBuildDefinitionInternal* Build() final;
using InputType = TVariant<FCbObject, FBuildPayloadKey, FGuid, FString, FIoHash>;
FString Name;
FString Function;
TMap<FString, InputType> Inputs;
private:
template <typename ValueType, typename ArgType>
inline void Add(FStringView Key, ArgType&& Value)
{
const uint32 KeyHash = GetTypeHash(Key);
checkf(!Key.IsEmpty(), TEXT("Empty key used in the %s build input for %s."), *Function, *Name);
checkf(!Inputs.ContainsByHash(KeyHash, Key), TEXT("Duplicate key %.*s used in the %s build input for %s."),
Key.Len(), Key.GetData(), *Function, *Name);
Inputs.EmplaceByHash(KeyHash, Key, InputType(TInPlaceType<ValueType>(), Forward<ArgType>(Value)));
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class FBuildDefinitionInternal final : public IBuildDefinitionInternal
{
public:
explicit FBuildDefinitionInternal(FBuildDefinitionBuilderInternal&& DefinitionBuilder);
explicit FBuildDefinitionInternal(FStringView Name, FCbObject&& Definition);
~FBuildDefinitionInternal() final = default;
const FBuildKey& GetKey() const final { return Key; }
FStringView GetName() const final { return Name; }
FStringView GetFunction() const final { return Function; }
void IterateConstants(TFunctionRef<void (FStringView Key, FCbObject&& Value)> Visitor) const final;
void IterateInputBuilds(TFunctionRef<void (FStringView Key, const FBuildPayloadKey& PayloadKey)> Visitor) const final;
void IterateInputBulkData(TFunctionRef<void (FStringView Key, const FGuid& BulkDataId)> Visitor) const final;
void IterateInputFiles(TFunctionRef<void (FStringView Key, FStringView Path)> Visitor) const final;
void IterateInputHashes(TFunctionRef<void (FStringView Key, const FIoHash& RawHash)> Visitor) const final;
void Save(FCbWriter& Writer) const final;
inline void AddRef() const final
{
ReferenceCount.fetch_add(1, std::memory_order_relaxed);
}
inline void Release() const final
{
if (ReferenceCount.fetch_sub(1, std::memory_order_acq_rel) == 1)
{
delete this;
}
}
private:
mutable std::atomic<uint32> ReferenceCount{0};
FString Name;
FString Function;
FCbObject Definition;
FBuildKey Key;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FBuildDefinitionInternal::FBuildDefinitionInternal(FBuildDefinitionBuilderInternal&& DefinitionBuilder)
: Name(MoveTemp(DefinitionBuilder.Name))
, Function(MoveTemp(DefinitionBuilder.Function))
{
DefinitionBuilder.Inputs.KeySort(TLess<>());
bool bHasConstants = false;
bool bHasBuilds = false;
bool bHasBulkData = false;
bool bHasFiles = false;
bool bHasHashes = false;
for (const TPair<FString, FBuildDefinitionBuilderInternal::InputType>& Pair : DefinitionBuilder.Inputs)
{
if (Pair.Value.IsType<FCbObject>())
{
bHasConstants = true;
}
else if (Pair.Value.IsType<FBuildPayloadKey>())
{
bHasBuilds = true;
}
else if (Pair.Value.IsType<FGuid>())
{
bHasBulkData = true;
}
else if (Pair.Value.IsType<FString>())
{
bHasFiles = true;
}
else if (Pair.Value.IsType<FIoHash>())
{
bHasHashes = true;
}
}
TCbWriter<2048> Writer;
Writer.BeginObject();
Writer.AddString("Function"_ASV, Function);
if (bHasConstants)
{
Writer.BeginObject("Constants"_ASV);
for (const TPair<FString, FBuildDefinitionBuilderInternal::InputType>& Pair : DefinitionBuilder.Inputs)
{
if (Pair.Value.IsType<FCbObject>())
{
Writer.AddObject(FTCHARToUTF8(Pair.Key), Pair.Value.Get<FCbObject>());
}
}
Writer.EndObject();
}
if (bHasBuilds)
{
Writer.BeginObject("Builds"_ASV);
for (const TPair<FString, FBuildDefinitionBuilderInternal::InputType>& Pair : DefinitionBuilder.Inputs)
{
if (Pair.Value.IsType<FBuildPayloadKey>())
{
const FBuildPayloadKey& PayloadKey = Pair.Value.Get<FBuildPayloadKey>();
Writer.BeginObject(FTCHARToUTF8(Pair.Key));
Writer.AddHash("Build"_ASV, PayloadKey.BuildKey.Hash);
Writer.AddObjectId("Payload"_ASV, FCbObjectId(PayloadKey.Id.GetView()));
Writer.EndObject();
}
}
Writer.EndObject();
}
if (bHasBulkData)
{
Writer.BeginObject("BulkData"_ASV);
for (const TPair<FString, FBuildDefinitionBuilderInternal::InputType>& Pair : DefinitionBuilder.Inputs)
{
if (Pair.Value.IsType<FGuid>())
{
Writer.AddUuid(FTCHARToUTF8(Pair.Key), Pair.Value.Get<FGuid>());
}
}
Writer.EndObject();
}
if (bHasFiles)
{
Writer.BeginObject("Files"_ASV);
for (const TPair<FString, FBuildDefinitionBuilderInternal::InputType>& Pair : DefinitionBuilder.Inputs)
{
if (Pair.Value.IsType<FString>())
{
Writer.AddString(FTCHARToUTF8(Pair.Key), Pair.Value.Get<FString>());
}
}
Writer.EndObject();
}
if (bHasHashes)
{
Writer.BeginObject("Hashes"_ASV);
for (const TPair<FString, FBuildDefinitionBuilderInternal::InputType>& Pair : DefinitionBuilder.Inputs)
{
if (Pair.Value.IsType<FIoHash>())
{
Writer.AddBinaryAttachment(FTCHARToUTF8(Pair.Key), Pair.Value.Get<FIoHash>());
}
}
Writer.EndObject();
}
Writer.EndObject();
Definition = Writer.Save().AsObject();
Key = FBuildKey{Definition.GetHash()};
}
FBuildDefinitionInternal::FBuildDefinitionInternal(FStringView InName, FCbObject&& InDefinition)
: Name(InName)
, Function(InDefinition.FindView("Function"_ASV).AsString())
, Definition(MoveTemp(InDefinition))
{
checkf(!InName.IsEmpty(), TEXT("A build definition requires a non-empty name."));
Definition.MakeOwned();
if (const bool bIsValid = Definition && Algo::AllOf(Function, FChar::IsAlnum))
{
Key = FBuildKey{Definition.GetHash()};
}
}
void FBuildDefinitionInternal::IterateConstants(TFunctionRef<void (FStringView Key, FCbObject&& Value)> Visitor) const
{
for (FCbField Field : Definition["Constants"_ASV])
{
Visitor(FUTF8ToTCHAR(Field.GetName()), Field.AsObject());
}
}
void FBuildDefinitionInternal::IterateInputBuilds(TFunctionRef<void (FStringView Key, const FBuildPayloadKey& PayloadKey)> Visitor) const
{
for (FCbFieldView Field : Definition.FindView("Builds"_ASV))
{
FCbObjectView Build = Field.AsObjectView();
const FBuildKey BuildKey{Build["Build"_ASV].AsHash()};
const FPayloadId Id = FPayloadId(Build["Payload"_ASV].AsObjectId().GetView());
Visitor(FUTF8ToTCHAR(Field.GetName()), FBuildPayloadKey{BuildKey, Id});
}
}
void FBuildDefinitionInternal::IterateInputBulkData(TFunctionRef<void (FStringView Key, const FGuid& BulkDataId)> Visitor) const
{
for (FCbFieldView Field : Definition.FindView("BulkData"_ASV))
{
Visitor(FUTF8ToTCHAR(Field.GetName()), Field.AsUuid());
}
}
void FBuildDefinitionInternal::IterateInputFiles(TFunctionRef<void (FStringView Key, FStringView Path)> Visitor) const
{
for (FCbFieldView Field : Definition.FindView("Files"_ASV))
{
Visitor(FUTF8ToTCHAR(Field.GetName()), FUTF8ToTCHAR(Field.AsString()));
}
}
void FBuildDefinitionInternal::IterateInputHashes(TFunctionRef<void (FStringView Key, const FIoHash& RawHash)> Visitor) const
{
for (FCbFieldView Field : Definition.FindView("Hashes"_ASV))
{
Visitor(FUTF8ToTCHAR(Field.GetName()), Field.AsBinaryAttachment());
}
}
void FBuildDefinitionInternal::Save(FCbWriter& Writer) const
{
Writer.AddObject(Definition);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
IBuildDefinitionInternal* FBuildDefinitionBuilderInternal::Build()
{
return new FBuildDefinitionInternal(MoveTemp(*this));
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FBuildDefinitionBuilder CreateBuildDefinition(FStringView Name, FStringView Function)
{
return CreateBuildDefinitionBuilder(new FBuildDefinitionBuilderInternal(Name, Function));
}
FBuildDefinition LoadBuildDefinition(FStringView Name, FCbObject&& Definition)
{
return CreateBuildDefinition(new FBuildDefinitionInternal(Name, MoveTemp(Definition)));
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
} // UE::DerivedData::Private