Compare commits
	
		
			No commits in common. "219af9d803b6e0f74aed030d8e14c20b7941bb84" and "72f635400a2022b2fc57ac5f1b159565891929ad" have entirely different histories.
		
	
	
		
			219af9d803
			...
			72f635400a
		
	
		
					 3 changed files with 40 additions and 452 deletions
				
			
		| 
						 | 
				
			
			@ -2,14 +2,6 @@ cmake_minimum_required(VERSION 3.22.0)
 | 
			
		|||
 | 
			
		||||
set(PROJECT_NAME zecsy)
 | 
			
		||||
 | 
			
		||||
if(NOT CMAKE_BUILD_TYPE)
 | 
			
		||||
  set(CMAKE_BUILD_TYPE Release)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
set(CMAKE_CXX_FLAGS "-Wall -Wextra")
 | 
			
		||||
set(CMAKE_CXX_FLAGS_DEBUG "-g")
 | 
			
		||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
 | 
			
		||||
 | 
			
		||||
project(${PROJECT_NAME})
 | 
			
		||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										458
									
								
								tests/zecsy.cpp
									
									
									
									
									
								
							
							
						
						
									
										458
									
								
								tests/zecsy.cpp
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -7,7 +7,7 @@
 | 
			
		|||
 | 
			
		||||
using namespace zecsy;
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Create a single entity and verify its existence", "[test]")
 | 
			
		||||
TEST_CASE("Create a single entity and verify its existence")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -16,8 +16,7 @@ TEST_CASE("Create a single entity and verify its existence", "[test]")
 | 
			
		|||
    REQUIRE(w.is_alive(e));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Destroy an entity and ensure it no longer exists in the world",
 | 
			
		||||
          "[test]")
 | 
			
		||||
