154 lines
5.4 KiB
C++
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;
|
|
}
|
|
} |