Gaia-ECS v0.9.3
A simple and powerful entity component system
Loading...
Searching...
No Matches
component_desc.h
1#pragma once
2#include "gaia/config/config.h"
3
4#include <cstdint>
5#include <cstring>
6#include <tuple>
7#include <type_traits>
8
9#include "gaia/core/span.h"
10#include "gaia/core/utility.h"
11#include "gaia/ecs/component.h"
12#include "gaia/mem/data_layout_policy.h"
13#include "gaia/mem/mem_utils.h"
14#include "gaia/meta/reflection.h"
15#include "gaia/meta/type_info.h"
16#include "gaia/ser/ser_rt.h"
17#include "gaia/util/str.h"
18
19namespace gaia {
20 namespace ecs {
22 enum class RuntimeTypeKind : uint8_t {
23 None,
24 Primitive,
25 Struct,
26 };
27
29 enum class RuntimePrimitiveKind : uint8_t {
30 None,
31 Bool,
32 S8,
33 U8,
34 S16,
35 U16,
36 S32,
37 U32,
38 S64,
39 U64,
40 Char8,
41 Char16,
42 Char32,
43 WChar,
44 F8,
45 F16,
46 F32,
47 F64,
48 F128,
49 };
50
53 struct RuntimeFieldDesc final {
57 Entity type = EntityBad;
59 uint32_t offset = 0;
61 uint32_t count = 0;
62 };
63
65 struct RuntimeField final {
66 char name[256]{};
67 Entity type = EntityBad;
68 uint32_t offset = 0;
69 uint32_t count = 0;
70 };
71
75 struct ComponentDesc final {
76 using FuncCtor = void(void*, uint32_t);
77 using FuncDtor = void(void*, uint32_t);
78 using FuncFrom = void(void*, void*, uint32_t, uint32_t, uint32_t, uint32_t);
79 using FuncCopy = void(void*, const void*, uint32_t, uint32_t, uint32_t, uint32_t);
80 using FuncMove = void(void*, void*, uint32_t, uint32_t, uint32_t, uint32_t);
81 using FuncSwap = void(void*, void*, uint32_t, uint32_t, uint32_t, uint32_t);
82 using FuncCmp = bool(const void*, const void*);
83 using FuncSave = void(ser::serializer&, const void*, uint32_t, uint32_t, uint32_t);
84 using FuncLoad = void(ser::serializer&, void*, uint32_t, uint32_t, uint32_t);
85
89 uint32_t size = 0;
91 uint32_t alig = 0;
93 DataStorageType storageType = DataStorageType::Table;
95 uint32_t soa = 0;
97 const uint8_t* pSoaSizes = nullptr;
101 RuntimeTypeKind typeKind = RuntimeTypeKind::Struct;
103 RuntimePrimitiveKind primitiveKind = RuntimePrimitiveKind::None;
105 FuncCtor* funcCtor = nullptr;
106 FuncMove* funcMoveCtor = nullptr;
107 FuncCopy* funcCopyCtor = nullptr;
108 FuncDtor* funcDtor = nullptr;
109 FuncCopy* funcCopy = nullptr;
110 FuncMove* funcMove = nullptr;
111 FuncSwap* funcSwap = nullptr;
112 FuncCmp* funcCmp = nullptr;
113 FuncSave* funcSave = nullptr;
114 FuncLoad* funcLoad = nullptr;
115 };
116
117 namespace detail {
118 template <typename T>
119 struct ComponentDesc final {
120 using CT = component_type_t<T>;
121 using U = typename component_type_t<T>::Type;
122 using DescU = typename CT::TypeFull;
123
124 static constexpr ComponentLookupHash hash_lookup() {
125 return {meta::type_info::hash<DescU>()};
126 }
127
128 static constexpr auto name() {
129 return meta::type_info::name<DescU>();
130 }
131
132 static constexpr uint32_t size() {
133 if constexpr (std::is_empty_v<U>)
134 return 0;
135 else
136 return (uint32_t)sizeof(U);
137 }
138
139 static constexpr uint32_t alig() {
140 constexpr auto alig = mem::auto_view_policy<U>::Alignment;
141 static_assert(alig < Component::MaxAlignment, "Maximum supported alignment for a component is MaxAlignment");
142 return alig;
143 }
144
145 static uint32_t soa(std::span<uint8_t, meta::StructToTupleMaxTypes> soaSizes) {
146 if constexpr (mem::is_soa_layout_v<U>) {
147 uint32_t i = 0;
148 using TTuple = decltype(meta::struct_to_tuple(std::declval<U>()));
149 // is_soa_layout_v is always false for empty types so we know there is at least one element in the tuple
150 constexpr auto TTupleSize = std::tuple_size_v<TTuple>;
151 static_assert(TTupleSize > 0);
152 static_assert(TTupleSize <= meta::StructToTupleMaxTypes);
153 core::each_tuple<TTuple>([&](auto&& item) {
154 static_assert(sizeof(item) <= 255, "Each member of a SoA component can be at most 255 B long!");
155 soaSizes[i] = (uint8_t)sizeof(item);
156 ++i;
157 });
158 GAIA_ASSERT(i <= meta::StructToTupleMaxTypes);
159 return i;
160 } else {
161 return 0U;
162 }
163 }
164
165 static constexpr auto func_ctor() {
166 if constexpr (!mem::is_soa_layout_v<U> && !std::is_trivially_constructible_v<U>) {
167 return [](void* ptr, uint32_t cnt) {
168 core::call_ctor_n((U*)ptr, cnt);
169 };
170 } else {
171 return nullptr;
172 }
173 }
174
175 static constexpr auto func_dtor() {
176 if constexpr (!mem::is_soa_layout_v<U> && !std::is_trivially_destructible_v<U>) {
177 return [](void* ptr, uint32_t cnt) {
178 core::call_dtor_n((U*)ptr, cnt);
179 };
180 } else {
181 return nullptr;
182 }
183 }
184
185 static constexpr auto func_copy_ctor() {
186 return [](void* GAIA_RESTRICT dst, const void* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
187 uint32_t sizeDst, uint32_t sizeSrc) {
188 mem::copy_ctor_element<U>((uint8_t*)dst, (const uint8_t*)src, idxDst, idxSrc, sizeDst, sizeSrc);
189 };
190 }
191
192 static constexpr auto func_move_ctor() {
193 return [](void* GAIA_RESTRICT dst, void* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
194 uint32_t sizeDst, uint32_t sizeSrc) {
195 mem::move_ctor_element<U>((uint8_t*)dst, (uint8_t*)src, idxDst, idxSrc, sizeDst, sizeSrc);
196 };
197 }
198
199 static constexpr auto func_copy() {
200 return [](void* GAIA_RESTRICT dst, const void* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
201 uint32_t sizeDst, uint32_t sizeSrc) {
202 mem::copy_element<U>((uint8_t*)dst, (const uint8_t*)src, idxDst, idxSrc, sizeDst, sizeSrc);
203 };
204 }
205
206 static constexpr auto func_move() {
207 return [](void* GAIA_RESTRICT dst, void* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
208 uint32_t sizeDst, uint32_t sizeSrc) {
209 mem::move_element<U>((uint8_t*)dst, (uint8_t*)src, idxDst, idxSrc, sizeDst, sizeSrc);
210 };
211 }
212
213 static constexpr auto func_swap() {
214 return [](void* GAIA_RESTRICT left, void* GAIA_RESTRICT right, uint32_t idxLeft, uint32_t idxRight,
215 uint32_t sizeLeft, uint32_t sizeRight) {
216 mem::swap_elements<U>((uint8_t*)left, (uint8_t*)right, idxLeft, idxRight, sizeLeft, sizeRight);
217 };
218 }
219
220 static constexpr auto func_cmp() {
221 if constexpr (mem::is_soa_layout_v<U>) {
222 return []([[maybe_unused]] const void* left, [[maybe_unused]] const void* right) {
223 GAIA_ASSERT(false && "func_cmp for SoA not implemented yet");
224 return false;
225 };
226 } else {
227 constexpr bool hasGlobalCmp = core::has_ffunc_equals<U>::value;
228 constexpr bool hasMemberCmp = core::has_func_equals<U>::value;
229 if constexpr (hasGlobalCmp || hasMemberCmp) {
230 return [](const void* left, const void* right) {
231 const auto* l = (const U*)left;
232 const auto* r = (const U*)right;
233 return *l == *r;
234 };
235 } else {
236 // fallback comparison function
237 return [](const void* left, const void* right) {
238 const auto* l = (const U*)left;
239 const auto* r = (const U*)right;
240 return memcmp(l, r, sizeof(U)) == 0;
241 };
242 }
243 }
244 }
245
246 static constexpr auto func_save() {
247 return [](ser::serializer& s, const void* pSrc, uint32_t from, uint32_t to, uint32_t cap) {
248 const auto* pComponent = (const U*)pSrc;
249
250#if GAIA_ASSERT_ENABLED
251 // Check if save and load match. Testing with one item is enough.
252 s.check(*pComponent);
253#endif
254
255 if constexpr (mem::is_soa_layout_v<U>) {
256 auto view = mem::auto_view_policy_get<U>{std::span{(const uint8_t*)pSrc, cap}};
257 GAIA_FOR2(from, to) {
258 auto val = view[i];
259 s.save(val);
260 }
261 } else {
262 pComponent += from;
263 GAIA_FOR2(from, to) {
264 s.save(*pComponent);
265 ++pComponent;
266 }
267 }
268 };
269 }
270
271 static constexpr auto func_load() {
272 return [](ser::serializer& s, void* pDst, uint32_t from, uint32_t to, uint32_t cap) {
273 if constexpr (mem::is_soa_layout_v<U>) {
274 auto view = mem::auto_view_policy_set<U>{std::span{(uint8_t*)pDst, cap}};
275 GAIA_FOR2(from, to) {
276 U val;
277 s.load(val);
278 view[i] = val;
279 }
280 } else {
281 auto* pComponent = (U*)pDst + from;
282 GAIA_FOR2(from, to) {
283 s.load(*pComponent);
284 ++pComponent;
285 }
286 }
287 };
288 }
289
295 static ecs::ComponentDesc
297 ecs::ComponentDesc desc{};
298 desc.name = descName;
299 desc.size = size();
300 desc.alig = alig();
301 desc.storageType = DataStorageType::Table;
302 desc.soa = soa(soaSizes);
303 desc.pSoaSizes = soaSizes.data();
304 desc.hashLookup = hash_lookup();
305 desc.funcCtor = func_ctor();
306 desc.funcMoveCtor = func_move_ctor();
307 desc.funcCopyCtor = func_copy_ctor();
308 desc.funcDtor = func_dtor();
309 desc.funcCopy = func_copy();
310 desc.funcMove = func_move();
311 desc.funcSwap = func_swap();
312 desc.funcCmp = func_cmp();
313 desc.funcSave = func_save();
314 desc.funcLoad = func_load();
315 return desc;
316 }
317 };
318 } // namespace detail
319 } // namespace ecs
320} // namespace gaia
Definition span_impl.h:99
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9
Detects whether T supports a free operator==.
Definition utility.h:766
Detects whether T defines operator== as a member function.
Definition utility.h:758
Plain component registration descriptor shared by typed and runtime component paths....
Definition component_desc.h:75
FuncCtor * funcCtor
Optional lifecycle and serialization callbacks.
Definition component_desc.h:105
const uint8_t * pSoaSizes
Per-element SoA sizes when soa is non-zero.
Definition component_desc.h:97
RuntimeTypeKind typeKind
Runtime reflection type kind.
Definition component_desc.h:101
uint32_t soa
Number of SoA elements, 0 means AoS.
Definition component_desc.h:95
DataStorageType storageType
Component storage mode.
Definition component_desc.h:93
RuntimePrimitiveKind primitiveKind
Runtime primitive kind. Only valid when typeKind is Primitive.
Definition component_desc.h:103
uint32_t alig
Component payload alignment in bytes.
Definition component_desc.h:91
uint32_t size
Component payload size in bytes.
Definition component_desc.h:89
ComponentLookupHash hashLookup
Optional explicit lookup hash. When empty, the symbol hash is used.
Definition component_desc.h:99
util::str_view name
Registered component symbol.
Definition component_desc.h:87
Definition id.h:247
User-authored runtime field descriptor. A count of 0 means scalar; positive values describe a fixed i...
Definition component_desc.h:53
uint32_t count
Inline array element count. 0 means scalar.
Definition component_desc.h:61
util::str_view name
Field symbol.
Definition component_desc.h:55
Entity type
Entity describing the field type.
Definition component_desc.h:57
uint32_t offset
Byte offset from the start of the component payload.
Definition component_desc.h:59
Stored runtime field metadata.
Definition component_desc.h:65
Definition component_desc.h:119
static ecs::ComponentDesc make(util::str_view descName, std::span< uint8_t, meta::StructToTupleMaxTypes > soaSizes)
Builds the plain descriptor used by component cache registration.
Definition component_desc.h:296
Definition data_layout_policy.h:90
Definition data_layout_policy.h:92
Definition data_layout_policy.h:87
Runtime serializer type-erased handle. Traversal logic is shared with compile-time serialization,...
Definition ser_rt.h:79
Lightweight non-owning string view over a character sequence.
Definition str.h:13
GAIA_NODISCARD constexpr uint32_t size() const
Returns the number of characters in the view.
Definition str.h:41