Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/gamecoe/entity/entities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ namespace gamecoe
id = m_recycle_ids.back();
m_recycle_ids.pop_back();
generation = m_generations[id];
GAMECOE_ASSERT_GUARD(generation <= entity::MAX_GENERATIONS,
"entities::create(): recycled entity generation exceeds maximum",
entity::invalid());
m_self_active[id] = true;
}

Expand Down Expand Up @@ -85,7 +82,9 @@ namespace gamecoe
to_destroy.insert(to_destroy.end(), kids->handles.begin(), kids->handles.end());

m_generations[current.id()]++;
m_recycle_ids.push_back(current.id());
bool exhausted = m_generations[current.id()] > entity::MAX_GENERATIONS;
GAMECOE_ASSERT_LOG(!exhausted, "entities::destroy(): id's generation reached the maximum, permanently retiring this id");
if (!exhausted) m_recycle_ids.push_back(current.id());

for (auto &pool : m_pools) if (pool) pool->remove(current);
}
Expand Down
42 changes: 42 additions & 0 deletions tests/entity/entities_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,48 @@ TEST_F(EntitiesTests, EntityLifecycle)
}
}

//==============================================================================
// Recycle Generation Overflow (destroy()-side guard)
//==============================================================================

#ifndef NDEBUG
TEST_F(EntitiesTests, RecycleGenerationOverflowIsGuarded)
{
mgr.clear();
entity e = mgr.create();

// Drive this one id's generation up to MAX_GENERATIONS by repeatedly recycling it: as the
// only entity in the recycle stack, each destroy()/create() pair recycles the same id (LIFO
// via m_recycle_ids.back()/pop_back()).
for (std::uint16_t gen = 0; gen < entity::MAX_GENERATIONS; ++gen)
{
mgr.destroy(e);
e = mgr.create();
}

EXPECT_DEATH(mgr.destroy(e), "id's generation reached the maximum");
}
#else
TEST_F(EntitiesTests, RecycleGenerationOverflowRetiresId)
{
mgr.clear();
entity e = mgr.create();
std::uint32_t id = e.id();

for (std::uint16_t gen = 0; gen < entity::MAX_GENERATIONS; ++gen)
{
mgr.destroy(e);
e = mgr.create();
}

mgr.destroy(e);

// Id is permanently retired - never handed out again by a later create() call.
for (int i = 0; i < 100; ++i)
EXPECT_NE(mgr.create().id(), id);
}
#endif

//==============================================================================
// Move Semantics
//==============================================================================
Expand Down
Loading