zengine/engine/modules/engine/zlib/include/pmr/name.inl

154 lines
5.4 KiB
C++

#include "name.h"
constexpr inline size_t meta_align_size(size_t size, size_t alignment = 8) {
return (size + (alignment - 1)) & ~(alignment - 1);
}
XMALLOC_API void* xmalloc(size_t size);
namespace pmr {
inline bool Name::Slot::IsTargetSlot(HashInfo hashInfo) const
{
if (GetSlotHashProbe() == hashInfo.GetSlotHashProbe<IS_USED_MASK>())
{
const StringEntry* stringEntry = UNIQUER_VAL(stringEntryMemoryManager).GetStringEntry(GetStringEntryHandle());
auto entryHeader = stringEntry->GetStringEntryHeader();
if (entryHeader == hashInfo.GetStringEntryHeader() && 0 == strncmp(stringEntry->GetData(), hashInfo.GetData(), entryHeader.GetSize()))
{
return true;
}
}
return false;
}
inline Name::Slot& Name::SlotPool::FindUnusedOrTargetSlot(HashInfo hashInfo)
{
const uint32_t SLOT_POOL_CAPCITY_MASK = capcity - 1;
for (uint32_t slotIndex = hashInfo.GetSlotIndex() & SLOT_POOL_CAPCITY_MASK; true; slotIndex = (slotIndex + 1) & SLOT_POOL_CAPCITY_MASK)
{
Slot& slot = slotArray[slotIndex];
if (!slot.IsUsed() || slot.IsTargetSlot(hashInfo))
{
return slot;
}
}
}
inline Name::Slot& Name::SlotPool::FindUnusedSlot(HashInfo hashInfo)
{
const uint32_t SLOT_POOL_CAPCITY_MASK = capcity - 1;
for (uint32_t slotIndex = hashInfo.GetSlotIndex() & SLOT_POOL_CAPCITY_MASK; true; slotIndex = (slotIndex + 1) & SLOT_POOL_CAPCITY_MASK)
{
Slot& slot = slotArray[slotIndex];
if (!slot.IsUsed())
{
return slot;
}
}
}
inline void Name::SlotPool::AutoResize()
{
if (size > SLOT_POOL_RESIZE_USAGE_RATE * capcity)
{
Resize();
}
}
inline void Name::SlotPool::Resize()
{
uint32_t oldCapcity = capcity;
Slot* oldSlotArray = slotArray;
capcity = oldCapcity * 2;
slotArray = reinterpret_cast<Slot*>(xmalloc(capcity * sizeof(Slot)));
//std::memset(slotArray, 0, capcity * sizeof(Slot));
auto& stringEntryMemoryManager = UNIQUER_VAL(stringEntryMemoryManager);
for (uint32_t slotIndex = 0; slotIndex < size; slotIndex++)
{
const Name::Slot& oldSlot = oldSlotArray[slotIndex];
StringEntry* stringEntry = stringEntryMemoryManager.GetStringEntry(oldSlotArray[slotIndex].GetStringEntryHandle());
const HashInfo hashInfo(std::string_view(stringEntry->GetData(), stringEntry->GetSize()));
Name::Slot& slot = FindUnusedSlot(hashInfo);
slot.Load(oldSlot);
}
std::free(oldSlotArray);
}
inline Name::StringEntryMemoryManager::StringEntryMemoryManager()
{
for (auto& slotPool : slotPoolArray)
{
slotPool.size = 0;
slotPool.capcity = SlotPool::SLOT_POOL_INITIALIZE_SIZE;
slotPool.slotArray = (Slot*)(xmalloc(SlotPool::SLOT_POOL_INITIALIZE_SIZE * sizeof(Slot)));
std::memset(slotPool.slotArray, 0, SlotPool::SLOT_POOL_INITIALIZE_SIZE);
}
currentMemoryBlockIndex = 0;
currentMemoryBlockAlignedCursor = 0;
memoryBlockArray[0] = (char*)(xmalloc(MAX_MEMORY_BLOCK_SIZE));
std::memset(memoryBlockArray[0], 0, MAX_MEMORY_BLOCK_SIZE);
}
inline void Name::StringEntryMemoryManager::reinitialize()
{
g_memory_blocks = memoryBlockArray;
}
inline Name::StringEntry* Name::StringEntryMemoryManager::GetStringEntry(StringEntryHandle stringEntryHandle) const
{
return reinterpret_cast<Name::StringEntry*>(memoryBlockArray[stringEntryHandle.GetMemoryBlockIndex()] + stringEntryHandle.GetMemoryBlockAlignedOffset() * ALIGN_BYTES);
}
inline Name::StringEntryHandle Name::StringEntryMemoryManager::AllocateStringEntry(StringEntryHeader stringEntryHeader, const char* data)
{
const uint32_t size = meta_align_size(sizeof(StringEntryHeader) + stringEntryHeader.GetSize() + 1, ALIGN_BYTES);
const uint32_t alignedSize = size >> 1;
StringEntryHandle stringEntryHandle{};
{
std::unique_lock<std::mutex> lock(mutex);
if (((static_cast<uint32_t>(currentMemoryBlockAlignedCursor) + alignedSize) << 1) >= MAX_MEMORY_BLOCK_SIZE)
{
CreateNewMemoryBlock();
}
stringEntryHandle = StringEntryHandle(currentMemoryBlockIndex, currentMemoryBlockAlignedCursor);
currentMemoryBlockAlignedCursor += alignedSize;
}
StringEntry* stringEntry = GetStringEntry(stringEntryHandle);
stringEntry->SetStringEntryHeader(stringEntryHeader);
stringEntry->SetStringData(data, stringEntryHeader.GetSize());
return stringEntryHandle;
}
inline void Name::StringEntryMemoryManager::CreateNewMemoryBlock()
{
if (currentMemoryBlockIndex >= (MAX_MEMORY_BLOCK_ARRAY_SIZE - 1))
throw std::runtime_error("Interned string only supports a maximum of 1GB memory.");
currentMemoryBlockIndex += 1;
currentMemoryBlockAlignedCursor = 0;
memoryBlockArray[currentMemoryBlockIndex] = (char*)(xmalloc(MAX_MEMORY_BLOCK_SIZE));
std::memset(memoryBlockArray[currentMemoryBlockIndex], 0, MAX_MEMORY_BLOCK_SIZE);
}
inline uint32_t Name::MakeInterned(std::string_view view)
{
if (view.empty()) {
return 0u;
}
HashInfo hashInfo(view);
auto& stringEntryMemoryManager = UNIQUER_VAL(stringEntryMemoryManager);
auto& slotPool = stringEntryMemoryManager.slotPoolArray[hashInfo.GetSlotPoolIndex()];
uint32_t slotValue = 0u;
{
std::unique_lock<std::mutex> lock(slotPool.mutex);
slotPool.AutoResize();
Name::Slot& slot = slotPool.FindUnusedOrTargetSlot(hashInfo);
if (!slot.IsUsed())
{
slotPool.size++;
StringEntryHandle stringEntryHandle = stringEntryMemoryManager.AllocateStringEntry(hashInfo.GetStringEntryHeader(), hashInfo.GetData());
slot.Load(hashInfo.GetSlotHashProbe<IS_USED_MASK>(), stringEntryHandle);
}
slotValue = slot.GetSlotValue();
}
return slotValue;
}
}