Files
UnrealEngineUWP/Engine/Source/Developer/DerivedDataCache/Private/DerivedDataCacheKey.cpp
Devin Doucette 155d29af66 DDC: Fixed checkSlow by adding otherwise-unused GetTypeHash for FCacheBucketOwner
#rb Zousar.Shaker
#rnx

[CL 16449009 by Devin Doucette in ue5-main branch]
2021-05-25 11:02:36 -04:00

117 lines
3.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "DerivedDataCacheKey.h"
#include "Algo/AllOf.h"
#include "Containers/Set.h"
#include "Math/UnrealMathUtility.h"
#include "Misc/ScopeRWLock.h"
namespace UE::DerivedData::Private
{
class FCacheBucketOwner : public FCacheBucket
{
public:
static const TCHAR* AllocName(FStringView Bucket);
inline explicit FCacheBucketOwner(FStringView Bucket);
inline FCacheBucketOwner(FCacheBucketOwner&& Bucket);
inline ~FCacheBucketOwner();
FCacheBucketOwner(const FCacheBucketOwner&) = delete;
FCacheBucketOwner& operator=(const FCacheBucketOwner&) = delete;
using FCacheBucket::operator==;
inline bool operator==(FStringView Bucket) const { return ToString<TCHAR>().Equals(Bucket, ESearchCase::IgnoreCase); }
friend inline uint32 GetTypeHash(const FCacheBucketOwner& Bucket)
{
return ::GetTypeHash(Bucket.ToString<TCHAR>());
}
};
inline const TCHAR* FCacheBucketOwner::AllocName(FStringView Bucket)
{
FTCHARToUTF8 Bucket8Conversion(Bucket);
FAnsiStringView Bucket8 = Bucket8Conversion;
const int32 BucketLen = Bucket.Len();
const int32 Bucket8Len = Bucket8.Len();
const int32 PrefixSize = FMath::DivideAndRoundUp<int32>(2, sizeof(TCHAR));
TCHAR* Buffer = new TCHAR[PrefixSize + BucketLen + 1 + FMath::DivideAndRoundUp<int32>(Bucket8Len + 1, sizeof(TCHAR))];
Buffer += PrefixSize;
const TCHAR* const Name = Buffer;
reinterpret_cast<uint8*>(Buffer)[LengthOffset] = static_cast<uint8>(BucketLen);
reinterpret_cast<uint8*>(Buffer)[LengthOffset8] = static_cast<uint8>(Bucket8Len);
Bucket.CopyString(Buffer, BucketLen);
Buffer += BucketLen;
*Buffer++ = TEXT('\0');
ANSICHAR* Buffer8 = reinterpret_cast<ANSICHAR*>(Buffer);
Bucket8.CopyString(Buffer8, Bucket8Len);
Buffer8 += Bucket8Len;
*Buffer8++ = '\0';
return Name;
}
inline FCacheBucketOwner::FCacheBucketOwner(FStringView Bucket)
: FCacheBucket(AllocName(Bucket))
{
}
inline FCacheBucketOwner::FCacheBucketOwner(FCacheBucketOwner&& Bucket)
: FCacheBucket(Bucket)
{
Bucket.Reset();
}
inline FCacheBucketOwner::~FCacheBucketOwner()
{
if (IsValid())
{
const int32 PrefixSize = FMath::DivideAndRoundUp<int32>(2, sizeof(TCHAR));
delete[] (ToString<TCHAR>().GetData() - PrefixSize);
}
}
class FCacheBuckets
{
public:
inline FCacheBucket FindOrAdd(FStringView Name);
private:
FRWLock Lock;
TSet<FCacheBucketOwner> Buckets;
};
inline FCacheBucket FCacheBuckets::FindOrAdd(FStringView Name)
{
const uint32 Hash = GetTypeHash(Name);
if (FReadScopeLock ReadLock(Lock); const FCacheBucketOwner* Bucket = Buckets.FindByHash(Hash, Name))
{
return *Bucket;
}
checkf(FCString::IsPureAnsi(Name.GetData(), Name.Len()) && Algo::AllOf(Name, FChar::IsAlnum) &&
!Name.IsEmpty() && Name.Len() < 256,
TEXT("Invalid cache bucket name '%.*s' must be alphanumeric, non-empty, and contain fewer than 256 code units."),
Name.Len(), Name.GetData());
FCacheBucketOwner LocalBucket(Name);
FWriteScopeLock WriteLock(Lock);
return Buckets.FindOrAddByHash(Hash, MoveTemp(LocalBucket));
}
FCacheBucket CreateCacheBucket(FStringView Name)
{
static FCacheBuckets Buckets;
return Buckets.FindOrAdd(Name);
}
} // UE::DerivedData::Private