Gaia-ECS v1.0.0
A simple and powerful entity component system
Loading...
Searching...
No Matches
reflection.h
1#pragma once
2#include "gaia/config/config.h"
3
4#include <tuple>
5#include <type_traits>
6#include <utility>
7
8#include "gaia/core/utility.h"
9
10namespace gaia {
11 namespace meta {
12
13 GAIA_MSVC_WARNING_PUSH()
14 // Fix for MSVC bug:
15 // ...
16 // template <DataLayout TDataLayout, typename ValueType>
17 // struct data_view_policy_soa {
18 // static_assert(std::is_copy_assignable_v<ValueType>);
19 // using TTuple = decltype(meta::struct_to_tuple(std::declval<ValueType>())); << unreachable code
20 // ...
21 GAIA_MSVC_WARNING_DISABLE(4702) // unreachable code
22
24 namespace detail {
25 // Check if type T is constructible via T{Args...}
26 struct any_type {
27 template <typename T>
28 constexpr operator T(); // non explicit
29 };
30
31 template <typename T, typename... TArgs>
32 decltype((void)T{std::declval<TArgs>()...}, std::true_type{}) is_braces_constructible(int);
33
34 template <typename, typename...>
35 std::false_type is_braces_constructible(...);
36
37 template <typename T, typename... TArgs>
38 using is_braces_constructible_t = decltype(detail::is_braces_constructible<T, TArgs...>(0));
39 } // namespace detail
41
42 //----------------------------------------------------------------------
43 // Tuple to struct conversion
44 //----------------------------------------------------------------------
45
52 template <typename S, size_t... Is, typename Tuple>
53 GAIA_NODISCARD S tuple_to_struct(std::index_sequence<Is...> /*no_name*/, Tuple&& tup) {
54 return {std::get<Is>(GAIA_FWD(tup))...};
55 }
56
62 template <typename S, typename Tuple>
63 GAIA_NODISCARD S tuple_to_struct(Tuple&& tup) {
64 using T = std::remove_reference_t<Tuple>;
65
66 return tuple_to_struct<S>(std::make_index_sequence<std::tuple_size<T>{}>{}, GAIA_FWD(tup));
67 }
68
69 //----------------------------------------------------------------------
70 // Struct to tuple conversion
71 //----------------------------------------------------------------------
72
74 static constexpr uint32_t StructToTupleMaxTypes_Bits = 4;
76 static constexpr uint32_t StructToTupleMaxTypes = (1 << StructToTupleMaxTypes_Bits) - 1;
77
82 template <typename T>
83 auto struct_to_tuple(T&& object) noexcept {
84 using type = core::raw_t<T>;
85
86 if constexpr (std::is_empty_v<type>) {
87 return std::make_tuple();
88 } else if constexpr (
89 detail::is_braces_constructible_t<
90 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
91 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
92 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type>{}) {
93 auto&& [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15] = GAIA_FWD(object);
94 return std::make_tuple(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15);
95 } else if constexpr (
96 detail::is_braces_constructible_t<
97 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
98 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
99 detail::any_type, detail::any_type, detail::any_type, detail::any_type>{}) {
100 auto&& [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14] = GAIA_FWD(object);
101 return std::make_tuple(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14);
102 } else if constexpr (
103 detail::is_braces_constructible_t<
104 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
105 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
106 detail::any_type, detail::any_type, detail::any_type>{}) {
107 auto&& [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13] = GAIA_FWD(object);
108 return std::make_tuple(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13);
109 } else if constexpr (
110 detail::is_braces_constructible_t<
111 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
112 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
113 detail::any_type, detail::any_type>{}) {
114 auto&& [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12] = GAIA_FWD(object);
115 return std::make_tuple(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12);
116 } else if constexpr (
117 detail::is_braces_constructible_t<
118 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
119 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
120 detail::any_type>{}) {
121 auto&& [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11] = GAIA_FWD(object);
122 return std::make_tuple(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11);
123 } else if constexpr (
124 detail::is_braces_constructible_t<
125 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
126 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type>{}) {
127 auto&& [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10] = GAIA_FWD(object);
128 return std::make_tuple(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
129 } else if constexpr (
130 detail::is_braces_constructible_t<
131 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
132 detail::any_type, detail::any_type, detail::any_type, detail::any_type>{}) {
133 auto&& [p1, p2, p3, p4, p5, p6, p7, p8, p9] = GAIA_FWD(object);
134 return std::make_tuple(p1, p2, p3, p4, p5, p6, p7, p8, p9);
135 } else if constexpr (
136 detail::is_braces_constructible_t<
137 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
138 detail::any_type, detail::any_type, detail::any_type>{}) {
139 auto&& [p1, p2, p3, p4, p5, p6, p7, p8] = GAIA_FWD(object);
140 return std::make_tuple(p1, p2, p3, p4, p5, p6, p7, p8);
141 } else if constexpr (
142 detail::is_braces_constructible_t<
143 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
144 detail::any_type, detail::any_type>{}) {
145 auto&& [p1, p2, p3, p4, p5, p6, p7] = GAIA_FWD(object);
146 return std::make_tuple(p1, p2, p3, p4, p5, p6, p7);
147 } else if constexpr (
148 detail::is_braces_constructible_t<
149 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
150 detail::any_type>{}) {
151 auto&& [p1, p2, p3, p4, p5, p6] = GAIA_FWD(object);
152 return std::make_tuple(p1, p2, p3, p4, p5, p6);
153 } else if constexpr (
154 detail::is_braces_constructible_t<
155 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type>{}) {
156 auto&& [p1, p2, p3, p4, p5] = GAIA_FWD(object);
157 return std::make_tuple(p1, p2, p3, p4, p5);
158 } else if constexpr (
159 detail::is_braces_constructible_t<
160 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type>{}) {
161 auto&& [p1, p2, p3, p4] = GAIA_FWD(object);
162 return std::make_tuple(p1, p2, p3, p4);
163 } else if constexpr (
164 detail::is_braces_constructible_t<type, detail::any_type, detail::any_type, detail::any_type>{}) {
165 auto&& [p1, p2, p3] = GAIA_FWD(object);
166 return std::make_tuple(p1, p2, p3);
167 } else if constexpr (detail::is_braces_constructible_t<type, detail::any_type, detail::any_type>{}) {
168 auto&& [p1, p2] = GAIA_FWD(object);
169 return std::make_tuple(p1, p2);
170 } else if constexpr (detail::is_braces_constructible_t<type, detail::any_type>{}) {
171 auto&& [p1] = GAIA_FWD(object);
172 return std::make_tuple(p1);
173 }
174
175 GAIA_ASSERT2(false, "Unsupported number of members");
176 }
177
178 //----------------------------------------------------------------------
179 // Struct to tuple conversion
180 //----------------------------------------------------------------------
181
185 template <typename T>
186 auto struct_member_count() {
187 using type = core::raw_t<T>;
188
189 if constexpr (std::is_empty_v<type>) {
190 return 0;
191 } else if constexpr (
192 detail::is_braces_constructible_t<
193 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
194 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
195 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type>{}) {
196 return 15;
197 } else if constexpr (
198 detail::is_braces_constructible_t<
199 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
200 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
201 detail::any_type, detail::any_type, detail::any_type, detail::any_type>{}) {
202 return 14;
203 } else if constexpr (
204 detail::is_braces_constructible_t<
205 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
206 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
207 detail::any_type, detail::any_type, detail::any_type>{}) {
208 return 13;
209 } else if constexpr (
210 detail::is_braces_constructible_t<
211 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
212 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
213 detail::any_type, detail::any_type>{}) {
214 return 12;
215 } else if constexpr (
216 detail::is_braces_constructible_t<
217 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
218 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
219 detail::any_type>{}) {
220 return 11;
221 } else if constexpr (
222 detail::is_braces_constructible_t<
223 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
224 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type>{}) {
225 return 10;
226 } else if constexpr (
227 detail::is_braces_constructible_t<
228 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
229 detail::any_type, detail::any_type, detail::any_type, detail::any_type>{}) {
230 return 9;
231 } else if constexpr (
232 detail::is_braces_constructible_t<
233 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
234 detail::any_type, detail::any_type, detail::any_type>{}) {
235 return 8;
236 } else if constexpr (
237 detail::is_braces_constructible_t<
238 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
239 detail::any_type, detail::any_type>{}) {
240 return 7;
241 } else if constexpr (
242 detail::is_braces_constructible_t<
243 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
244 detail::any_type>{}) {
245 return 6;
246 } else if constexpr (
247 detail::is_braces_constructible_t<
248 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type>{}) {
249 return 5;
250 } else if constexpr (
251 detail::is_braces_constructible_t<
252 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type>{}) {
253 return 4;
254 } else if constexpr (
255 detail::is_braces_constructible_t<type, detail::any_type, detail::any_type, detail::any_type>{}) {
256 return 3;
257 } else if constexpr (detail::is_braces_constructible_t<type, detail::any_type, detail::any_type>{}) {
258 return 2;
259 } else if constexpr (detail::is_braces_constructible_t<type, detail::any_type>{}) {
260 return 1;
261 }
262
263 GAIA_ASSERT2(false, "Unsupported number of members");
264 }
265
272 template <typename T, typename Func>
273 auto each_member(T&& object, Func&& visitor) {
274 using type = core::raw_t<T>;
275
276 if constexpr (std::is_empty_v<type>) {
277 visitor();
278 } else if constexpr (
279 detail::is_braces_constructible_t<
280 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
281 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
282 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type>{}) {
283 auto&& [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15] = object;
284 return visitor(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15);
285 } else if constexpr (
286 detail::is_braces_constructible_t<
287 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
288 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
289 detail::any_type, detail::any_type, detail::any_type, detail::any_type>{}) {
290 auto&& [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14] = object;
291 return visitor(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14);
292 } else if constexpr (
293 detail::is_braces_constructible_t<
294 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
295 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
296 detail::any_type, detail::any_type, detail::any_type>{}) {
297 auto&& [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13] = object;
298 return visitor(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13);
299 } else if constexpr (
300 detail::is_braces_constructible_t<
301 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
302 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
303 detail::any_type, detail::any_type>{}) {
304 auto&& [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12] = object;
305 return visitor(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12);
306 } else if constexpr (
307 detail::is_braces_constructible_t<
308 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
309 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
310 detail::any_type>{}) {
311 auto&& [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11] = object;
312 return visitor(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11);
313 } else if constexpr (
314 detail::is_braces_constructible_t<
315 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
316 detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type>{}) {
317 auto&& [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10] = object;
318 return visitor(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
319 } else if constexpr (
320 detail::is_braces_constructible_t<
321 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
322 detail::any_type, detail::any_type, detail::any_type, detail::any_type>{}) {
323 auto&& [p1, p2, p3, p4, p5, p6, p7, p8, p9] = object;
324 return visitor(p1, p2, p3, p4, p5, p6, p7, p8, p9);
325 } else if constexpr (
326 detail::is_braces_constructible_t<
327 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
328 detail::any_type, detail::any_type, detail::any_type>{}) {
329 auto&& [p1, p2, p3, p4, p5, p6, p7, p8] = object;
330 return visitor(p1, p2, p3, p4, p5, p6, p7, p8);
331 } else if constexpr (
332 detail::is_braces_constructible_t<
333 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
334 detail::any_type, detail::any_type>{}) {
335 auto&& [p1, p2, p3, p4, p5, p6, p7] = object;
336 return visitor(p1, p2, p3, p4, p5, p6, p7);
337 } else if constexpr (
338 detail::is_braces_constructible_t<
339 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type,
340 detail::any_type>{}) {
341 auto&& [p1, p2, p3, p4, p5, p6] = object;
342 return visitor(p1, p2, p3, p4, p5, p6);
343 } else if constexpr (
344 detail::is_braces_constructible_t<
345 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type, detail::any_type>{}) {
346 auto&& [p1, p2, p3, p4, p5] = object;
347 return visitor(p1, p2, p3, p4, p5);
348 } else if constexpr (
349 detail::is_braces_constructible_t<
350 type, detail::any_type, detail::any_type, detail::any_type, detail::any_type>{}) {
351 auto&& [p1, p2, p3, p4] = object;
352 return visitor(p1, p2, p3, p4);
353 } else if constexpr (
354 detail::is_braces_constructible_t<type, detail::any_type, detail::any_type, detail::any_type>{}) {
355 auto&& [p1, p2, p3] = object;
356 return visitor(p1, p2, p3);
357 } else if constexpr (detail::is_braces_constructible_t<type, detail::any_type, detail::any_type>{}) {
358 auto&& [p1, p2] = object;
359 return visitor(p1, p2);
360 } else if constexpr (detail::is_braces_constructible_t<type, detail::any_type>{}) {
361 auto&& [p1] = object;
362 return visitor(p1);
363 }
364
365 GAIA_ASSERT2(false, "Unsupported number of members");
366 }
367
368 GAIA_MSVC_WARNING_POP() // C4702
369 } // namespace meta
370} // namespace gaia