2021-01-21 01:57:01 -04:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
|
|
#include "DerivedDataCacheKey.h"
|
|
|
|
|
|
|
|
|
|
#include "Algo/AllOf.h"
|
2021-02-24 11:46:41 -04:00
|
|
|
#include "Containers/Set.h"
|
|
|
|
|
#include "Misc/ScopeRWLock.h"
|
2021-01-21 01:57:01 -04:00
|
|
|
|
|
|
|
|
namespace UE
|
|
|
|
|
{
|
|
|
|
|
namespace DerivedData
|
|
|
|
|
{
|
2021-03-10 17:33:38 -04:00
|
|
|
namespace Private
|
|
|
|
|
{
|
2021-01-21 01:57:01 -04:00
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2021-02-24 11:46:41 -04:00
|
|
|
class FCacheBuckets
|
2021-01-21 01:57:01 -04:00
|
|
|
{
|
2021-02-24 11:46:41 -04:00
|
|
|
public:
|
|
|
|
|
inline const TCHAR* FindOrAdd(FStringView Name)
|
|
|
|
|
{
|
|
|
|
|
const uint32 Hash = GetTypeHash(Name);
|
|
|
|
|
{
|
|
|
|
|
FReadScopeLock ReadLock(Lock);
|
|
|
|
|
if (const FBucket* Bucket = Buckets.FindByHash(Hash, Name))
|
|
|
|
|
{
|
|
|
|
|
return Bucket->GetName();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
FWriteScopeLock WriteLock(Lock);
|
|
|
|
|
const FBucket& Bucket = Buckets.FindOrAddByHash(Hash, FBucket(Name));
|
|
|
|
|
return Bucket.GetName();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
class FBucket
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline explicit FBucket(FStringView Bucket)
|
|
|
|
|
{
|
|
|
|
|
const int32 BucketLen = Bucket.Len();
|
|
|
|
|
TCHAR* Buffer = new TCHAR[BucketLen + 2];
|
|
|
|
|
*reinterpret_cast<uint8*>(Buffer++) = static_cast<uint8>(BucketLen);
|
|
|
|
|
Bucket.CopyString(Buffer, BucketLen);
|
|
|
|
|
Buffer[BucketLen] = TEXT('\0');
|
|
|
|
|
Name = Buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FBucket(const FBucket&) = delete;
|
|
|
|
|
FBucket& operator=(const FBucket&) = delete;
|
|
|
|
|
|
|
|
|
|
inline FBucket(FBucket&& Bucket)
|
|
|
|
|
: Name(Bucket.Name)
|
|
|
|
|
{
|
|
|
|
|
Bucket.Name = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FBucket& operator=(FBucket&& Bucket)
|
|
|
|
|
{
|
|
|
|
|
Name = Bucket.Name;
|
|
|
|
|
Bucket.Name = nullptr;
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline ~FBucket()
|
|
|
|
|
{
|
|
|
|
|
if (Name)
|
|
|
|
|
{
|
|
|
|
|
delete[] (Name - 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline FStringView ToString() const
|
|
|
|
|
{
|
|
|
|
|
return FStringView(Name, *reinterpret_cast<const uint8*>(Name - 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool operator==(const FBucket& Bucket) const
|
|
|
|
|
{
|
|
|
|
|
return Name == Bucket.Name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool operator==(FStringView Bucket) const
|
|
|
|
|
{
|
|
|
|
|
return ToString().Equals(Bucket, ESearchCase::IgnoreCase);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
friend inline uint32 GetTypeHash(const FBucket& Bucket)
|
|
|
|
|
{
|
|
|
|
|
return GetTypeHash(Bucket.ToString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline const TCHAR* GetName() const { return Name; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const TCHAR* Name;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FRWLock Lock;
|
|
|
|
|
TSet<FBucket> Buckets;
|
|
|
|
|
};
|
|
|
|
|
|
2021-03-10 12:23:29 -04:00
|
|
|
FCacheBucket CreateCacheBucket(FStringView Name)
|
2021-02-24 11:46:41 -04:00
|
|
|
{
|
2021-03-10 12:23:29 -04:00
|
|
|
checkf(!Name.IsEmpty() && Name.Len() < 256 && Algo::AllOf(Name, FChar::IsAlnum),
|
2021-02-24 11:46:41 -04:00
|
|
|
TEXT("Invalid cache bucket name '%.*s' must be alphanumeric, non-empty, and contain fewer than 256 characters."),
|
2021-03-10 12:23:29 -04:00
|
|
|
Name.Len(), Name.GetData());
|
2021-02-24 11:46:41 -04:00
|
|
|
static FCacheBuckets Buckets;
|
2021-03-10 17:33:38 -04:00
|
|
|
return FCacheBucket(FCacheBucketName{Buckets.FindOrAdd(Name)});
|
2021-01-21 01:57:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2021-03-10 17:33:38 -04:00
|
|
|
} // Private
|
2021-01-21 01:57:01 -04:00
|
|
|
} // DerivedData
|
|
|
|
|
} // UE
|