Flecs: include/flecs/addons/cpp/lifecycle_traits.hpp Source File
Description: A fast entity component system (ECS) for C & C++

| Flecs v4.0 A fast entity component system (ECS) for C & C++

Loading...
Searching...
No Matches
lifecycle_traits.hpp
Go to the documentation of this file.
1
5
6#pragma once
7
8namespace flecs
9{
10
11namespace _
12{
13
14// T()
15// Can't coexist with T(flecs::entity) or T(flecs::world, flecs::entity)
16template <typename T>
17void ctor_impl(void *ptr, int32_t count, const ecs_type_info_t *info) {
18 (void)info; ecs_assert(info->size == ECS_SIZEOF(T),
19 ECS_INTERNAL_ERROR, NULL);
20 T *arr = static_cast<T*>(ptr);
21 for (int i = 0; i < count; i ++) {
22 FLECS_PLACEMENT_NEW(&arr[i], T);
23 }
24}
25
26// ~T()
27template <typename T>
28void dtor_impl(void *ptr, int32_t count, const ecs_type_info_t *info) {
29 (void)info; ecs_assert(info->size == ECS_SIZEOF(T),
30 ECS_INTERNAL_ERROR, NULL);
31 T *arr = static_cast<T*>(ptr);
32 for (int i = 0; i < count; i ++) {
33 arr[i].~T();
34 }
35}
36
37// T& operator=(const T&)
38template <typename T>
39void copy_impl(void *dst_ptr, const void *src_ptr, int32_t count,
40 const ecs_type_info_t *info)
41{
42 (void)info; ecs_assert(info->size == ECS_SIZEOF(T),
43 ECS_INTERNAL_ERROR, NULL);
44 T *dst_arr = static_cast<T*>(dst_ptr);
45 const T *src_arr = static_cast<const T*>(src_ptr);
46 for (int i = 0; i < count; i ++) {
47 dst_arr[i] = src_arr[i];
48 }
49}
50
51// T& operator=(T&&)
52template <typename T>
53void move_impl(void *dst_ptr, void *src_ptr, int32_t count,
54 const ecs_type_info_t *info)
55{
56 (void)info; ecs_assert(info->size == ECS_SIZEOF(T),
57 ECS_INTERNAL_ERROR, NULL);
58 T *dst_arr = static_cast<T*>(dst_ptr);
59 T *src_arr = static_cast<T*>(src_ptr);
60 for (int i = 0; i < count; i ++) {
61 dst_arr[i] = FLECS_MOV(src_arr[i]);
62 }
63}
64
65// T(T&)
66template <typename T>
67void copy_ctor_impl(void *dst_ptr, const void *src_ptr, int32_t count,
68 const ecs_type_info_t *info)
69{
70 (void)info; ecs_assert(info->size == ECS_SIZEOF(T),
71 ECS_INTERNAL_ERROR, NULL);
72 T *dst_arr = static_cast<T*>(dst_ptr);
73 const T *src_arr = static_cast<const T*>(src_ptr);
74 for (int i = 0; i < count; i ++) {
75 FLECS_PLACEMENT_NEW(&dst_arr[i], T(src_arr[i]));
76 }
77}
78
79// T(T&&)
80template <typename T>
81void move_ctor_impl(void *dst_ptr, void *src_ptr, int32_t count,
82 const ecs_type_info_t *info)
83{
84 (void)info; ecs_assert(info->size == ECS_SIZEOF(T),
85 ECS_INTERNAL_ERROR, NULL);
86 T *dst_arr = static_cast<T*>(dst_ptr);
87 T *src_arr = static_cast<T*>(src_ptr);
88 for (int i = 0; i < count; i ++) {
89 FLECS_PLACEMENT_NEW(&dst_arr[i], T(FLECS_MOV(src_arr[i])));
90 }
91}
92
93// T(T&&), ~T()
94// Typically used when moving to a new table, and removing from the old table
95template <typename T>
96void ctor_move_dtor_impl(void *dst_ptr, void *src_ptr, int32_t count,
97 const ecs_type_info_t *info)
98{
99 (void)info; ecs_assert(info->size == ECS_SIZEOF(T),
100 ECS_INTERNAL_ERROR, NULL);
101 T *dst_arr = static_cast<T*>(dst_ptr);
102 T *src_arr = static_cast<T*>(src_ptr);
103 for (int i = 0; i < count; i ++) {
104 FLECS_PLACEMENT_NEW(&dst_arr[i], T(FLECS_MOV(src_arr[i])));
105 src_arr[i].~T();
106 }
107}
108
109// Move assign + dtor (non-trivial move assignment)
110// Typically used when moving a component to a deleted component
111template <typename T, if_not_t<
112 std::is_trivially_move_assignable<T>::value > = 0>
113void move_dtor_impl(void *dst_ptr, void *src_ptr, int32_t count,
114 const ecs_type_info_t *info)
115{
116 (void)info; ecs_assert(info->size == ECS_SIZEOF(T),
117 ECS_INTERNAL_ERROR, NULL);
118 T *dst_arr = static_cast<T*>(dst_ptr);
119 T *src_arr = static_cast<T*>(src_ptr);
120 for (int i = 0; i < count; i ++) {
121 // Move assignment should free dst & assign dst to src
122 dst_arr[i] = FLECS_MOV(src_arr[i]);
123 // Destruct src. Move should have left object in a state where it no
124 // longer holds resources, but it still needs to be destructed.
125 src_arr[i].~T();
126 }
127}
128
129// Move assign + dtor (trivial move assignment)
130// Typically used when moving a component to a deleted component
131template <typename T, if_t<
132 std::is_trivially_move_assignable<T>::value > = 0>
133void move_dtor_impl(void *dst_ptr, void *src_ptr, int32_t count,
134 const ecs_type_info_t *info)
135{
136 (void)info; ecs_assert(info->size == ECS_SIZEOF(T),
137 ECS_INTERNAL_ERROR, NULL);
138 T *dst_arr = static_cast<T*>(dst_ptr);
139 T *src_arr = static_cast<T*>(src_ptr);
140 for (int i = 0; i < count; i ++) {
141 // Cleanup resources of dst
142 dst_arr[i].~T();
143 // Copy src to dst
144 dst_arr[i] = FLECS_MOV(src_arr[i]);
145 // No need to destruct src. Since this is a trivial move the code
146 // should be agnostic to the address of the component which means we
147 // can pretend nothing got destructed.
148 }
149}
150
151} // _
152
153// Trait to test if type is constructible by flecs
154template <typename T>
155 struct is_flecs_constructible {
156 static constexpr bool value =
157 std::is_default_constructible<actual_type_t<T>>::value;
158};
159
160namespace _
161{
162
163// Trivially constructible
164template <typename T, if_t< std::is_trivially_constructible<T>::value > = 0>
165 ecs_xtor_t ctor(ecs_flags32_t &) {
166 return nullptr;
167}
168
169// Not constructible by flecs
170template <typename T, if_t<
171 ! std::is_default_constructible<T>::value > = 0>
172 ecs_xtor_t ctor(ecs_flags32_t &flags) {
173 flags |= ECS_TYPE_HOOK_CTOR_ILLEGAL;
174 return nullptr;
175}
176
177// Default constructible
178template <typename T, if_t<
179 ! std::is_trivially_constructible<T>::value &&
180 std::is_default_constructible<T>::value > = 0>
181 ecs_xtor_t ctor(ecs_flags32_t &) {
182 return ctor_impl<T>;
183}
184
185// No dtor
186template <typename T, if_t< std::is_trivially_destructible<T>::value > = 0>
187 ecs_xtor_t dtor(ecs_flags32_t &) {
188 return nullptr;
189}
190
191// Dtor
192template <typename T, if_t<
193 std::is_destructible<T>::value &&
194 ! std::is_trivially_destructible<T>::value > = 0>
195 ecs_xtor_t dtor(ecs_flags32_t &) {
196 return dtor_impl<T>;
197}
198
199// Assert when the type cannot be destructed
200template <typename T, if_not_t< std::is_destructible<T>::value > = 0>
201 ecs_xtor_t dtor(ecs_flags32_t &flags) {
202 flecs_static_assert(always_false<T>::value,
203 "component type must be destructible");
204 flags |= ECS_TYPE_HOOK_DTOR_ILLEGAL;
205 return nullptr;
206}
207
208// Trivially copyable
209template <typename T, if_t< std::is_trivially_copyable<T>::value > = 0>
210 ecs_copy_t copy(ecs_flags32_t &) {
211 return nullptr;
212}
213
214// Not copyable
215template <typename T, if_t<
216 ! std::is_trivially_copyable<T>::value &&
217 ! std::is_copy_assignable<T>::value > = 0>
218 ecs_copy_t copy(ecs_flags32_t &flags) {
219 flags |= ECS_TYPE_HOOK_COPY_ILLEGAL;
220 return nullptr;
221}
222
223// Copy assignment
224template <typename T, if_t<
225 std::is_copy_assignable<T>::value &&
226 ! std::is_trivially_copyable<T>::value > = 0>
227 ecs_copy_t copy(ecs_flags32_t &) {
228 return copy_impl<T>;
229}
230
231// Trivially move assignable
232template <typename T, if_t< std::is_trivially_move_assignable<T>::value > = 0>
233 ecs_move_t move(ecs_flags32_t &) {
234 return nullptr;
235}
236
237// Component types must be move assignable
238template <typename T, if_not_t< std::is_move_assignable<T>::value > = 0>
239 ecs_move_t move(ecs_flags32_t &flags) {
240 flags |= ECS_TYPE_HOOK_MOVE_ILLEGAL;
241 return nullptr;
242}
243
244// Move assignment
245template <typename T, if_t<
246 std::is_move_assignable<T>::value &&
247 ! std::is_trivially_move_assignable<T>::value > = 0>
248 ecs_move_t move(ecs_flags32_t &) {
249 return move_impl<T>;
250}
251
252// Trivially copy constructible
253template <typename T, if_t<
254 std::is_trivially_copy_constructible<T>::value > = 0>
255 ecs_copy_t copy_ctor(ecs_flags32_t &) {
256 return nullptr;
257}
258
259// No copy ctor
260template <typename T, if_t< ! std::is_copy_constructible<T>::value > = 0>
261 ecs_copy_t copy_ctor(ecs_flags32_t &flags) {
262 flags |= ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL;
263 return nullptr;
264
265}
266
267// Copy ctor
268template <typename T, if_t<
269 std::is_copy_constructible<T>::value &&
270 ! std::is_trivially_copy_constructible<T>::value > = 0>
271 ecs_copy_t copy_ctor(ecs_flags32_t &) {
272 return copy_ctor_impl<T>;
273}
274
275// Trivially move constructible
276template <typename T, if_t<
277 std::is_trivially_move_constructible<T>::value > = 0>
278 ecs_move_t move_ctor(ecs_flags32_t &) {
279 return nullptr;
280}
281
282// Component types must be move constructible
283template <typename T, if_not_t< std::is_move_constructible<T>::value > = 0>
284 ecs_move_t move_ctor(ecs_flags32_t &flags) {
285 flags |= ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL;
286 return nullptr;
287}
288
289// Move ctor
290template <typename T, if_t<
291 std::is_move_constructible<T>::value &&
292 ! std::is_trivially_move_constructible<T>::value > = 0>
293 ecs_move_t move_ctor(ecs_flags32_t &) {
294 return move_ctor_impl<T>;
295}
296
297// Trivial merge (move assign + dtor)
298template <typename T, if_t<
299 std::is_trivially_move_constructible<T>::value &&
300 std::is_trivially_destructible<T>::value > = 0>
301 ecs_move_t ctor_move_dtor(ecs_flags32_t &) {
302 return nullptr;
303}
304
305// Component types must be move constructible and destructible
306template <typename T, if_t<
307 ! std::is_move_constructible<T>::value ||
308 ! std::is_destructible<T>::value > = 0>
309 ecs_move_t ctor_move_dtor(ecs_flags32_t &flags) {
310 flags |= ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL;
311 return nullptr;
312}
313
314// Merge ctor + dtor
315template <typename T, if_t<
316 !(std::is_trivially_move_constructible<T>::value &&
317 std::is_trivially_destructible<T>::value) &&
318 std::is_move_constructible<T>::value &&
319 std::is_destructible<T>::value > = 0>
320 ecs_move_t ctor_move_dtor(ecs_flags32_t &) {
321 return ctor_move_dtor_impl<T>;
322}
323
324// Trivial merge (move assign + dtor)
325template <typename T, if_t<
326 std::is_trivially_move_assignable<T>::value &&
327 std::is_trivially_destructible<T>::value > = 0>
328 ecs_move_t move_dtor(ecs_flags32_t &) {
329 return nullptr;
330}
331
332// Component types must be move constructible and destructible
333template <typename T, if_t<
334 ! std::is_move_assignable<T>::value ||
335 ! std::is_destructible<T>::value > = 0>
336 ecs_move_t move_dtor(ecs_flags32_t &flags) {
337 flags |= ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL;
338 return nullptr;
339}
340
341// Merge assign + dtor
342template <typename T, if_t<
343 !(std::is_trivially_move_assignable<T>::value &&
344 std::is_trivially_destructible<T>::value) &&
345 std::is_move_assignable<T>::value &&
346 std::is_destructible<T>::value > = 0>
347 ecs_move_t move_dtor(ecs_flags32_t &) {
348 return move_dtor_impl<T>;
349}
350
351} // _
352} // flecs
ecs_assert
#define ecs_assert(condition, error_code,...)
Assert.
Definition log.h:368
ecs_type_info_t
struct ecs_type_info_t ecs_type_info_t
Type information.
Definition flecs.h:452
ecs_copy_t
void(* ecs_copy_t)(void *dst_ptr, const void *src_ptr, int32_t count, const ecs_type_info_t *type_info)
Copy is invoked when a component is copied into another component.
Definition flecs.h:633
ecs_move_t
void(* ecs_move_t)(void *dst_ptr, void *src_ptr, int32_t count, const ecs_type_info_t *type_info)
Move is invoked when a component is moved to another component.
Definition flecs.h:640
ecs_xtor_t
void(* ecs_xtor_t)(void *ptr, int32_t count, const ecs_type_info_t *type_info)
Constructor/destructor callback.
Definition flecs.h:627
flecs::_
Int to enum.
Definition component.hpp:21
ecs_type_info_t::size
ecs_size_t size
Size of type.
Definition flecs.h:954
flecs::is_flecs_constructible
Definition lifecycle_traits.hpp:155