Files
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

232 lines
4.0 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Chaos/Character/CharacterGroundConstraintContainer.h"
#include "Chaos/Deformable/MuscleActivationConstraints.h"
#include "Templates/SharedPointer.h"
#include "Misc/ScopeLock.h"
template <typename KeyType, typename ValueType>
class TRegistry : public TSharedFromThis<TRegistry<KeyType, ValueType>>
{
public:
class FHandle
{
friend TRegistry;
public:
FHandle() = default;
private:
FHandle(uint32 InId, const TWeakPtr<TRegistry>& InWeakRegistry)
{
Id = InId;
WeakRegistry = InWeakRegistry;
}
public:
FHandle(const FHandle& Other)
{
*this = Other;
}
FHandle(FHandle&& Other)
{
*this = MoveTemp(Other);
}
operator bool() const
{
return Id != ID_NONE && WeakRegistry.IsValid();
}
FHandle& operator=(const FHandle& Other)
{
Id = Other.Id;
WeakRegistry = Other.WeakRegistry;
if (TSharedPtr<TRegistry> Registry = WeakRegistry.Pin())
{
Registry->Increment(Id);
}
return *this;
}
FHandle& operator=(FHandle&& Other)
{
Id = Other.Id;
Other.Id = ID_NONE;
WeakRegistry = Other.WeakRegistry;
Other.WeakRegistry = nullptr;
return *this;
}
bool operator==(const FHandle& Other) const
{
return Id == Other.Id && WeakRegistry == Other.WeakRegistry;
}
~FHandle()
{
if (TSharedPtr<TRegistry> Registry = WeakRegistry.Pin())
{
Registry->Decrement(Id);
}
}
const KeyType* GetKey() const
{
if (TSharedPtr<TRegistry> Registry = WeakRegistry.Pin())
{
return &Registry->GetKey(Id);
}
else
{
return nullptr;
}
}
const ValueType* GetValue() const
{
if (TSharedPtr<TRegistry> Registry = WeakRegistry.Pin())
{
return &Registry->GetValue(Id);
}
else
{
return nullptr;
}
}
FString ToString() const
{
return FString::FromInt(Id);
}
friend uint32 GetTypeHash(const FHandle& Handle)
{
return HashCombine(Handle.Id, GetTypeHash(Handle.WeakRegistry));
}
private:
uint32 Id = ID_NONE;
TWeakPtr<TRegistry> WeakRegistry;
};
private:
struct FKeyContainer
{
TSharedRef<KeyType> Key;
bool operator==(const FKeyContainer& Other) const
{
return Key.Get() == Other.Key.Get();
}
bool operator==(const KeyType& Other) const
{
return Key.Get() == Other;
}
friend uint32 GetTypeHash(const FKeyContainer& KeyContainer)
{
return GetTypeHash(KeyContainer.Key.Get());
}
};
struct FEntry
{
uint32 RefCount = 0;
FKeyContainer KeyContainer;
ValueType Value;
};
public:
FHandle Add(const KeyType& Key, const ValueType& Value)
{
FScopeLock Lock(&CriticalSection);
if (uint32* Result = KeyIndex.FindByHash(GetTypeHash(Key), Key))
{
const uint32 Id = *Result;
++Entries[Id].RefCount;
return FHandle(Id, TSharedFromThis<TRegistry>::AsShared());
}
uint32 Id = GlobalId++;
FKeyContainer KeyContainer { MakeShared<KeyType>(Key) };
Entries.Emplace(Id, FEntry(1, KeyContainer, Value));
KeyIndex.Emplace(KeyContainer, Id);
return FHandle(Id, TSharedFromThis<TRegistry>::AsShared());
}
ValueType* Find(const KeyType& Key)
{
if (uint32* Result = KeyIndex.FindByHash(GetTypeHash(Key), Key))
{
const uint32 Id = *Result;
return &Entries[Id].Value;
}
else
{
return nullptr;
}
}
private:
const KeyType& GetKey(int32 Id) const
{
return Entries[Id].KeyContainer.Key.Get();
}
const ValueType& GetValue(int32 Id) const
{
return Entries[Id].Value;
}
void Increment(uint32 Id)
{
FScopeLock Lock(&CriticalSection);
FEntry& Entry = Entries[Id];
++Entry.RefCount;
}
void Decrement(uint32 Id)
{
FScopeLock Lock(&CriticalSection);
FEntry& Entry = Entries[Id];
--Entry.RefCount;
if (Entry.RefCount == 0)
{
KeyIndex.Remove(Entry.KeyContainer);
Entries.Remove(Id);
}
}
static constexpr uint32 ID_NONE = TNumericLimits<uint32>::Max();
/** Global incremental Id counter. */
uint32 GlobalId = 0;
TMap<uint32, FEntry> Entries;
TMap<FKeyContainer, uint32> KeyIndex;
FCriticalSection CriticalSection;
};