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