You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
The structure with a value and attachments is an artifact of an early design where the record *was* a compact binary package. That design changed months ago and it now simplifies the cache record significantly to make it a collection of values without specific "value" and "attachment" types. #rb Zousar.Shaker #rnx #preflight 61d8b94ed17842e547def37a #ROBOMERGE-AUTHOR: devin.doucette #ROBOMERGE-SOURCE: CL 18553971 in //UE5/Release-5.0/... via CL 18553976 #ROBOMERGE-BOT: STARSHIP (Release-Engine-Staging -> Release-Engine-Test) (v899-18417669) [CL 18553977 by devin doucette in ue5-release-engine-test branch]
379 lines
11 KiB
C++
379 lines
11 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 <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."));
|
|
AssertValidBuildFunctionName(Function, Name);
|
|
}
|
|
|
|
~FBuildDefinitionBuilderInternal() final = default;
|
|
|
|
void AddConstant(FStringView Key, const FCbObject& Value) final
|
|
{
|
|
Add<FCbObject>(Key, Value);
|
|
}
|
|
|
|
void AddInputBuild(FStringView Key, const FBuildValueKey& ValueKey) final
|
|
{
|
|
Add<FBuildValueKey>(Key, ValueKey);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
FBuildDefinition Build() final;
|
|
|
|
using InputType = TVariant<FCbObject, FBuildValueKey, 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 definition for build of '%s' by %s."), *Name, *Function);
|
|
checkf(!Inputs.ContainsByHash(KeyHash, Key), TEXT("Duplicate key '%.*s' used in definition ")
|
|
TEXT("for build of '%s' by %s."), Key.Len(), Key.GetData(), *Name, *Function);
|
|
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, bool& bOutIsValid);
|
|
|
|
~FBuildDefinitionInternal() final = default;
|
|
|
|
const FBuildKey& GetKey() const final { return Key; }
|
|
|
|
FStringView GetName() const final { return Name; }
|
|
FStringView GetFunction() const final { return Function; }
|
|
|
|
bool HasConstants() const final;
|
|
bool HasInputs() const final;
|
|
|
|
void IterateConstants(TFunctionRef<void (FStringView Key, FCbObject&& Value)> Visitor) const final;
|
|
void IterateInputBuilds(TFunctionRef<void (FStringView Key, const FBuildValueKey& ValueKey)> 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:
|
|
FString Name;
|
|
FString Function;
|
|
FCbObject Definition;
|
|
FBuildKey Key;
|
|
mutable std::atomic<uint32> ReferenceCount{0};
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
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<FBuildValueKey>())
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
const bool bHasInputs = bHasBuilds | bHasBulkData | bHasFiles | bHasHashes;
|
|
|
|
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 (bHasInputs)
|
|
{
|
|
Writer.BeginObject("Inputs"_ASV);
|
|
}
|
|
|
|
if (bHasBuilds)
|
|
{
|
|
Writer.BeginObject("Builds"_ASV);
|
|
for (const TPair<FString, FBuildDefinitionBuilderInternal::InputType>& Pair : DefinitionBuilder.Inputs)
|
|
{
|
|
if (Pair.Value.IsType<FBuildValueKey>())
|
|
{
|
|
const FBuildValueKey& ValueKey = Pair.Value.Get<FBuildValueKey>();
|
|
Writer.BeginObject(FTCHARToUTF8(Pair.Key));
|
|
Writer.AddHash("Build"_ASV, ValueKey.BuildKey.Hash);
|
|
Writer.AddObjectId("Id"_ASV, ValueKey.Id);
|
|
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();
|
|
}
|
|
|
|
if (bHasInputs)
|
|
{
|
|
Writer.EndObject();
|
|
}
|
|
|
|
Writer.EndObject();
|
|
Definition = Writer.Save().AsObject();
|
|
Key.Hash = Definition.GetHash();
|
|
}
|
|
|
|
FBuildDefinitionInternal::FBuildDefinitionInternal(FStringView InName, FCbObject&& InDefinition, bool& bOutIsValid)
|
|
: Name(InName)
|
|
, Function(InDefinition.FindView("Function"_ASV).AsString())
|
|
, Definition(MoveTemp(InDefinition))
|
|
, Key{Definition.GetHash()}
|
|
{
|
|
checkf(!Name.IsEmpty(), TEXT("A build definition requires a non-empty name."));
|
|
Definition.MakeOwned();
|
|
bOutIsValid = Definition
|
|
&& IsValidBuildFunctionName(Function)
|
|
&& Algo::AllOf(Definition.AsView()["Constants"_ASV],
|
|
[](FCbFieldView Field) { return Field.GetName().Len() > 0 && Field.IsObject(); })
|
|
&& Algo::AllOf(Definition.AsView()["Inputs"_ASV]["Builds"_ASV], [](FCbFieldView Field)
|
|
{
|
|
return Field.GetName().Len() > 0 && Field.IsObject()
|
|
&& Field["Build"_ASV].IsHash()
|
|
&& Field["Id"_ASV].IsObjectId();
|
|
})
|
|
&& Algo::AllOf(Definition.AsView()["Inputs"_ASV]["BulkData"_ASV],
|
|
[](FCbFieldView Field) { return Field.GetName().Len() > 0 && Field.IsUuid(); })
|
|
&& Algo::AllOf(Definition.AsView()["Inputs"_ASV]["Files"_ASV],
|
|
[](FCbFieldView Field) { return Field.GetName().Len() > 0 && Field.AsString().Len() > 0; })
|
|
&& Algo::AllOf(Definition.AsView()["Inputs"_ASV]["Hashes"_ASV],
|
|
[](FCbFieldView Field) { return Field.GetName().Len() > 0 && Field.IsBinaryAttachment(); });
|
|
}
|
|
|
|
bool FBuildDefinitionInternal::HasConstants() const
|
|
{
|
|
return Definition["Constants"_ASV].HasValue();
|
|
}
|
|
|
|
bool FBuildDefinitionInternal::HasInputs() const
|
|
{
|
|
return Definition["Inputs"_ASV].HasValue();
|
|
}
|
|
|
|
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 FBuildValueKey& ValueKey)> Visitor) const
|
|
{
|
|
for (FCbFieldView Field : Definition.AsView()["Inputs"_ASV]["Builds"_ASV])
|
|
{
|
|
const FBuildKey BuildKey{Field["Build"_ASV].AsHash()};
|
|
const FValueId Id = Field["Id"_ASV].AsObjectId();
|
|
Visitor(FUTF8ToTCHAR(Field.GetName()), FBuildValueKey{BuildKey, Id});
|
|
}
|
|
}
|
|
|
|
void FBuildDefinitionInternal::IterateInputBulkData(TFunctionRef<void (FStringView Key, const FGuid& BulkDataId)> Visitor) const
|
|
{
|
|
for (FCbFieldView Field : Definition.AsView()["Inputs"_ASV]["BulkData"_ASV])
|
|
{
|
|
Visitor(FUTF8ToTCHAR(Field.GetName()), Field.AsUuid());
|
|
}
|
|
}
|
|
|
|
void FBuildDefinitionInternal::IterateInputFiles(TFunctionRef<void (FStringView Key, FStringView Path)> Visitor) const
|
|
{
|
|
for (FCbFieldView Field : Definition.AsView()["Inputs"_ASV]["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.AsView()["Inputs"_ASV]["Hashes"_ASV])
|
|
{
|
|
Visitor(FUTF8ToTCHAR(Field.GetName()), Field.AsBinaryAttachment());
|
|
}
|
|
}
|
|
|
|
void FBuildDefinitionInternal::Save(FCbWriter& Writer) const
|
|
{
|
|
Writer.AddObject(Definition);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
FBuildDefinition FBuildDefinitionBuilderInternal::Build()
|
|
{
|
|
return CreateBuildDefinition(new FBuildDefinitionInternal(MoveTemp(*this)));
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
FBuildDefinition CreateBuildDefinition(IBuildDefinitionInternal* Definition)
|
|
{
|
|
return FBuildDefinition(Definition);
|
|
}
|
|
|
|
FBuildDefinitionBuilder CreateBuildDefinitionBuilder(IBuildDefinitionBuilderInternal* DefinitionBuilder)
|
|
{
|
|
return FBuildDefinitionBuilder(DefinitionBuilder);
|
|
}
|
|
|
|
FBuildDefinitionBuilder CreateBuildDefinition(FStringView Name, FStringView Function)
|
|
{
|
|
return CreateBuildDefinitionBuilder(new FBuildDefinitionBuilderInternal(Name, Function));
|
|
}
|
|
|
|
} // UE::DerivedData::Private
|
|
|
|
namespace UE::DerivedData
|
|
{
|
|
|
|
FOptionalBuildDefinition FBuildDefinition::Load(FStringView Name, FCbObject&& Definition)
|
|
{
|
|
bool bIsValid = false;
|
|
FOptionalBuildDefinition Out = Private::CreateBuildDefinition(
|
|
new Private::FBuildDefinitionInternal(Name, MoveTemp(Definition), bIsValid));
|
|
if (!bIsValid)
|
|
{
|
|
Out.Reset();
|
|
}
|
|
return Out;
|
|
}
|
|
|
|
} // UE::DerivedData
|