From 52d6b7c4c3dd8dd0d7615aea0ba0c2ce45ada00d Mon Sep 17 00:00:00 2001
From: NukeBird <nukebird.dev@gmail.com>
Date: Wed, 19 Feb 2025 22:50:21 +0300
Subject: [PATCH] Combine world and component_storage

---
 zecsy.hpp | 306 ++++++++++++++++++++++--------------------------------
 1 file changed, 127 insertions(+), 179 deletions(-)

diff --git a/zecsy.hpp b/zecsy.hpp
index cf1aa29..4c2279c 100644
--- a/zecsy.hpp
+++ b/zecsy.hpp
@@ -35,166 +35,6 @@ namespace zecsy
      */
     using entities_set = std::set<entity_id>;
 
-    class component_storage final
-    {
-    public:
-        template<Component T>
-        bool has(entity_id e) const;
-
-        template<Component First, Component Second, Component... Rest>
-        bool has(entity_id e) const;
-
-        template<Component T>
-        T& get(entity_id e);
-
-        template<Component T>
-        void set(entity_id e);
-
-        template<Component T>
-        void set(entity_id e, const T& comp);
-
-        template<Component First, Component Second, Component... Rest>
-        void set(entity_id e);
-
-        template<Component First, Component Second, Component... Rest>
-        void set(entity_id e, const First& comp0, const Second& comp1,
-                 const Rest&... rest_comps);
-
-        template<Component T>
-        void remove(entity_id e);
-
-        template<Component First, Component Second, Component... Rest>
-        void remove(entity_id e);
-
-    private:
-        using comp_id = size_t;
-
-        struct component_pool
-        {
-            std::vector<uint8_t> data;
-            std::vector<size_t> free_list; // Reusable indices
-            std::unordered_map<entity_id, size_t> entity_to_index;
-            std::unordered_map<size_t, entity_id> index_to_entity;
-        };
-
-        std::unordered_map<comp_id, component_pool> pools;
-
-        template<typename T>
-        static comp_id get_component_id()
-        {
-            static comp_id id = next_component_id++;
-            return id;
-        }
-
-        static comp_id next_component_id;
-    };
-
-    inline component_storage::comp_id component_storage::next_component_id = 0;
-
-    template<Component T>
-    inline bool component_storage::has(entity_id e) const
-    {
-        auto id = get_component_id<T>();
-        if(pools.contains(id))
-        {
-            return pools.at(id).entity_to_index.contains(e);
-        }
-        return false;
-    }
-
-    template<Component T>
-    inline T& component_storage::get(entity_id e)
-    {
-        auto id = get_component_id<T>();
-        if(!has<T>(e))
-        {
-            throw std::runtime_error(
-                std::format("Entity #{} doesn't have {}", e, typeid(T).name()));
-        }
-
-        auto& pool = pools.at(id);
-        auto index = pool.entity_to_index.at(e);
-        return *reinterpret_cast<T*>(&pool.data[index * sizeof(T)]);
-    }
-
-    template<Component T>
-    inline void component_storage::set(entity_id e, const T& comp)
-    {
-        auto id = get_component_id<T>();
-        auto& pool = pools[id];
-
-        size_t index;
-        if(!pool.free_list.empty())
-        {
-            index = pool.free_list.back();
-            pool.free_list.pop_back();
-        }
-        else
-        {
-            index = pool.data.size() / sizeof(T);
-            pool.data.resize(pool.data.size() + sizeof(T));
-        }
-
-        new(&pool.data[index * sizeof(T)]) T(comp);
-        pool.entity_to_index[e] = index;
-        pool.index_to_entity[index] = e;
-    }
-
-    template<Component T>
-    inline void component_storage::set(entity_id e)
-    {
-        set(e, T{});
-    }
-
-    template<Component T>
-    inline void component_storage::remove(entity_id e)
-    {
-        auto id = get_component_id<T>();
-        if(!has<T>(e))
-        {
-            return;
-        }
-
-        auto& pool = pools[id];
-        auto index = pool.entity_to_index[e];
-
-        pool.free_list.push_back(index);
-        pool.entity_to_index.erase(e);
-        pool.index_to_entity.erase(index);
-    }
-
-    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<Component First, Component Second, Component... Rest>
-    inline void component_storage::set(entity_id e)
-    {
-        set(e, First{});
-        set(e, Second{});
-        (set(e, 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)
-    {
-        set(e, comp0);
-        set(e, comp1);
-        (set(e, rest_comps), ...);
-    }
-
-    template<Component First, Component Second, Component... Rest>
-    inline void component_storage::remove(entity_id e)
-    {
-        remove<First>(e);
-        remove<Second>(e);
-        (remove<Rest>(e), ...);
-    }
-
     class system_scheduler final
     {
     public:
@@ -248,19 +88,32 @@ namespace zecsy
         void destroy_entity(entity_id e);
         bool is_alive(entity_id e) const;
 
-        template<Component... T>
+        template<Component T>
+        bool has(entity_id e) const;
+
+        template<Component First, Component Second, Component... Rest>
         bool has(entity_id e) const;
 
         template<Component T>
         T& get(entity_id e);
 
-        template<Component... T>
+        template<Component T>
         void set(entity_id e);
 
-        template<Component... T>
-        void set(entity_id e, const T&... comps);
+        template<Component T>
+        void set(entity_id e, const T& comp);
 
-        template<Component... T>
+        template<Component First, Component Second, Component... Rest>
+        void set(entity_id e);
+
+        template<Component First, Component Second, Component... Rest>
+        void set(entity_id e, const First& comp0, const Second& comp1,
+                 const Rest&... rest_comps);
+
+        template<Component T>
+        void remove(entity_id e);
+
+        template<Component First, Component Second, Component... Rest>
         void remove(entity_id e);
 
         template<Component... T>
@@ -269,9 +122,31 @@ namespace zecsy
     private:
         entities_set alive_entities;
         entity_id entity_counter = 0;
-        component_storage storage;
+
+        using comp_id = size_t;
+
+        struct component_pool
+        {
+            std::vector<uint8_t> data;
+            std::vector<size_t> free_list; // Reusable indices
+            std::unordered_map<entity_id, size_t> entity_to_index;
+            std::unordered_map<size_t, entity_id> index_to_entity;
+        };
+
+        std::unordered_map<comp_id, component_pool> pools;
+
+        template<typename T>
+        static comp_id get_component_id()
+        {
+            static comp_id id = next_component_id++;
+            return id;
+        }
+
+        static comp_id next_component_id;
     };
 
+    inline world::comp_id world::next_component_id = 0;
+
     inline entity_id world::make_entity()
     {
         auto id = ++entity_counter;
@@ -289,34 +164,107 @@ namespace zecsy
         return alive_entities.contains(e);
     }
 
-    template<Component... T>
+    template<Component T>
     inline bool world::has(entity_id e) const
     {
-        return storage.has<T...>(e);
+        auto id = get_component_id<T>();
+        if(pools.contains(id))
+        {
+            return pools.at(id).entity_to_index.contains(e);
+        }
+        return false;
     }
 
     template<Component T>
     inline T& world::get(entity_id e)
     {
-        return storage.get<T>(e);
+        auto id = get_component_id<T>();
+        if(!has<T>(e))
+        {
+            throw std::runtime_error(
+                std::format("Entity #{} doesn't have {}", e, typeid(T).name()));
+        }
+
+        auto& pool = pools.at(id);
+        auto index = pool.entity_to_index.at(e);
+        return *reinterpret_cast<T*>(&pool.data[index * sizeof(T)]);
     }
 
-    template<Component... T>
+    template<Component T>
+    inline void world::set(entity_id e, const T& comp)
+    {
+        auto id = get_component_id<T>();
+        auto& pool = pools[id];
+
+        size_t index;
+        if(!pool.free_list.empty())
+        {
+            index = pool.free_list.back();
+            pool.free_list.pop_back();
+        }
+        else
+        {
+            index = pool.data.size() / sizeof(T);
+            pool.data.resize(pool.data.size() + sizeof(T));
+        }
+
+        new(&pool.data[index * sizeof(T)]) T(comp);
+        pool.entity_to_index[e] = index;
+        pool.index_to_entity[index] = e;
+    }
+
+    template<Component T>
     inline void world::set(entity_id e)
     {
-        storage.set<T...>(e);
+        set(e, T{});
     }
 
-    template<Component... T>
-    inline void world::set(entity_id e, const T&... comps)
-    {
-        storage.set(e, comps...);
-    }
-
-    template<Component... T>
+    template<Component T>
     inline void world::remove(entity_id e)
     {
-        storage.remove<T...>(e);
+        auto id = get_component_id<T>();
+        if(!has<T>(e))
+        {
+            return;
+        }
+
+        auto& pool = pools[id];
+        auto index = pool.entity_to_index[e];
+
+        pool.free_list.push_back(index);
+        pool.entity_to_index.erase(e);
+        pool.index_to_entity.erase(index);
+    }
+
+    template<Component First, Component Second, Component... Rest>
+    inline bool world::has(entity_id e) const
+    {
+        return has<First>(e) && has<Second>(e) && (has<Rest>(e) && ...);
+    }
+
+    template<Component First, Component Second, Component... Rest>
+    inline void world::set(entity_id e)
+    {
+        set(e, First{});
+        set(e, Second{});
+        (set(e, Rest{}), ...);
+    }
+
+    template<Component First, Component Second, Component... Rest>
+    inline void world::set(entity_id e, const First& comp0, const Second& comp1,
+                           const Rest&... rest_comps)
+    {
+        set(e, comp0);
+        set(e, comp1);
+        (set(e, rest_comps), ...);
+    }
+
+    template<Component First, Component Second, Component... Rest>
+    inline void world::remove(entity_id e)
+    {
+        remove<First>(e);
+        remove<Second>(e);
+        (remove<Rest>(e), ...);
     }
 
     template<Component... T>