diff --git a/tests/zecsy.cpp b/tests/zecsy.cpp index 2eddd4c..497b145 100644 --- a/tests/zecsy.cpp +++ b/tests/zecsy.cpp @@ -1,5 +1,4 @@ #include <catch2/catch_test_macros.hpp> -#include <string> #define CATCH_CONFIG_MAIN #include <catch2/catch_all.hpp> @@ -74,9 +73,9 @@ TEST_CASE("Attach a simple component to an entity and verify it is correctly " REQUIRE(w.has<ChoosenOne>(e2)); } -struct Name +struct Comp { - std::string value; + int v = 0; }; TEST_CASE("Retrieve a component from an entity and verify its data matches " @@ -85,13 +84,13 @@ TEST_CASE("Retrieve a component from an entity and verify its data matches " world w; auto e = w.make_entity(); - w.set(e, Name{"zecsy!"}); + w.set(e, Comp()); - REQUIRE(w.get<Name>(e).value == "zecsy!"); + REQUIRE(w.get<Comp>(e).v == 0); - w.get<Name>(e).value = "super-zecsy!"; + w.get<Comp>(e).v = 77; - REQUIRE(w.get<Name>(e).value == "super-zecsy!"); + REQUIRE(w.get<Comp>(e).v == 77); } TEST_CASE( @@ -161,15 +160,15 @@ TEST_CASE("Attach multiple components to an entity and verify all are " world w; auto e = w.make_entity(); - w.set(e, ChoosenOne{}, Name{"zecsy"}); + w.set(e, ChoosenOne{}, Comp{}); - REQUIRE(w.has<ChoosenOne, Name>(e)); + REQUIRE(w.has<ChoosenOne, Comp>(e)); - w.remove<ChoosenOne, Name>(e); + w.remove<ChoosenOne, Comp>(e); - REQUIRE_FALSE(w.has<ChoosenOne, Name>(e)); + REQUIRE_FALSE(w.has<ChoosenOne, Comp>(e)); REQUIRE_FALSE(w.has<ChoosenOne>(e)); - REQUIRE_FALSE(w.has<Name>(e)); + REQUIRE_FALSE(w.has<Comp>(e)); } TEST_CASE("Create a simple system that processes entities with a specific " diff --git a/zecsy.hpp b/zecsy.hpp index 34f5216..4d4a467 100644 --- a/zecsy.hpp +++ b/zecsy.hpp @@ -6,13 +6,33 @@ #include <functional> #include <set> #include <stdexcept> +#include <type_traits> #include <unordered_map> +#include <variant> #include <vector> +#include <concepts> namespace zecsy { using entity_id = uint64_t; + /* + * Actually, not a pure POD. Gotta figure out a better name + */ + template<typename... T> + concept Component = [] + { + static_assert((std::is_default_constructible_v<T> && ...), + "Should have a default constructor"); + static_assert((std::is_trivially_copyable_v<T> && ...), + "Should be trivially copyable"); + static_assert((std::is_trivially_destructible_v<T> && ...), + "Should be trivially destructible"); + static_assert((std::is_standard_layout_v<T> && ...), + "Should have standard layout"); + return true; + }(); + /* * Using std::set for entities_set to maintain sorted order, which can * improve cache locality during queries and iterations. @@ -22,32 +42,32 @@ namespace zecsy class component_storage final { public: - template<typename T> + template<Component T> bool has(entity_id e) const; - template<typename First, typename Second, typename... Rest> + template<Component First, Component Second, Component... Rest> bool has(entity_id e) const; - template<typename T> + template<Component T> T& get(entity_id e); - template<typename T> + template<Component T> void set(entity_id e); - template<typename T> + template<Component T> void set(entity_id e, const T& comp); - template<typename First, typename Second, typename... Rest> + template<Component First, Component Second, Component... Rest> void set(entity_id e); - template<typename First, typename Second, typename... Rest> + template<Component First, Component Second, Component... Rest> void set(entity_id e, const First& comp0, const Second& comp1, const Rest&... rest_comps); - template<typename T> + template<Component T> void remove(entity_id e); - template<typename First, typename Second, typename... Rest> + template<Component First, Component Second, Component... Rest> void remove(entity_id e); private: @@ -75,7 +95,7 @@ namespace zecsy inline component_storage::comp_id component_storage::next_component_id = 0; - template<typename T> + template<Component T> inline bool component_storage::has(entity_id e) const { auto id = get_component_id<T>(); @@ -86,7 +106,7 @@ namespace zecsy return false; } - template<typename T> + template<Component T> inline T& component_storage::get(entity_id e) { auto id = get_component_id<T>(); @@ -101,7 +121,7 @@ namespace zecsy return *reinterpret_cast<T*>(&pool.data[index * sizeof(T)]); } - template<typename T> + template<Component T> inline void component_storage::set(entity_id e, const T& comp) { auto id = get_component_id<T>(); @@ -124,13 +144,13 @@ namespace zecsy pool.index_to_entity[index] = e; } - template<typename T> + template<Component T> inline void component_storage::set(entity_id e) { set(e, T{}); } - template<typename T> + template<Component T> inline void component_storage::remove(entity_id e) { auto id = get_component_id<T>(); @@ -153,13 +173,13 @@ namespace zecsy pool.index_to_entity.erase(index); } - template<typename First, typename Second, typename... Rest> + template<Component First, Component Second, Component... Rest> inline bool component_storage::has(entity_id e) const { return has<First>(e) && has<Second>(e) && (has<Rest>(e) && ...); } - template<typename First, typename Second, typename... Rest> + template<Component First, Component Second, Component... Rest> inline void component_storage::set(entity_id e) { set(e, First{}); @@ -167,7 +187,7 @@ namespace zecsy (set(e, Rest{}), ...); } - template<typename First, typename Second, typename... Rest> + template<Component First, Component Second, Component... Rest> inline void component_storage::set(entity_id e, const First& comp0, const Second& comp1, const Rest&... rest_comps) @@ -177,7 +197,7 @@ namespace zecsy (set(e, rest_comps), ...); } - template<typename First, typename Second, typename... Rest> + template<Component First, Component Second, Component... Rest> inline void component_storage::remove(entity_id e) { remove<First>(e); @@ -193,7 +213,6 @@ namespace zecsy void add_system(int freq, auto&& func); void update(float dt); - private: struct system_handler { @@ -238,24 +257,23 @@ namespace zecsy void destroy_entity(entity_id e); bool is_alive(entity_id e) const; - template<typename... T> + template<Component... T> bool has(entity_id e) const; - template<typename T> + template<Component T> T& get(entity_id e); - template<typename... T> + template<Component... T> void set(entity_id e); - template<typename... T> + template<Component... T> void set(entity_id e, const T&... comps); - template<typename... T> + template<Component... T> void remove(entity_id e); - template<typename... T> + template<Component... T> void query(auto&& system); - private: entities_set alive_entities; entity_id entity_counter = 0; @@ -279,37 +297,37 @@ namespace zecsy return alive_entities.contains(e); } - template<typename... T> + template<Component... T> inline bool world::has(entity_id e) const { return storage.has<T...>(e); } - template<typename T> + template<Component T> inline T& world::get(entity_id e) { return storage.get<T>(e); } - template<typename... T> + template<Component... T> inline void world::set(entity_id e) { storage.set<T...>(e); } - template<typename... T> + template<Component... T> inline void world::set(entity_id e, const T&... comps) { storage.set(e, comps...); } - template<typename... T> + template<Component... T> inline void world::remove(entity_id e) { storage.remove<T...>(e); } - template<typename... T> + template<Component... T> inline void world::query(auto&& system) { for(auto e: alive_entities)