Gaia-ECS v0.9.3
A simple and powerful entity component system
Loading...
Searching...
No Matches
component_cache_item.h
1#pragma once
2#include "gaia/config/config.h"
3
4#include <cstdint>
5#include <type_traits>
6
7#include "gaia/core/hashing_string.h"
8#include "gaia/ecs/component.h"
9#include "gaia/ecs/component_desc.h"
10#include "gaia/ecs/id.h"
11#include "gaia/mem/mem_alloc.h"
12#include "gaia/mem/mem_utils.h"
13
14namespace gaia {
15 namespace ser {
16 struct ISerializer;
17 } // namespace ser
18
19 namespace ecs {
20 class World;
21 class Chunk;
22 struct ComponentRecord;
23
24 struct GAIA_API ComponentCacheItem final {
25 static constexpr uint32_t MaxNameLength = 256;
26
28
29 using FuncCtor = void(void*, uint32_t);
30 using FuncDtor = void(void*, uint32_t);
31 using FuncFrom = void(void*, void*, uint32_t, uint32_t, uint32_t, uint32_t);
32 using FuncCopy = void(void*, const void*, uint32_t, uint32_t, uint32_t, uint32_t);
33 using FuncMove = void(void*, void*, uint32_t, uint32_t, uint32_t, uint32_t);
34 using FuncSwap = void(void*, void*, uint32_t, uint32_t, uint32_t, uint32_t);
35 using FuncCmp = bool(const void*, const void*);
36
37 using FuncSave = void(ser::ISerializer*, const void*, uint32_t, uint32_t, uint32_t);
38 using FuncLoad = void(ser::ISerializer*, void*, uint32_t, uint32_t, uint32_t);
39
40 using FuncOnAdd = void(const World& world, const ComponentCacheItem&, Entity);
41 using FuncOnDel = void(const World& world, const ComponentCacheItem&, Entity);
42 using FuncOnSet = void(const World& world, const ComponentRecord&, Chunk& chunk);
43
51 uint8_t soaSizes[meta::StructToTupleMaxTypes];
52
56 FuncCtor* func_ctor{};
58 FuncMove* func_move_ctor{};
60 FuncCopy* func_copy_ctor{};
62 FuncDtor* func_dtor{};
64 FuncCopy* func_copy{};
66 FuncMove* func_move{};
68 FuncSwap* func_swap{};
70 FuncCmp* func_cmp{};
72 FuncSave* func_save{};
73 // !Function to call when loading component from a buffer
74 FuncLoad* func_load{};
75
76#if GAIA_ENABLE_HOOKS
77 struct Hooks {
78 #if GAIA_ENABLE_ADD_DEL_HOOKS
80 FuncOnAdd* func_add{};
82 FuncOnDel* func_del{};
83 #endif
84 #if GAIA_ENABLE_SET_HOOKS
86 FuncOnSet* func_set{};
87 #endif
88 };
89 Hooks comp_hooks;
90#endif
91
92 private:
93 ComponentCacheItem() = default;
94 ~ComponentCacheItem() = default;
95
96 public:
97 ComponentCacheItem(const ComponentCacheItem&) = delete;
98 ComponentCacheItem(ComponentCacheItem&&) = delete;
99 ComponentCacheItem& operator=(const ComponentCacheItem&) = delete;
100 ComponentCacheItem& operator=(ComponentCacheItem&&) = delete;
101
102 void
103 ctor_move(void* pDst, void* pSrc, uint32_t idxDst, uint32_t idxSrc, uint32_t sizeDst, uint32_t sizeSrc) const {
104 GAIA_ASSERT(func_move_ctor != nullptr && (pSrc != pDst || idxSrc != idxDst));
105 func_move_ctor(pDst, pSrc, idxDst, idxSrc, sizeDst, sizeSrc);
106 }
107
108 void ctor_copy(
109 void* pDst, const void* pSrc, uint32_t idxDst, uint32_t idxSrc, uint32_t sizeDst, uint32_t sizeSrc) const {
110 GAIA_ASSERT(func_copy_ctor != nullptr && (pSrc != pDst || idxSrc != idxDst));
111 func_copy_ctor(pDst, pSrc, idxDst, idxSrc, sizeDst, sizeSrc);
112 }
113
114 void dtor(void* pSrc) const {
115 if (func_dtor != nullptr)
116 func_dtor(pSrc, 1);
117 }
118
119 void
120 copy(void* pDst, const void* pSrc, uint32_t idxDst, uint32_t idxSrc, uint32_t sizeDst, uint32_t sizeSrc) const {
121 GAIA_ASSERT(func_copy != nullptr && (pSrc != pDst || idxSrc != idxDst));
122 func_copy(pDst, pSrc, idxDst, idxSrc, sizeDst, sizeSrc);
123 }
124
125 void move(void* pDst, void* pSrc, uint32_t idxDst, uint32_t idxSrc, uint32_t sizeDst, uint32_t sizeSrc) const {
126 GAIA_ASSERT(func_move != nullptr && (pSrc != pDst || idxSrc != idxDst));
127 func_move(pDst, pSrc, idxDst, idxSrc, sizeDst, sizeSrc);
128 }
129
130 void
131 swap(void* pLeft, void* pRight, uint32_t idxLeft, uint32_t idxRight, uint32_t sizeDst, uint32_t sizeSrc) const {
132 GAIA_ASSERT(func_swap != nullptr);
133 func_swap(pLeft, pRight, idxLeft, idxRight, sizeDst, sizeSrc);
134 }
135
136 bool cmp(const void* pLeft, const void* pRight) const {
137 GAIA_ASSERT(pLeft != pRight);
138 GAIA_ASSERT(func_cmp != nullptr);
139 return func_cmp(pLeft, pRight);
140 }
141
142 void save(ser::ISerializer* pSerializer, const void* pSrc, uint32_t from, uint32_t to, uint32_t cap) const {
143 GAIA_ASSERT(func_save != nullptr && pSrc != nullptr && from < to && to <= cap);
144 func_save(pSerializer, pSrc, from, to, cap);
145 }
146
147 void load(ser::ISerializer* pSerializer, void* pDst, uint32_t from, uint32_t to, uint32_t cap) const {
148 GAIA_ASSERT(func_load != nullptr && pDst != nullptr && from < to && to <= cap);
149 func_load(pSerializer, pDst, from, to, cap);
150 }
151
152#if GAIA_ENABLE_HOOKS
153 Hooks& hooks() {
154 return comp_hooks;
155 }
156
157 const Hooks& hooks() const {
158 return comp_hooks;
159 }
160
161#endif
162
163 GAIA_NODISCARD uint32_t calc_new_mem_offset(uint32_t addr, size_t cnt) const noexcept {
164 if (comp.soa() == 0) {
165 addr = (uint32_t)mem::detail::get_aligned_byte_offset(addr, comp.alig(), comp.size(), cnt);
166 } else {
167 GAIA_FOR(comp.soa()) {
168 addr = (uint32_t)mem::detail::get_aligned_byte_offset(addr, comp.alig(), soaSizes[i], cnt);
169 }
170 // TODO: Magic offset. Otherwise, SoA data might leak past the chunk boundary when accessing
171 // the last element. By faking the memory offset we can bypass this is issue for now.
172 // Obviously, this needs fixing at some point.
173 addr += comp.soa() * 12;
174 }
175 return addr;
176 }
177
178 template <typename T>
179 GAIA_NODISCARD static ComponentCacheItem* create(Entity entity) {
180 static_assert(core::is_raw_v<T>);
181
182 constexpr auto componentSize = detail::ComponentDesc<T>::size();
183 static_assert(
184 componentSize < Component::MaxComponentSizeInBytes,
185 "Trying to register a component larger than the maximum allowed component size! In the future this "
186 "restriction won't apply to components not stored inside archetype chunks.");
187
188 auto* cci = mem::AllocHelper::alloc<ComponentCacheItem>("ComponentCacheItem");
189 (void)new (cci) ComponentCacheItem();
190 cci->entity = entity;
191 cci->comp = Component(
192 // component id
193 detail::ComponentDesc<T>::id(),
194 // soa
195 detail::ComponentDesc<T>::soa(cci->soaSizes),
196 // size in bytes
197 componentSize,
198 // alignment
199 detail::ComponentDesc<T>::alig());
200 cci->hashLookup = detail::ComponentDesc<T>::hash_lookup();
201
202 auto ct_name = detail::ComponentDesc<T>::name();
203
204 // Allocate enough memory for the name string + the null-terminating character (
205 // the compile time string returned by ComponentDesc<T>::name is not null-terminated).
206 // Different compilers will give a bit different strings, e.g.:
207 // Clang/GCC: gaia::ecs::uni<Position>
208 // MSVC : gaia::ecs::uni<struct Position>
209 // Therefore, we first copy the compile-time string and then tweak it so it is
210 // the same on all supported compilers.
211 char nameTmp[MaxNameLength];
212 auto nameTmpLen = (uint32_t)ct_name.size();
213 GAIA_ASSERT(nameTmpLen < MaxNameLength);
214 memcpy((void*)nameTmp, (const void*)ct_name.data(), nameTmpLen + 1);
215 nameTmp[ct_name.size()] = 0;
216
217 // Remove "class " or "struct " substrings from the string
218 const uint32_t NSubstrings = 2;
219 const char* to_remove[NSubstrings] = {"class ", "struct "};
220 const uint32_t to_remove_len[NSubstrings] = {6, 7};
221 GAIA_FOR(NSubstrings) {
222 const auto& str = to_remove[i];
223 const auto len = to_remove_len[i];
224
225 auto* pos = nameTmp;
226 while ((pos = strstr(pos, str)) != nullptr) {
227 memmove(pos, pos + len, strlen(pos + len) + 1);
228 nameTmpLen -= len;
229 }
230 }
231
232 // Allocate the final string
233 char* name = mem::AllocHelper::alloc<char>(nameTmpLen + 1);
234 memcpy((void*)name, (const void*)nameTmp, nameTmpLen + 1);
235 name[nameTmpLen] = 0;
236
237 cci->name = SymbolLookupKey(name, nameTmpLen, 1);
238
239 cci->func_ctor = detail::ComponentDesc<T>::func_ctor();
240 cci->func_move_ctor = detail::ComponentDesc<T>::func_move_ctor();
241 cci->func_copy_ctor = detail::ComponentDesc<T>::func_copy_ctor();
242 cci->func_dtor = detail::ComponentDesc<T>::func_dtor();
243 cci->func_copy = detail::ComponentDesc<T>::func_copy();
244 cci->func_move = detail::ComponentDesc<T>::func_move();
245 cci->func_swap = detail::ComponentDesc<T>::func_swap();
246 cci->func_cmp = detail::ComponentDesc<T>::func_cmp();
247 cci->func_save = detail::ComponentDesc<T>::func_save();
248 cci->func_load = detail::ComponentDesc<T>::func_load();
249
250 return cci;
251 }
252
253 static void destroy(ComponentCacheItem* pItem) {
254 if (pItem == nullptr)
255 return;
256
257 if (pItem->name.str() != nullptr && pItem->name.owned()) {
258 mem::AllocHelper::free((void*)pItem->name.str());
259 pItem->name = {};
260 }
261
262 pItem->~ComponentCacheItem();
263 mem::AllocHelper::free("ComponentCacheItem", pItem);
264 }
265 };
266 } // namespace ecs
267} // namespace gaia
Definition chunk.h:29
Definition world.h:48
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9
Definition component_cache_item.h:24
Entity entity
Component entity.
Definition component_cache_item.h:45
ComponentLookupHash hashLookup
Complex hash used for look-ups.
Definition component_cache_item.h:49
Component comp
Unique component identifier.
Definition component_cache_item.h:47
SymbolLookupKey name
Component name.
Definition component_cache_item.h:54
Definition chunk_header.h:30
Definition id.h:25
Definition id.h:225
Definition ser_rt.h:13