LCOV - code coverage report
Current view: top level - include/ecs - ComponentStorage.hpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 90.0 % 40 36
Test Date: 2026-04-10 19:03:25 Functions: 87.2 % 47 41

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2025 aeml
       3              :  *
       4              :  * This program is free software: you can redistribute it and/or modify
       5              :  * it under the terms of the GNU General Public License as published by
       6              :  * the Free Software Foundation, either version 3 of the License, or
       7              :  * (at your option) any later version.
       8              :  *
       9              :  * This program is distributed in the hope that it will be useful,
      10              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12              :  * GNU General Public License for more details.
      13              :  *
      14              :  * You should have received a copy of the GNU General Public License
      15              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      16              :  */
      17              : 
      18              : #pragma once
      19              : 
      20              : #include <vector>
      21              : #include <unordered_map>
      22              : #include <utility>
      23              : 
      24              : // Forward declaration of EntityId to avoid circular include with World.hpp.
      25              : #include <cstdint>
      26              : namespace ecs { using EntityId = std::uint32_t; }
      27              : 
      28              : namespace ecs
      29              : {
      30              :     template <typename TComponent>
      31              :     class ComponentStorage
      32              :     {
      33              :     public:
      34        10876 :         TComponent& Add(EntityId id, const TComponent& component)
      35              :         {
      36        10876 :             if (m_entityToDense.find(id) != m_entityToDense.end())
      37              :             {
      38              :                 // Update existing
      39            0 :                 size_t index = m_entityToDense[id];
      40            0 :                 m_data[index] = component;
      41            0 :                 return m_data[index];
      42              :             }
      43              : 
      44        10876 :             size_t index = m_data.size();
      45        10876 :             m_data.push_back(component);
      46        10876 :             m_denseToEntity.push_back(id);
      47        10876 :             m_entityToDense[id] = index;
      48        10876 :             return m_data.back();
      49              :         }
      50              : 
      51     36038742 :         TComponent* Get(EntityId id)
      52              :         {
      53     36038742 :             auto it = m_entityToDense.find(id);
      54     36038742 :             return it != m_entityToDense.end() ? &m_data[it->second] : nullptr;
      55              :         }
      56              : 
      57              :         const TComponent* Get(EntityId id) const
      58              :         {
      59              :             auto it = m_entityToDense.find(id);
      60              :             return it != m_entityToDense.end() ? &m_data[it->second] : nullptr;
      61              :         }
      62              : 
      63            2 :         bool Remove(EntityId id)
      64              :         {
      65            2 :             auto it = m_entityToDense.find(id);
      66            2 :             if (it == m_entityToDense.end())
      67              :             {
      68            0 :                 return false;
      69              :             }
      70              : 
      71            2 :             const size_t index = it->second;
      72            2 :             const size_t lastIndex = m_data.size() - 1;
      73              : 
      74            2 :             if (index != lastIndex)
      75              :             {
      76            1 :                 m_data[index] = std::move(m_data[lastIndex]);
      77            1 :                 const EntityId movedId = m_denseToEntity[lastIndex];
      78            1 :                 m_denseToEntity[index] = movedId;
      79            1 :                 m_entityToDense[movedId] = index;
      80              :             }
      81              : 
      82            2 :             m_data.pop_back();
      83            2 :             m_denseToEntity.pop_back();
      84            2 :             m_entityToDense.erase(it);
      85            2 :             return true;
      86              :         }
      87              : 
      88              :         template <typename Fn>
      89         2344 :         void ForEach(Fn&& fn)
      90              :         {
      91       186798 :             for (size_t i = 0; i < m_data.size(); ++i)
      92              :             {
      93       184454 :                 fn(m_denseToEntity[i], m_data[i]);
      94              :             }
      95         2344 :         }
      96              : 
      97              :         template <typename Fn>
      98           23 :         void ForEach(Fn&& fn) const
      99              :         {
     100         2066 :             for (size_t i = 0; i < m_data.size(); ++i)
     101              :             {
     102         2043 :                 fn(m_denseToEntity[i], m_data[i]);
     103              :             }
     104           23 :         }
     105              : 
     106              :         // Direct access for systems (e.g. JobSystem)
     107       151258 :         std::vector<TComponent>& GetData() { return m_data; }
     108         6199 :         const std::vector<TComponent>& GetData() const { return m_data; }
     109       140129 :         const std::vector<EntityId>& GetEntities() const { return m_denseToEntity; }
     110          590 :         size_t Size() const { return m_data.size(); }
     111              : 
     112              :     private:
     113              :         std::vector<TComponent> m_data;
     114              :         std::vector<EntityId>   m_denseToEntity;
     115              :         std::unordered_map<EntityId, size_t> m_entityToDense;
     116              :     };
     117              : }
        

Generated by: LCOV version 2.0-1