Files
UnrealEngineUWP/Engine/Source/Developer/DerivedDataCache/Private/DerivedDataCacheKey.cpp
Devin Doucette 8c27714a84 DDC: Added ConvertLegacyCacheKey to construct new cache keys from legacy cache keys
The function is shared with the legacy cache store to allow callers of the legacy API to migrate to the value API using this conversion function without invalidating existing cache keys.

#preflight 624c9ab68d1db441a913137e
#rb Zousar.Shaker

[CL 19630681 by Devin Doucette in ue5-main branch]
2022-04-05 16:27:17 -04:00

150 lines
3.9 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "DerivedDataCacheKey.h"
#include "Containers/Set.h"
#include "Containers/StringConv.h"
#include "DerivedDataCachePrivate.h"
#include "IO/IoHash.h"
#include "Math/UnrealMathUtility.h"
#include "Misc/ScopeRWLock.h"
#include "Misc/StringBuilder.h"
#include "Serialization/CompactBinaryWriter.h"
#include "String/Find.h"
namespace UE::DerivedData::Private
{
template <typename CharType>
static inline void AssertValidCacheBucketName(TStringView<CharType> Name)
{
checkf(IsValidCacheBucketName(Name),
TEXT("A cache bucket name must be alphanumeric, non-empty, and contain fewer than 256 code units. ")
TEXT("Name: '%s'"), *WriteToString<256>(Name));
}
class FCacheBucketOwner : public FCacheBucket
{
public:
inline explicit FCacheBucketOwner(FAnsiStringView Bucket);
inline FCacheBucketOwner(FCacheBucketOwner&& Bucket);
inline ~FCacheBucketOwner();
FCacheBucketOwner(const FCacheBucketOwner&) = delete;
FCacheBucketOwner& operator=(const FCacheBucketOwner&) = delete;
using FCacheBucket::operator==;
inline bool operator==(FAnsiStringView Bucket) const { return ToString().Equals(Bucket, ESearchCase::IgnoreCase); }
friend inline uint32 GetTypeHash(const FCacheBucketOwner& Bucket)
{
return ::GetTypeHash(Bucket.ToString());
}
};
inline FCacheBucketOwner::FCacheBucketOwner(FAnsiStringView Bucket)
{
const int32 BucketLen = Bucket.Len();
const int32 PrefixSize = FMath::DivideAndRoundUp<int32>(1, sizeof(ANSICHAR));
ANSICHAR* Buffer = new ANSICHAR[PrefixSize + BucketLen + 1];
Buffer += PrefixSize;
Name = Buffer;
reinterpret_cast<uint8*>(Buffer)[LengthOffset] = static_cast<uint8>(BucketLen);
Bucket.CopyString(Buffer, BucketLen);
Buffer += BucketLen;
*Buffer = '\0';
}
inline FCacheBucketOwner::FCacheBucketOwner(FCacheBucketOwner&& Bucket)
: FCacheBucket(Bucket)
{
Bucket.Reset();
}
inline FCacheBucketOwner::~FCacheBucketOwner()
{
if (Name)
{
const int32 PrefixSize = FMath::DivideAndRoundUp<int32>(1, sizeof(ANSICHAR));
delete[] (Name - PrefixSize);
}
}
class FCacheBuckets
{
public:
template <typename CharType>
inline FCacheBucket FindOrAdd(TStringView<CharType> Name);
private:
FRWLock Lock;
TSet<FCacheBucketOwner> Buckets;
};
template <typename CharType>
inline FCacheBucket FCacheBuckets::FindOrAdd(TStringView<CharType> Name)
{
const auto AnsiCast = StringCast<ANSICHAR>(Name.GetData(), Name.Len());
const FAnsiStringView AnsiName = AnsiCast;
const uint32 Hash = GetTypeHash(AnsiName);
if (FReadScopeLock ReadLock(Lock); const FCacheBucketOwner* Bucket = Buckets.FindByHash(Hash, AnsiName))
{
return *Bucket;
}
// It is valid to assert after because the "bogus char" '?' is not valid in a bucket name.
AssertValidCacheBucketName(Name);
FCacheBucketOwner LocalBucket(AnsiName);
FWriteScopeLock WriteLock(Lock);
return Buckets.FindOrAddByHash(Hash, MoveTemp(LocalBucket));
}
static FCacheBuckets& GetCacheBuckets()
{
static FCacheBuckets Buckets;
return Buckets;
}
} // UE::DerivedData::Private
namespace UE::DerivedData
{
FCacheBucket::FCacheBucket(FUtf8StringView InName)
: FCacheBucket(Private::GetCacheBuckets().FindOrAdd(InName))
{
}
FCacheBucket::FCacheBucket(FWideStringView InName)
: FCacheBucket(Private::GetCacheBuckets().FindOrAdd(InName))
{
}
FCbWriter& operator<<(FCbWriter& Writer, const FCacheKey& Key)
{
Writer.BeginObject();
Writer.AddString(ANSITEXTVIEW("Bucket"), Key.Bucket.ToString());
Writer.AddHash(ANSITEXTVIEW("Hash"), Key.Hash);
Writer.EndObject();
return Writer;
}
FCacheKey ConvertLegacyCacheKey(const FStringView Key)
{
FTCHARToUTF8 Utf8Key(Key);
TUtf8StringBuilder<64> Utf8Bucket;
Utf8Bucket << ANSITEXTVIEW("Legacy");
if (const int32 BucketEnd = String::FindFirstChar(Utf8Key, '_'); BucketEnd != INDEX_NONE)
{
Utf8Bucket << FUtf8StringView(Utf8Key).Left(BucketEnd);
}
const FCacheBucket Bucket(Utf8Bucket);
return {Bucket, FIoHash::HashBuffer(MakeMemoryView(Utf8Key))};
}
} // UE::DerivedData