Gaia-ECS v0.9.3
A simple and powerful entity component system
Loading...
Searching...
No Matches
component_cache.h
1#pragma once
2#include "gaia/config/config.h"
3
4#include <cinttypes>
5#include <cstdint>
6#include <type_traits>
7
8#include "gaia/cnt/darray.h"
9#include "gaia/cnt/map.h"
10#include "gaia/core/hashing_string.h"
11#include "gaia/ecs/component.h"
12#include "gaia/ecs/component_cache_item.h"
13#include "gaia/ecs/component_desc.h"
14#include "gaia/ecs/id.h"
15#include "gaia/meta/type_info.h"
16#include "gaia/util/logging.h"
17
18namespace gaia {
19 namespace ecs {
20 class World;
21
23 class GAIA_API ComponentCache final {
24 friend class World;
25
26 static constexpr uint32_t FastComponentCacheSize = 512;
27
32
37
44 void clear() {
45 for (const auto* pItem: m_itemArr)
46 ComponentCacheItem::destroy(const_cast<ComponentCacheItem*>(pItem));
47 for (auto [componentId, pItem]: m_itemByDescId)
48 ComponentCacheItem::destroy(const_cast<ComponentCacheItem*>(pItem));
49
50 m_itemArr.clear();
51 m_itemByDescId.clear();
52 m_compByString.clear();
53 m_compByEntity.clear();
54 }
55
56 public:
58 // Reserve enough storage space for most use-cases
59 m_itemArr.reserve(FastComponentCacheSize);
60 }
61
63 clear();
64 }
65
67 ComponentCache(const ComponentCache&) = delete;
68 ComponentCache& operator=(ComponentCache&&) = delete;
69 ComponentCache& operator=(const ComponentCache&) = delete;
70
73 template <typename T>
74 GAIA_NODISCARD GAIA_FORCEINLINE const ComponentCacheItem& add(Entity entity) {
75 static_assert(!is_pair<T>::value);
76 GAIA_ASSERT(!entity.pair());
77
78 const auto compDescId = detail::ComponentDesc<T>::id();
79
80 // Fast path for small component ids - use the array storage
81 if (compDescId < FastComponentCacheSize) {
82 auto createDesc = [&]() -> const ComponentCacheItem& {
83 const auto* pItem = ComponentCacheItem::create<T>(entity);
84 GAIA_ASSERT(compDescId == pItem->comp.id());
85 m_itemArr[compDescId] = pItem;
86 m_compByString.emplace(pItem->name, pItem);
87 m_compByEntity.emplace(pItem->entity, pItem);
88 return *pItem;
89 };
90
91 if GAIA_UNLIKELY (compDescId >= m_itemArr.size()) {
92 const auto oldSize = m_itemArr.size();
93 const auto newSize = compDescId + 1U;
94
95 // Increase the capacity by multiples of CapacityIncreaseSize
96 constexpr uint32_t CapacityIncreaseSize = 128;
97 const auto newCapacity = ((newSize / CapacityIncreaseSize) * CapacityIncreaseSize) + CapacityIncreaseSize;
98 m_itemArr.reserve(newCapacity);
99
100 // Update the size
101 m_itemArr.resize(newSize);
102
103 // Make sure unused memory is initialized to nullptr.
104 GAIA_FOR2(oldSize, newSize - 1) m_itemArr[i] = nullptr;
105
106 return createDesc();
107 }
108
109 if GAIA_UNLIKELY (m_itemArr[compDescId] == nullptr) {
110 return createDesc();
111 }
112
113 return *m_itemArr[compDescId];
114 }
115
116 // Generic path for large component ids - use the map storage
117 {
118 auto createDesc = [&]() -> const ComponentCacheItem& {
119 const auto* pItem = ComponentCacheItem::create<T>(entity);
120 GAIA_ASSERT(compDescId == pItem->comp.id());
121 m_itemByDescId.emplace(compDescId, pItem);
122 m_compByString.emplace(pItem->name, pItem);
123 m_compByEntity.emplace(pItem->entity, pItem);
124 return *pItem;
125 };
126
127 const auto it = m_itemByDescId.find(compDescId);
128 if (it == m_itemByDescId.end())
129 return createDesc();
130
131 return *it->second;
132 }
133 }
134
138 GAIA_NODISCARD const ComponentCacheItem* find(detail::ComponentDescId compDescId) const noexcept {
139 // Fast path - array storage
140 if (compDescId < FastComponentCacheSize) {
141 if (compDescId >= m_itemArr.size())
142 return nullptr;
143
144 return m_itemArr[compDescId];
145 }
146
147 // Generic path - map storage
148 const auto it = m_itemByDescId.find(compDescId);
149 return it != m_itemByDescId.end() ? it->second : nullptr;
150 }
151
156 GAIA_NODISCARD const ComponentCacheItem& get(detail::ComponentDescId compDescId) const noexcept {
157 // Fast path - array storage
158 if (compDescId < FastComponentCacheSize) {
159 GAIA_ASSERT(compDescId < m_itemArr.size());
160 return *m_itemArr[compDescId];
161 }
162
163 // Generic path - map storage
164 GAIA_ASSERT(m_itemByDescId.contains(compDescId));
165 return *m_itemByDescId.find(compDescId)->second;
166 }
167
171 GAIA_NODISCARD const ComponentCacheItem* find(Entity entity) const noexcept {
172 GAIA_ASSERT(!entity.pair());
173 const auto it = m_compByEntity.find(EntityLookupKey(entity));
174 if (it != m_compByEntity.end())
175 return it->second;
176
177 return nullptr;
178 }
179
184 GAIA_NODISCARD const ComponentCacheItem& get(Entity entity) const noexcept {
185 GAIA_ASSERT(!entity.pair());
186 const auto* pItem = find(entity);
187 GAIA_ASSERT(pItem != nullptr);
188 return *pItem;
189 }
190
195 GAIA_NODISCARD const ComponentCacheItem* find(const char* name, uint32_t len = 0) const noexcept {
196 GAIA_ASSERT(name != nullptr);
197
198 const auto l = len == 0 ? (uint32_t)strnlen(name, ComponentCacheItem::MaxNameLength) : len;
199 GAIA_ASSERT(l < ComponentCacheItem::MaxNameLength);
200
201 const auto it = m_compByString.find(ComponentCacheItem::SymbolLookupKey(name, l, 0));
202 if (it != m_compByString.end())
203 return it->second;
204
205 return nullptr;
206 }
207
213 GAIA_NODISCARD const ComponentCacheItem& get(const char* name, uint32_t len = 0) const noexcept {
214 const auto* pItem = find(name, len);
215 GAIA_ASSERT(pItem != nullptr);
216 return *pItem;
217 }
218
222 template <typename T>
223 GAIA_NODISCARD const ComponentCacheItem* find() const noexcept {
224 static_assert(!is_pair<T>::value);
225 const auto compDescId = detail::ComponentDesc<T>::id();
226 return find(compDescId);
227 }
228
232 template <typename T>
233 GAIA_NODISCARD const ComponentCacheItem& get() const noexcept {
234 static_assert(!is_pair<T>::value);
235 const auto compDescId = detail::ComponentDesc<T>::id();
236 return get(compDescId);
237 }
238
239#if GAIA_ENABLE_HOOKS
240
244 static ComponentCacheItem::Hooks& hooks(const ComponentCacheItem& cacheItem) noexcept {
245 return const_cast<ComponentCacheItem&>(cacheItem).hooks();
246 }
247
248#endif
249
250 void diag() const {
251 const auto registeredTypes = m_itemArr.size();
252 GAIA_LOG_N("Registered components: %u", registeredTypes);
253
254 auto logDesc = [](const ComponentCacheItem& item) {
255 GAIA_LOG_N(
256 " hash:%016" PRIx64 ", size:%3u B, align:%3u B, [%u:%u] %s [%s]", item.hashLookup.hash,
257 item.comp.size(), item.comp.alig(), item.entity.id(), item.entity.gen(), item.name.str(),
258 EntityKindString[item.entity.kind()]);
259 };
260 for (const auto* pItem: m_itemArr) {
261 if (pItem == nullptr)
262 continue;
263 logDesc(*pItem);
264 }
265 for (auto [componentId, pItem]: m_itemByDescId)
266 logDesc(*pItem);
267 }
268 };
269 } // namespace ecs
270} // namespace gaia
Array with variable size of elements of type.
Definition darray_impl.h:25
Cache for compile-time defined components.
Definition component_cache.h:23
GAIA_NODISCARD const ComponentCacheItem & get(Entity entity) const noexcept
Returns the component cache item.
Definition component_cache.h:184
GAIA_NODISCARD const ComponentCacheItem & get(const char *name, uint32_t len=0) const noexcept
Returns the component cache item. The provided string is NOT copied internally.
Definition component_cache.h:213
GAIA_NODISCARD const ComponentCacheItem & get() const noexcept
Returns the component item for.
Definition component_cache.h:233
GAIA_NODISCARD const ComponentCacheItem * find(const char *name, uint32_t len=0) const noexcept
Searches for the component cache item. The provided string is NOT copied internally.
Definition component_cache.h:195
GAIA_NODISCARD const ComponentCacheItem * find(detail::ComponentDescId compDescId) const noexcept
Searches for the component cache item given the compDescId.
Definition component_cache.h:138
GAIA_NODISCARD const ComponentCacheItem * find(Entity entity) const noexcept
Searches for the component cache item.
Definition component_cache.h:171
GAIA_NODISCARD const ComponentCacheItem * find() const noexcept
Searches for the component item for.
Definition component_cache.h:223
GAIA_NODISCARD const ComponentCacheItem & get(detail::ComponentDescId compDescId) const noexcept
Returns the component cache item given the compDescId.
Definition component_cache.h:156
GAIA_NODISCARD GAIA_FORCEINLINE const ComponentCacheItem & add(Entity entity)
Registers the component item for.
Definition component_cache.h:74
Definition world.h:48
Definition robin_hood.h:720
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9
Definition component_cache_item.h:24
Hashmap lookup structure used for Entity.
Definition id.h:336
Definition id.h:225
Definition component_desc.h:24
Definition id.h:217