TEST_CASE("Destroy an entity and ensure it no longer exists in the world")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +26,7 @@ TEST_CASE("Destroy an entity and ensure it no longer exists in the world",
 | 
			
		|||
    REQUIRE_FALSE(w.is_alive(e));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Entity #0 should be reserved and never used", "[test]")
 | 
			
		||||
TEST_CASE("Entity #0 should be reserved and never used")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -41,8 +40,7 @@ struct ChoosenOne
 | 
			
		|||
{
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Entity shouldn't have a component that wasn't attached to it",
 | 
			
		||||
          "[test]")
 | 
			
		||||
TEST_CASE("Entity shouldn't have a component that wasn't attached to it")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +49,7 @@ TEST_CASE("Entity shouldn't have a component that wasn't attached to it",
 | 
			
		|||
    REQUIRE_FALSE(w.has<ChoosenOne>(e));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Attempt of getting non-owned component should throw", "[test]")
 | 
			
		||||
TEST_CASE("Attempt of getting non-owned component should throw")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -61,8 +59,7 @@ TEST_CASE("Attempt of getting non-owned component should throw", "[test]")
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Attach a simple component to an entity and verify it is correctly "
 | 
			
		||||
          "associated",
 | 
			
		||||
          "[test]")
 | 
			
		||||
          "associated")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -83,8 +80,7 @@ struct Comp
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Retrieve a component from an entity and verify its data matches "
 | 
			
		||||
          "what was set",
 | 
			
		||||
          "[test]")
 | 
			
		||||
          "what was set")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -99,8 +95,7 @@ TEST_CASE("Retrieve a component from an entity and verify its data matches "
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE(
 | 
			
		||||
    "Remove a component from an entity and verify it is no longer attached",
 | 
			
		||||
    "[test]")
 | 
			
		||||
    "Remove a component from an entity and verify it is no longer attached")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -116,7 +111,7 @@ TEST_CASE(
 | 
			
		|||
    REQUIRE_FALSE(w.has<ChoosenOne>(e));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Addresses of removed components should be reused", "[test]")
 | 
			
		||||
TEST_CASE("Addresses of removed components should be reused")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
    std::vector<entity_id> entities;
 | 
			
		||||
| 
						 | 
				
			
			@ -161,8 +156,7 @@ TEST_CASE("Addresses of removed components should be reused", "[test]")
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Attach multiple components to an entity and verify all are "
 | 
			
		||||
          "correctly stored and retrievable",
 | 
			
		||||
          "[test]")
 | 
			
		||||
          "correctly stored and retrievable")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -179,8 +173,7 @@ TEST_CASE("Attach multiple components to an entity and verify all are "
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Create a simple system that processes entities with a specific "
 | 
			
		||||
          "component and verify it executes correctly",
 | 
			
		||||
          "[test]")
 | 
			
		||||
          "component and verify it executes correctly")
 | 
			
		||||
{
 | 
			
		||||
    struct Component
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -207,8 +200,7 @@ TEST_CASE("Create a simple system that processes entities with a specific "
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Test a systems ability to query and process only entities with a "
 | 
			
		||||
          "specific combination of components",
 | 
			
		||||
          "[test]")
 | 
			
		||||
          "specific combination of components")
 | 
			
		||||
{
 | 
			
		||||
    struct C0
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -234,8 +226,7 @@ TEST_CASE("Test a systems ability to query and process only entities with a "
 | 
			
		|||
    REQUIRE(w.get<C0>(e0).value == 0);
 | 
			
		||||
    REQUIRE(w.get<C1>(e0).value == 10);
 | 
			
		||||
 | 
			
		||||
    w.query<C0, C1>(
 | 
			
		||||
        [e0](entity_id e, C0& c0, C1& c1)
 | 
			
		||||
    w.query<C0, C1>([e0](entity_id e, C0& c0, C1& c1)
 | 
			
		||||
    {
 | 
			
		||||
        REQUIRE(e == e0);
 | 
			
		||||
        c0.value++;
 | 
			
		||||
| 
						 | 
				
			
			@ -252,7 +243,7 @@ TEST_CASE("Test a systems ability to query and process only entities with a "
 | 
			
		|||
    REQUIRE_FALSE(w.has<C0>(e2));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Systems execute at correct frequencies", "[test]")
 | 
			
		||||
TEST_CASE("Systems execute at correct frequencies")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
    system_scheduler scheduler;
 | 
			
		||||
| 
						 | 
				
			
			@ -277,7 +268,7 @@ TEST_CASE("Systems execute at correct frequencies", "[test]")
 | 
			
		|||
    REQUIRE(slow_count == 2);   // 1 Hz system should execute 1 time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Systems handle zero-frequency gracefully", "[test]")
 | 
			
		||||
TEST_CASE("Systems handle zero-frequency gracefully")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
    system_scheduler scheduler;
 | 
			
		||||
| 
						 | 
				
			
			@ -297,7 +288,7 @@ TEST_CASE("Systems handle zero-frequency gracefully", "[test]")
 | 
			
		|||
    REQUIRE(zero_count == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Systems handle varying update rates", "[test]")
 | 
			
		||||
TEST_CASE("Systems handle varying update rates")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
    system_scheduler scheduler;
 | 
			
		||||
| 
						 | 
				
			
			@ -317,7 +308,7 @@ TEST_CASE("Systems handle varying update rates", "[test]")
 | 
			
		|||
    REQUIRE(varying_count == 10);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Systems handle large time steps", "[test]")
 | 
			
		||||
TEST_CASE("Systems handle large time steps")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
    system_scheduler scheduler;
 | 
			
		||||
| 
						 | 
				
			
			@ -334,7 +325,7 @@ TEST_CASE("Systems handle large time steps", "[test]")
 | 
			
		|||
    REQUIRE(large_step_count == 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Systems handle multiple frequencies", "[test]")
 | 
			
		||||
TEST_CASE("Systems handle multiple frequencies")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
    system_scheduler scheduler;
 | 
			
		||||
| 
						 | 
				
			
			@ -360,7 +351,7 @@ TEST_CASE("Systems handle multiple frequencies", "[test]")
 | 
			
		|||
    REQUIRE(slow_count == 1);    // 1 Hz system
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Systems handle fractional frequencies", "[test]")
 | 
			
		||||
TEST_CASE("Systems handle fractional frequencies")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
    system_scheduler scheduler;
 | 
			
		||||
| 
						 | 
				
			
			@ -381,7 +372,7 @@ TEST_CASE("Systems handle fractional frequencies", "[test]")
 | 
			
		|||
    REQUIRE(fractional_count == 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Systems handle zero delta time", "[test]")
 | 
			
		||||
TEST_CASE("Systems handle zero delta time")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
    system_scheduler scheduler;
 | 
			
		||||
| 
						 | 
				
			
			@ -398,7 +389,7 @@ TEST_CASE("Systems handle zero delta time", "[test]")
 | 
			
		|||
    REQUIRE(zero_dt_count == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Systems handle negative delta time", "[test]")
 | 
			
		||||
TEST_CASE("Systems handle negative delta time")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
    system_scheduler scheduler;
 | 
			
		||||
| 
						 | 
				
			
			@ -419,7 +410,7 @@ TEST_CASE("Systems handle negative delta time", "[test]")
 | 
			
		|||
    REQUIRE(count == 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Entity count tracking", "[test]")
 | 
			
		||||
TEST_CASE("Entity count tracking")
 | 
			
		||||
{
 | 
			
		||||
    world w;
 | 
			
		||||
    REQUIRE(w.entity_count() == 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -432,7 +423,7 @@ TEST_CASE("Entity count tracking", "[test]")
 | 
			
		|||
    REQUIRE(w.entity_count() == 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Component counting mechanisms", "[test]")
 | 
			
		||||
TEST_CASE("Component counting mechanisms")
 | 
			
		||||
{
 | 
			
		||||
    struct Health
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -463,7 +454,7 @@ TEST_CASE("Component counting mechanisms", "[test]")
 | 
			
		|||
    REQUIRE(w.total_component_count() == 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Archetype signature management", "[test]")
 | 
			
		||||
TEST_CASE("Archetype signature management")
 | 
			
		||||
{
 | 
			
		||||
    struct A
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -518,7 +509,7 @@ TEST_CASE("Archetype signature management", "[test]")
 | 
			
		|||
    REQUIRE(w.archetype_count() == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Component distribution across archetypes", "[test]")
 | 
			
		||||
TEST_CASE("Component distribution across archetypes")
 | 
			
		||||
{
 | 
			
		||||
    struct A
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -556,7 +547,7 @@ TEST_CASE("Component distribution across archetypes", "[test]")
 | 
			
		|||
    REQUIRE(w.archetype_count() == 3); //<A>, <A, B>, <B>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Entity inspection", "[test]")
 | 
			
		||||
TEST_CASE("Entity inspection")
 | 
			
		||||
{
 | 
			
		||||
    struct Transform
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -581,400 +572,3 @@ TEST_CASE("Entity inspection", "[test]")
 | 
			
		|||
    w.remove<Transform>(e);
 | 
			
		||||
    REQUIRE(w.components_in_entity(e) == 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace
 | 
			
		||||
{
 | 
			
		||||
    // Benchmark components
 | 
			
		||||
    struct Position
 | 
			
		||||
    {
 | 
			
		||||
        float x, y;
 | 
			
		||||
    };
 | 
			
		||||
    struct Velocity
 | 
			
		||||
    {
 | 
			
		||||
        float dx, dy;
 | 
			
		||||
    };
 | 
			
		||||
    struct Health
 | 
			
		||||
    {
 | 
			
		||||
        int value;
 | 
			
		||||
    };
 | 
			
		||||
    struct BigData
 | 
			
		||||
    {
 | 
			
		||||
        char buffer[4096];
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Benchmark entity counts
 | 
			
		||||
    constexpr int SMALL = 1'000;
 | 
			
		||||
    constexpr int MEDIUM = 5'000;
 | 
			
		||||
    constexpr int LARGE = 10'000;
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Core operations benchmarks", "[benchmark]")
 | 
			
		||||
{
 | 
			
		||||
    BENCHMARK_ADVANCED("Create entities [1000]")(
 | 
			
		||||
        Catch::Benchmark::Chronometer meter)
 | 
			
		||||
    {
 | 
			
		||||
        meter.measure(
 | 
			
		||||
            [&]
 | 
			
		||||
            {
 | 
			
		||||
                world w;
 | 
			
		||||
                for(int i = 0; i < SMALL; ++i)
 | 
			
		||||
                {
 | 
			
		||||
                    w.make_entity();
 | 
			
		||||
                }
 | 
			
		||||
                return w.entity_count();
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    BENCHMARK_ADVANCED("Create entities [5000]")(
 | 
			
		||||
        Catch::Benchmark::Chronometer meter)
 | 
			
		||||
    {
 | 
			
		||||
        meter.measure(
 | 
			
		||||
            [&]
 | 
			
		||||
            {
 | 
			
		||||
                world w;
 | 
			
		||||
                for(int i = 0; i < MEDIUM; ++i)
 | 
			
		||||
                {
 | 
			
		||||
                    w.make_entity();
 | 
			
		||||
                }
 | 
			
		||||
                return w.entity_count();
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    BENCHMARK_ADVANCED("Create entities [10000]")(
 | 
			
		||||
        Catch::Benchmark::Chronometer meter)
 | 
			
		||||
    {
 | 
			
		||||
        meter.measure(
 | 
			
		||||
            [&]
 | 
			
		||||
            {
 | 
			
		||||
                world w;
 | 
			
		||||
                for(int i = 0; i < LARGE; ++i)
 | 
			
		||||
                {
 | 
			
		||||
                    w.make_entity();
 | 
			
		||||
                }
 | 
			
		||||
                return w.entity_count();
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    BENCHMARK_ADVANCED("Create entities with components [1000]")(
 | 
			
		||||
        Catch::Benchmark::Chronometer meter)
 | 
			
		||||
    {
 | 
			
		||||
        meter.measure(
 | 
			
		||||
            [&]
 | 
			
		||||
            {
 | 
			
		||||
                world w;
 | 
			
		||||
                for(int i = 0; i < SMALL; ++i)
 | 
			
		||||
                {
 | 
			
		||||
                    auto e = w.make_entity();
 | 
			
		||||
                    w.set<Position>(e, {1.0f, 2.0f});
 | 
			
		||||
                    w.set<Velocity>(e, {3.0f, 4.0f});
 | 
			
		||||
                }
 | 
			
		||||
                return w.total_component_count();
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    BENCHMARK_ADVANCED("Create entities with components [5000]")(
 | 
			
		||||
        Catch::Benchmark::Chronometer meter)
 | 
			
		||||
    {
 | 
			
		||||
        meter.measure(
 | 
			
		||||
            [&]
 | 
			
		||||
            {
 | 
			
		||||
                world w;
 | 
			
		||||
                for(int i = 0; i < MEDIUM; ++i)
 | 
			
		||||
                {
 | 
			
		||||
                    auto e = w.make_entity();
 | 
			
		||||
                    w.set<Position>(e, {1.0f, 2.0f});
 | 
			
		||||
                    w.set<Velocity>(e, {3.0f, 4.0f});
 | 
			
		||||
                }
 | 
			
		||||
                return w.total_component_count();
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    BENCHMARK_ADVANCED("Create entities with components [10000]")(
 | 
			
		||||
        Catch::Benchmark::Chronometer meter)
 | 
			
		||||
    {
 | 
			
		||||
        meter.measure(
 | 
			
		||||
            [&]
 | 
			
		||||
            {
 | 
			
		||||
                world w;
 | 
			
		||||
                for(int i = 0; i < LARGE; ++i)
 | 
			
		||||
                {
 | 
			
		||||
                    auto e = w.make_entity();
 | 
			
		||||
                    w.set<Position>(e, {1.0f, 2.0f});
 | 
			
		||||
                    w.set<Velocity>(e, {3.0f, 4.0f});
 | 
			
		||||
                }
 | 
			
		||||
                return w.total_component_count();
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Component operations benchmarks", "[benchmark]")
 | 
			
		||||
{
 | 
			
		||||
    BENCHMARK_ADVANCED("Add component to existing entities [1000]")(
 | 
			
		||||
        Catch::Benchmark::Chronometer meter)
 | 
			
		||||
    {
 | 
			
		||||
        world w;
 | 
			
		||||
        std::vector<entity_id> entities;
 | 
			
		||||
        for(int i = 0; i < SMALL; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            entities.push_back(w.make_entity());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        meter.measure(
 | 
			
		||||
            [&]
 | 
			
		||||
            {
 | 
			
		||||
                for(auto e: entities)
 | 
			
		||||
                {
 | 
			
		||||
                    w.set<Health>(e, {100});
 | 
			
		||||
                }
 | 
			
		||||
                return w.component_count<Health>();
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    BENCHMARK_ADVANCED("Add component to existing entities [5000]")(
 | 
			
		||||
        Catch::Benchmark::Chronometer meter)
 | 
			
		||||
    {
 | 
			
		||||
        world w;
 | 
			
		||||
        std::vector<entity_id> entities;
 | 
			
		||||
        for(int i = 0; i < MEDIUM; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            entities.push_back(w.make_entity());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        meter.measure(
 | 
			
		||||
            [&]
 | 
			
		||||
            {
 | 
			
		||||
                for(auto e: entities)
 | 
			
		||||
                {
 | 
			
		||||
                    w.set<Health>(e, {100});
 | 
			
		||||
                }
 | 
			
		||||
                return w.component_count<Health>();
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    BENCHMARK_ADVANCED("Add component to existing entities [10000]")(
 | 
			
		||||
        Catch::Benchmark::Chronometer meter)
 | 
			
		||||
    {
 | 
			
		||||
        world w;
 | 
			
		||||
        std::vector<entity_id> entities;
 | 
			
		||||
        for(int i = 0; i < LARGE; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            entities.push_back(w.make_entity());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        meter.measure(
 | 
			
		||||
            [&]
 | 
			
		||||
            {
 | 
			
		||||
                for(auto e: entities)
 | 
			
		||||
                {
 | 
			
		||||
                    w.set<Health>(e, {100});
 | 
			
		||||
                }
 | 
			
		||||
                return w.component_count<Health>();
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    BENCHMARK_ADVANCED("Remove component from entities [1000]")(
 | 
			
		||||
        Catch::Benchmark::Chronometer meter)
 | 
			
		||||
    {
 | 
			
		||||
        world w;
 | 
			
		||||
        std::vector<entity_id> entities;
 | 
			
		||||
        for(int i = 0; i < SMALL; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            auto e = w.make_entity();
 | 
			
		||||
            w.set<Health>(e, {100});
 | 
			
		||||
            entities.push_back(e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        meter.measure(
 | 
			
		||||
            [&]
 | 
			
		||||
            {
 | 
			
		||||
                for(auto e: entities)
 | 
			
		||||
                {
 | 
			
		||||
                    w.remove<Health>(e);
 | 
			
		||||
                }
 | 
			
		||||
                return w.component_count<Health>();
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    BENCHMARK_ADVANCED("Remove component from entities [5000]")(
 | 
			
		||||
        Catch::Benchmark::Chronometer meter)
 | 
			
		||||
    {
 | 
			
		||||
        world w;
 | 
			
		||||
        std::vector<entity_id> entities;
 | 
			
		||||
        for(int i = 0; i < MEDIUM; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            auto e = w.make_entity();
 | 
			
		||||
            w.set<Health>(e, {100});
 | 
			
		||||
            entities.push_back(e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        meter.measure(
 | 
			
		||||
            [&]
 | 
			
		||||
            {
 | 
			
		||||
                for(auto e: entities)
 | 
			
		||||
                {
 | 
			
		||||
                    w.remove<Health>(e);
 | 
			
		||||
                }
 | 
			
		||||
                return w.component_count<Health>();
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    BENCHMARK_ADVANCED("Remove component from entities [10000]")(
 | 
			
		||||
        Catch::Benchmark::Chronometer meter)
 | 
			
		||||
    {
 | 
			
		||||
        world w;
 | 
			
		||||
        std::vector<entity_id> entities;
 | 
			
		||||
        for(int i = 0; i < LARGE; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            auto e = w.make_entity();
 | 
			
		||||
            w.set<Health>(e, {100});
 | 
			
		||||
            entities.push_back(e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        meter.measure(
 | 
			
		||||
            [&]
 | 
			
		||||
            {
 | 
			
		||||
                for(auto e: entities)
 | 
			
		||||
                {
 | 
			
		||||
                    w.remove<Health>(e);
 | 
			
		||||
                }
 | 
			
		||||
                return w.component_count<Health>();
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Query performance benchmarks", "[benchmark]")
 | 
			
		||||
{
 | 
			
		||||
    BENCHMARK_ADVANCED("Dense query (90% match)")(
 | 
			
		||||
        Catch::Benchmark::Chronometer meter)
 | 
			
		||||
    {
 | 
			
		||||
        world w;
 | 
			
		||||
        for(int i = 0; i < LARGE; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            auto e = w.make_entity();
 | 
			
		||||
            w.set<Position>(e);
 | 
			
		||||
            if(i % 10 != 0)
 | 
			
		||||
                w.set<Velocity>(e); // 90% match
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        meter.measure(
 | 
			
		||||
            [&]
 | 
			
		||||
            {
 | 
			
		||||
                int count = 0;
 | 
			
		||||
                w.query<Position, Velocity>([&](auto...) { count++; });
 | 
			
		||||
                return count;
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    BENCHMARK_ADVANCED("Sparse query (10% match)")(
 | 
			
		||||
        Catch::Benchmark::Chronometer meter)
 | 
			
		||||
    {
 | 
			
		||||
        world w;
 | 
			
		||||
        for(int i = 0; i < LARGE; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            auto e = w.make_entity();
 | 
			
		||||
            w.set<Position>(e);
 | 
			
		||||
            if(i % 10 == 0)
 | 
			
		||||
                w.set<Velocity>(e); // 10% match
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        meter.measure(
 | 
			
		||||
            [&]
 | 
			
		||||
            {
 | 
			
		||||
                int count = 0;
 | 
			
		||||
                w.query<Position, Velocity>([&](auto...) { count++; });
 | 
			
		||||
                return count;
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Memory intensive benchmarks", "[benchmark]")
 | 
			
		||||
{
 | 
			
		||||
    BENCHMARK_ADVANCED("Large component allocation")(
 | 
			
		||||
        Catch::Benchmark::Chronometer meter)
 | 
			
		||||
    {
 | 
			
		||||
        meter.measure(
 | 
			
		||||
            [&]
 | 
			
		||||
            {
 | 
			
		||||
                world w;
 | 
			
		||||
                for(int i = 0; i < SMALL; ++i)
 | 
			
		||||
                {
 | 
			
		||||
                    auto e = w.make_entity();
 | 
			
		||||
                    w.set<BigData>(e);
 | 
			
		||||
                }
 | 
			
		||||
                return w.total_component_count();
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    BENCHMARK_ADVANCED("Component memory reuse")(
 | 
			
		||||
        Catch::Benchmark::Chronometer meter)
 | 
			
		||||
    {
 | 
			
		||||
        world w;
 | 
			
		||||
        std::vector<entity_id> entities;
 | 
			
		||||
        for(int i = 0; i < SMALL; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            auto e = w.make_entity();
 | 
			
		||||
            w.set<BigData>(e);
 | 
			
		||||
            entities.push_back(e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        meter.measure(
 | 
			
		||||
            [&]
 | 
			
		||||
            {
 | 
			
		||||
                // Remove and re-add components
 | 
			
		||||
                for(auto e: entities)
 | 
			
		||||
                {
 | 
			
		||||
                    w.remove<BigData>(e);
 | 
			
		||||
                    w.set<BigData>(e);
 | 
			
		||||
                }
 | 
			
		||||
                return w.component_count<BigData>();
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Archetype transition benchmarks", "[benchmark]")
 | 
			
		||||
{
 | 
			
		||||
    BENCHMARK_ADVANCED("Single component addition")(
 | 
			
		||||
        Catch::Benchmark::Chronometer meter)
 | 
			
		||||
    {
 | 
			
		||||
        world w;
 | 
			
		||||
        std::vector<entity_id> entities;
 | 
			
		||||
        for(int i = 0; i < MEDIUM; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            entities.push_back(w.make_entity());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        meter.measure(
 | 
			
		||||
            [&]
 | 
			
		||||
            {
 | 
			
		||||
                for(auto e: entities)
 | 
			
		||||
                {
 | 
			
		||||
                    w.set<Health>(e);
 | 
			
		||||
                }
 | 
			
		||||
                return w.archetype_count();
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    BENCHMARK_ADVANCED("Multi-component transition")(
 | 
			
		||||
        Catch::Benchmark::Chronometer meter)
 | 
			
		||||
    {
 | 
			
		||||
        world w;
 | 
			
		||||
        std::vector<entity_id> entities;
 | 
			
		||||
        for(int i = 0; i < MEDIUM; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            auto e = w.make_entity();
 | 
			
		||||
            w.set<Position>(e);
 | 
			
		||||
            entities.push_back(e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        meter.measure(
 | 
			
		||||
            [&]
 | 
			
		||||
            {
 | 
			
		||||
                for(auto e: entities)
 | 
			
		||||
                {
 | 
			
		||||
                    w.set<Velocity>(e);
 | 
			
		||||
                    w.set<Health>(e);
 | 
			
		||||
                }
 | 
			
		||||
                return w.archetype_count();
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										16
									
								
								zecsy.hpp
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								zecsy.hpp
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -97,7 +97,7 @@ namespace zecsy
 | 
			
		|||
        std::unordered_map<comp_id, component_pool> pools;
 | 
			
		||||
 | 
			
		||||
        using archetype_signature = std::vector<comp_id>;
 | 
			
		||||
        using entity_group = std::set<entity_id>;
 | 
			
		||||
        using entity_group = std::vector<entity_id>;
 | 
			
		||||
 | 
			
		||||
        struct archetype_hash
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -186,7 +186,7 @@ namespace zecsy
 | 
			
		|||
 | 
			
		||||
        std::vector<comp_id> key;
 | 
			
		||||
        auto& group = archetypes[key];
 | 
			
		||||
        group.emplace(id);
 | 
			
		||||
        group.emplace_back(id);
 | 
			
		||||
 | 
			
		||||
        return id;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -199,7 +199,7 @@ namespace zecsy
 | 
			
		|||
        std::vector<comp_id> key(comp_set.begin(), comp_set.end());
 | 
			
		||||
 | 
			
		||||
        auto& group = archetypes[key];
 | 
			
		||||
        group.erase(e);
 | 
			
		||||
        group.erase(std::remove(group.begin(), group.end(), e), group.end());
 | 
			
		||||
 | 
			
		||||
        if(archetypes[key].empty())
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -279,7 +279,8 @@ namespace zecsy
 | 
			
		|||
            std::vector<comp_id> old_key(old_set.begin(), old_set.end());
 | 
			
		||||
 | 
			
		||||
            auto& group = archetypes[old_key];
 | 
			
		||||
            group.erase(e);
 | 
			
		||||
            group.erase(std::remove(group.begin(), group.end(), e),
 | 
			
		||||
                        group.end());
 | 
			
		||||
 | 
			
		||||
            if(archetypes[old_key].empty())
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -287,7 +288,7 @@ namespace zecsy
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            std::vector<comp_id> new_key(comp_set.begin(), comp_set.end());
 | 
			
		||||
            archetypes[new_key].emplace(e);
 | 
			
		||||
            archetypes[new_key].emplace_back(e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -310,12 +311,13 @@ namespace zecsy
 | 
			
		|||
            std::sort(old_key.begin(), old_key.end());
 | 
			
		||||
 | 
			
		||||
            auto& old_group = archetypes[old_key];
 | 
			
		||||
            old_group.erase(e);
 | 
			
		||||
            old_group.erase(std::remove(old_group.begin(), old_group.end(), e),
 | 
			
		||||
                            old_group.end());
 | 
			
		||||
 | 
			
		||||
            std::vector<comp_id> new_key(comp_set.begin(), comp_set.end());
 | 
			
		||||
            std::sort(new_key.begin(), new_key.end());
 | 
			
		||||
 | 
			
		||||
            archetypes[new_key].emplace(e);
 | 
			
		||||
            archetypes[new_key].emplace_back(e);
 | 
			
		||||
 | 
			
		||||
            if(archetypes[old_key].empty())
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue