Extract slotkey from slotmap

This commit is contained in:
2026-07-30 23:17:28 +02:00
parent 5283e238fb
commit 33944d0b7d
3 changed files with 124 additions and 121 deletions
@@ -15,77 +15,77 @@
namespace Bigfoot
{
template<class TYPE,
class VERSION_TYPE = std::uint32_t,
template<class VERSION_TYPE = std::uint32_t,
class INDEX_TYPE = std::uint32_t,
std::enable_if_t<std::is_unsigned_v<VERSION_TYPE> && std::is_unsigned_v<INDEX_TYPE>, bool> = true>
class SlotMapKey
{
public:
using IndexType = INDEX_TYPE;
using VersionType = VERSION_TYPE;
private:
static constexpr std::uint32_t VERSION_BIT_COUNT = sizeof(VersionType) * std::numeric_limits<unsigned char>::digits;
static constexpr std::uint32_t INDEX_BIT_COUNT = sizeof(IndexType) * std::numeric_limits<unsigned char>::digits;
static_assert(VERSION_BIT_COUNT + INDEX_BIT_COUNT <= 64,
"We cant construct a 64 bit key from the given Version and Index types!");
static constexpr std::uint64_t INDEX_MASK = (static_cast<std::uint64_t>(1) << INDEX_BIT_COUNT) - 1;
public:
static constexpr VersionType INVALID_VERSION = 0;
static constexpr IndexType MAX_INDEX = std::numeric_limits<IndexType>::max();
constexpr SlotMapKey(const VersionType p_version, const IndexType p_index):
m_key((static_cast<std::uint64_t>(p_version) << INDEX_BIT_COUNT) |
(static_cast<std::uint64_t>(p_index) & INDEX_MASK))
{
}
constexpr SlotMapKey():
SlotMapKey(INVALID_VERSION, 0)
{
}
constexpr SlotMapKey(const SlotMapKey& p_slotKey) = default;
constexpr SlotMapKey(SlotMapKey&& p_slotKey) = default;
constexpr ~SlotMapKey() = default;
constexpr bool Valid() const
{
return GetVersion() != INVALID_VERSION;
}
constexpr VersionType GetVersion() const
{
return static_cast<VersionType>(m_key >> INDEX_BIT_COUNT);
}
constexpr IndexType GetIndex() const
{
return static_cast<IndexType>(m_key & INDEX_MASK);
}
constexpr SlotMapKey& operator=(const SlotMapKey& p_slotKey) = default;
constexpr SlotMapKey& operator=(SlotMapKey&& p_slotKey) = default;
[[nodiscard]]
constexpr bool operator==(const SlotMapKey& p_other) const = default;
private:
std::uint64_t m_key;
};
template<class TYPE, class VERSION_TYPE = std::uint32_t, class INDEX_TYPE = std::uint32_t>
class SlotMap
{
public:
class SlotKey
{
public:
using IndexType = INDEX_TYPE;
using VersionType = VERSION_TYPE;
private:
static constexpr std::uint32_t VERSION_BIT_COUNT = sizeof(VersionType) *
std::numeric_limits<unsigned char>::digits;
static constexpr std::uint32_t INDEX_BIT_COUNT = sizeof(IndexType) * std::numeric_limits<unsigned char>::digits;
static_assert(VERSION_BIT_COUNT + INDEX_BIT_COUNT <= 64,
"We cant construct a 64 bit key from the given Version and Index types!");
static constexpr std::uint64_t INDEX_MASK = (static_cast<std::uint64_t>(1) << INDEX_BIT_COUNT) - 1;
public:
static constexpr VersionType INVALID_VERSION = 0;
static constexpr IndexType MAX_INDEX = std::numeric_limits<IndexType>::max();
constexpr SlotKey(const VersionType p_version, const IndexType p_index):
m_key((static_cast<std::uint64_t>(p_version) << INDEX_BIT_COUNT) |
(static_cast<std::uint64_t>(p_index) & INDEX_MASK))
{
}
constexpr SlotKey():
SlotKey(INVALID_VERSION, 0)
{
}
constexpr SlotKey(const SlotKey& p_slotKey) = default;
constexpr SlotKey(SlotKey&& p_slotKey) = default;
constexpr ~SlotKey() = default;
constexpr bool Valid() const
{
return GetVersion() != INVALID_VERSION;
}
constexpr VersionType GetVersion() const
{
return static_cast<VersionType>(m_key >> INDEX_BIT_COUNT);
}
constexpr IndexType GetIndex() const
{
return static_cast<IndexType>(m_key & INDEX_MASK);
}
constexpr SlotKey& operator=(const SlotKey& p_slotKey) = default;
constexpr SlotKey& operator=(SlotKey&& p_slotKey) = default;
[[nodiscard]]
constexpr bool operator==(const SlotKey& p_other) const = default;
private:
std::uint64_t m_key;
};
using InternalSlotKey = SlotMapKey<VERSION_TYPE, INDEX_TYPE>;
SlotMap():
m_freeSlotHead(std::numeric_limits<typename SlotKey::IndexType>::max())
m_freeSlotHead(std::numeric_limits<typename InternalSlotKey::IndexType>::max())
{
}
@@ -96,67 +96,68 @@ class SlotMap
template<class... ARGS>
[[nodiscard]]
SlotKey Insert(ARGS&&... p_args)
InternalSlotKey Insert(ARGS&&... p_args)
{
ASSERT(UtilsAssertHandler, m_slots.size() < SlotKey::MAX_INDEX, "All slots have been exhausted!");
ASSERT(UtilsAssertHandler, m_slots.size() < InternalSlotKey::MAX_INDEX, "All slots have been exhausted!");
const typename SlotKey::IndexType dataIndex = static_cast<SlotKey::IndexType>(m_data.size());
const typename InternalSlotKey::IndexType dataIndex = static_cast<InternalSlotKey::IndexType>(m_data.size());
m_data.emplace_back(std::forward<ARGS>(p_args)...);
if (HasFreeSlots())
{
const typename SlotKey::IndexType slotIndex = m_freeSlotHead;
const typename InternalSlotKey::IndexType slotIndex = m_freeSlotHead;
m_freeSlotHead = m_slots[slotIndex].GetIndex();
m_slots[slotIndex] = SlotKey {m_slots[slotIndex].GetVersion(), dataIndex};
m_slots[slotIndex] = InternalSlotKey {m_slots[slotIndex].GetVersion(), dataIndex};
m_dataToSlots.push_back(slotIndex);
return SlotKey {m_slots[slotIndex].GetVersion(), slotIndex};
return InternalSlotKey {m_slots[slotIndex].GetVersion(), slotIndex};
}
const typename SlotKey::IndexType slotIndex = static_cast<SlotKey::IndexType>(m_slots.size());
const typename InternalSlotKey::IndexType slotIndex = static_cast<InternalSlotKey::IndexType>(m_slots.size());
m_slots.emplace_back(1, dataIndex);
m_dataToSlots.push_back(slotIndex);
return SlotKey {1, slotIndex};
return InternalSlotKey {1, slotIndex};
}
void Remove(const SlotKey p_slotKey)
void Remove(const InternalSlotKey p_slotKey)
{
if (!Has(p_slotKey))
{
return;
}
const typename SlotKey::IndexType dataIndex = m_slots[p_slotKey.GetIndex()].GetIndex();
const typename InternalSlotKey::IndexType dataIndex = m_slots[p_slotKey.GetIndex()].GetIndex();
m_data.erase_unsorted(m_data.begin() + dataIndex);
m_dataToSlots.erase_unsorted(m_dataToSlots.begin() + dataIndex);
if (dataIndex < m_data.size())
{
m_slots[m_dataToSlots[dataIndex]] = SlotKey {m_slots[m_dataToSlots[dataIndex]].GetVersion(), dataIndex};
m_slots[m_dataToSlots[dataIndex]] = InternalSlotKey {m_slots[m_dataToSlots[dataIndex]].GetVersion(),
dataIndex};
}
RecycleSlot(p_slotKey.GetVersion() + 1, p_slotKey.GetIndex());
}
[[nodiscard]]
bool Has(const SlotKey p_slotKey) const
bool Has(const InternalSlotKey p_slotKey) const
{
return p_slotKey.Valid() && (p_slotKey.GetIndex() < m_slots.size() &&
p_slotKey.GetVersion() == m_slots[p_slotKey.GetIndex()].GetVersion());
}
[[nodiscard]]
TYPE* Get(const SlotKey p_slotKey)
TYPE* Get(const InternalSlotKey p_slotKey)
{
return Has(p_slotKey) ? &m_data[m_slots[p_slotKey.GetIndex()].GetIndex()] : nullptr;
}
[[nodiscard]]
const TYPE* Get(const SlotKey p_slotKey) const
const TYPE* Get(const InternalSlotKey p_slotKey) const
{
return Has(p_slotKey) ? &m_data[m_slots[p_slotKey.GetIndex()].GetIndex()] : nullptr;
}
@@ -166,14 +167,14 @@ class SlotMap
m_data.clear();
m_slots.clear();
m_dataToSlots.clear();
m_freeSlotHead = std::numeric_limits<typename SlotKey::IndexType>::max();
m_freeSlotHead = std::numeric_limits<typename InternalSlotKey::IndexType>::max();
}
void Clear()
{
for (const typename eastl::vector<TYPE>::size_type slotIndex: m_dataToSlots)
{
RecycleSlot(m_slots[slotIndex].GetVersion() + 1, static_cast<SlotKey::IndexType>(slotIndex));
RecycleSlot(m_slots[slotIndex].GetVersion() + 1, static_cast<InternalSlotKey::IndexType>(slotIndex));
}
m_data.clear();
@@ -284,27 +285,27 @@ class SlotMap
[[nodiscard]]
bool HasFreeSlots() const
{
return m_freeSlotHead != std::numeric_limits<typename SlotKey::IndexType>::max();
return m_freeSlotHead != std::numeric_limits<typename InternalSlotKey::IndexType>::max();
}
void RecycleSlot(const SlotKey::VersionType p_version, const SlotKey::IndexType p_slotIndex)
void RecycleSlot(const InternalSlotKey::VersionType p_version, const InternalSlotKey::IndexType p_slotIndex)
{
if (p_version == SlotKey::INVALID_VERSION)
if (p_version == InternalSlotKey::INVALID_VERSION)
{
m_slots[p_slotIndex] = SlotKey {SlotKey::INVALID_VERSION, 0};
m_slots[p_slotIndex] = InternalSlotKey {InternalSlotKey::INVALID_VERSION, 0};
return;
}
m_slots[p_slotIndex] = SlotKey {p_version, m_freeSlotHead};
m_slots[p_slotIndex] = InternalSlotKey {p_version, m_freeSlotHead};
m_freeSlotHead = p_slotIndex;
}
eastl::vector<TYPE> m_data;
eastl::vector<SlotKey> m_slots;
eastl::vector<InternalSlotKey> m_slots;
eastl::vector<typename eastl::vector<TYPE>::size_type> m_dataToSlots;
SlotKey::IndexType m_freeSlotHead;
InternalSlotKey::IndexType m_freeSlotHead;
};
} // namespace Bigfoot