diff --git a/engine/src/assets/pools/mesh_pool.cpp b/engine/src/assets/pools/mesh_pool.cpp index c7c4010..2183ebe 100644 --- a/engine/src/assets/pools/mesh_pool.cpp +++ b/engine/src/assets/pools/mesh_pool.cpp @@ -4,6 +4,10 @@ namespace sophia { +namespace { +constexpr u32 GENERATION_MASK = (1u << 12) - 1; +} // namespace + MeshPool::MeshPool(Device& device) : device{device} {} MeshPool::~MeshPool() = default; @@ -12,30 +16,43 @@ MeshHandle MeshPool::create(const Mesh::Builder& builder) { auto mesh = std::make_unique(device, builder); if (!freeList.empty()) { - MeshHandle handle = freeList.back(); + u32 index = freeList.back(); freeList.pop_back(); - meshes[handle] = std::move(mesh); - return handle; + slots[index].mesh = std::move(mesh); + return MeshHandle{index, slots[index].generation}; } - meshes.push_back(std::move(mesh)); - return static_cast(meshes.size() - 1); + slots.push_back(Slot{std::move(mesh), 0}); + return MeshHandle{static_cast(slots.size() - 1), 0}; } const Mesh& MeshPool::get(MeshHandle handle) const { - SOPHIA_ASSERT(handle < meshes.size(), "invalid MeshHandle:", handle); - SOPHIA_ASSERT(meshes[handle] != nullptr, - "MeshHandle refers to a released mesh:", handle); - return *meshes[handle]; + SOPHIA_ASSERT(handle.isValid(), "invalid MeshHandle"); + SOPHIA_ASSERT(handle.index < slots.size(), + "MeshHandle index out of range:", handle.index); + + const Slot& slot = slots[handle.index]; + SOPHIA_ASSERT(slot.generation == handle.generation, + "stale MeshHandle (generation mismatch):", handle.index); + SOPHIA_ASSERT(slot.mesh != nullptr, + "MeshHandle refers to a released mesh:", handle.index); + return *slot.mesh; } void MeshPool::release(MeshHandle handle) { - SOPHIA_ASSERT(handle < meshes.size(), "invalid MeshHandle:", handle); - SOPHIA_ASSERT(meshes[handle] != nullptr, - "MeshHandle already released:", handle); + SOPHIA_ASSERT(handle.isValid(), "invalid MeshHandle"); + SOPHIA_ASSERT(handle.index < slots.size(), + "MeshHandle index out of range:", handle.index); - meshes[handle].reset(); - freeList.push_back(handle); + Slot& slot = slots[handle.index]; + SOPHIA_ASSERT(slot.generation == handle.generation, + "stale MeshHandle (generation mismatch):", handle.index); + SOPHIA_ASSERT(slot.mesh != nullptr, + "MeshHandle already released:", handle.index); + + slot.mesh.reset(); + slot.generation = (slot.generation + 1) & GENERATION_MASK; + freeList.push_back(handle.index); } } // namespace sophia diff --git a/engine/src/assets/pools/mesh_pool.hpp b/engine/src/assets/pools/mesh_pool.hpp index 09845e5..218f0bb 100644 --- a/engine/src/assets/pools/mesh_pool.hpp +++ b/engine/src/assets/pools/mesh_pool.hpp @@ -21,10 +21,15 @@ class MeshPool { void release(MeshHandle handle); private: + struct Slot { + std::unique_ptr mesh; + u32 generation = 0; + }; + Device& device; - std::vector> meshes; - std::vector freeList; + std::vector slots; + std::vector freeList; }; } // namespace sophia