// Copyright Epic Games, Inc. All Rights Reserved. #include "DerivedDataBuildInputs.h" #include "Compression/CompressedBuffer.h" #include "Containers/Map.h" #include "Containers/SharedString.h" #include "Containers/StringView.h" #include "DerivedDataBuildPrivate.h" #include "Misc/StringBuilder.h" #include namespace UE::DerivedData::Private { class FBuildInputsBuilderInternal final : public IBuildInputsBuilderInternal { public: inline explicit FBuildInputsBuilderInternal(const FSharedString& InName) : Name(InName) { checkf(!Name.IsEmpty(), TEXT("Build inputs require a non-empty name.")); } ~FBuildInputsBuilderInternal() final = default; void AddInput(FUtf8StringView Key, const FCompressedBuffer& Buffer) final { const uint32 KeyHash = GetTypeHash(Key); checkf(Buffer, TEXT("Null buffer used in input for build of '%s'."), *Name); checkf(!Key.IsEmpty(), TEXT("Empty key used in input for build of '%s'."), *Name); checkf(!Inputs.ContainsByHash(KeyHash, Key), TEXT("Duplicate key '%s' used in input for build of '%s'."), *WriteToString<64>(Key), *Name); Inputs.EmplaceByHash(KeyHash, Key, Buffer); } FBuildInputs Build() final; FSharedString Name; TMap Inputs; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class FBuildInputsInternal final : public IBuildInputsInternal { public: explicit FBuildInputsInternal(FBuildInputsBuilderInternal&& InputsBuilder); ~FBuildInputsInternal() final = default; const FSharedString& GetName() const final { return Name; } const FCompressedBuffer& FindInput(FUtf8StringView Key) const final; void IterateInputs(TFunctionRef Visitor) 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: FSharedString Name; TMap Inputs; mutable std::atomic ReferenceCount{0}; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// FBuildInputsInternal::FBuildInputsInternal(FBuildInputsBuilderInternal&& InputsBuilder) : Name(MoveTemp(InputsBuilder.Name)) , Inputs(MoveTemp(InputsBuilder.Inputs)) { Inputs.KeySort(TLess<>()); } const FCompressedBuffer& FBuildInputsInternal::FindInput(FUtf8StringView Key) const { if (const FCompressedBuffer* Buffer = Inputs.FindByHash(GetTypeHash(Key), Key)) { return *Buffer; } return FCompressedBuffer::Null; } void FBuildInputsInternal::IterateInputs(TFunctionRef Visitor) const { for (const TPair& Input : Inputs) { Input.ApplyAfter(Visitor); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// FBuildInputs FBuildInputsBuilderInternal::Build() { return CreateBuildInputs(new FBuildInputsInternal(MoveTemp(*this))); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// FBuildInputs CreateBuildInputs(IBuildInputsInternal* Inputs) { return FBuildInputs(Inputs); } FBuildInputsBuilder CreateBuildInputsBuilder(IBuildInputsBuilderInternal* InputsBuilder) { return FBuildInputsBuilder(InputsBuilder); } FBuildInputsBuilder CreateBuildInputs(const FSharedString& Name) { return CreateBuildInputsBuilder(new FBuildInputsBuilderInternal(Name)); } } // UE::DerivedData::Private