Gaia-ECS v0.9.3
A simple and powerful entity component system
Loading...
Searching...
No Matches
mem_utils.h
1#pragma once
2#include "gaia/config/config.h"
3
4#include <cstdint>
5#include <type_traits>
6
7#include "gaia/core/utility.h"
8#include "gaia/mem/data_layout_policy.h"
9
10namespace gaia {
11 namespace mem {
12 template <typename T>
13 constexpr bool is_copyable() {
14 return std::is_trivially_copyable_v<T> || std::is_trivially_assignable_v<T, T> || //
15 std::is_copy_assignable_v<T> || std::is_copy_constructible_v<T>;
16 }
17
18 template <typename T>
19 constexpr bool is_movable() {
20 return std::is_trivially_move_assignable_v<T> || std::is_trivially_move_constructible_v<T> || //
21 std::is_move_assignable_v<T> || std::is_move_constructible_v<T>;
22 }
23
24 namespace detail {
25 template <typename T>
26 void copy_ctor_element_aos(T* GAIA_RESTRICT dst, const T* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc) {
27 GAIA_MSVC_WARNING_PUSH()
28 GAIA_MSVC_WARNING_DISABLE(6385)
29
30 if constexpr (std::is_trivially_copyable_v<T>) {
31 memcpy(dst + idxDst, src + idxSrc, sizeof(T));
32 } else if constexpr (std::is_copy_assignable_v<T>) {
33 // Prefer assignment path — it can be faster for types with data reuse
34 core::call_ctor(&dst[idxDst]);
35 dst[idxDst] = src[idxSrc];
36 } else {
37 static_assert(std::is_copy_constructible_v<T>);
38 core::call_ctor(&dst[idxDst], T(src[idxSrc]));
39 }
40
41 GAIA_MSVC_WARNING_POP()
42 }
43
44 template <typename T>
45 void copy_element_aos(T* GAIA_RESTRICT dst, const T* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc) {
46 GAIA_MSVC_WARNING_PUSH()
47 GAIA_MSVC_WARNING_DISABLE(6385)
48
49 if constexpr (std::is_trivially_copyable_v<T>) {
50 memcpy(dst + idxDst, src + idxSrc, sizeof(T));
51 } else if constexpr (std::is_copy_assignable_v<T>) {
52 dst[idxDst] = src[idxSrc];
53 } else {
54 static_assert(std::is_copy_constructible_v<T>);
55 dst[idxDst] = T(src[idxSrc]);
56 }
57
58 GAIA_MSVC_WARNING_POP()
59 }
60
61 template <typename T>
62 void copy_elements_aos(T* GAIA_RESTRICT dst, const T* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc) {
63 GAIA_MSVC_WARNING_PUSH()
64 GAIA_MSVC_WARNING_DISABLE(6385)
65
66 GAIA_ASSERT(idxSrc < idxDst);
67
68 const auto cnt = idxDst - idxSrc;
69
70 if constexpr (std::is_trivially_copyable_v<T>) {
71 memcpy(dst + idxSrc, src + idxSrc, sizeof(T) * cnt);
72 } else if constexpr (std::is_copy_assignable_v<T>) {
73 const T* s = src + idxSrc;
74 T* d = dst + idxSrc;
75 GAIA_FOR(cnt) d[i] = s[i];
76 } else {
77 static_assert(std::is_copy_constructible_v<T>);
78 const T* s = src + idxSrc;
79 T* d = dst + idxSrc;
80 GAIA_FOR(cnt) d[i] = T(s[i]);
81 }
82
83 GAIA_MSVC_WARNING_POP()
84 }
85
86 template <typename T>
87 void copy_element_soa(
88 uint8_t* GAIA_RESTRICT dst, const uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
89 uint32_t sizeDst, uint32_t sizeSrc) {
90 GAIA_MSVC_WARNING_PUSH()
91 GAIA_MSVC_WARNING_DISABLE(6385)
92
93 static_assert(mem::is_soa_layout_v<T>);
94
95 (data_view_policy_soa_set<T::gaia_Data_Layout, T>({std::span{dst, sizeDst}}))[idxDst] =
96 (data_view_policy_soa_get<T::gaia_Data_Layout, T>({std::span{(const uint8_t*)src, sizeSrc}}))[idxSrc];
97
98 GAIA_MSVC_WARNING_POP()
99 }
100
101 template <typename T>
102 void copy_elements_soa(
103 uint8_t* GAIA_RESTRICT dst, const uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
104 uint32_t sizeDst, uint32_t sizeSrc) {
105 GAIA_MSVC_WARNING_PUSH()
106 GAIA_MSVC_WARNING_DISABLE(6385)
107
108 static_assert(mem::is_soa_layout_v<T>);
109
110 GAIA_ASSERT(idxSrc < idxDst);
111
112 GAIA_FOR2(idxSrc, idxDst) {
113 (data_view_policy_soa_set<T::gaia_Data_Layout, T>({std::span{dst, sizeDst}}))[i] =
114 (data_view_policy_soa_get<T::gaia_Data_Layout, T>({std::span{(const uint8_t*)src, sizeSrc}}))[i];
115 }
116
117 GAIA_MSVC_WARNING_POP()
118 }
119
120 template <typename T>
121 void move_ctor_element_aos(T* GAIA_RESTRICT dst, T* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc) {
122 GAIA_MSVC_WARNING_PUSH()
123 GAIA_MSVC_WARNING_DISABLE(6385)
124
125 if constexpr (std::is_trivially_move_constructible_v<T> && std::is_trivially_destructible_v<T>) {
126 memcpy(dst + idxDst, src + idxSrc, sizeof(T));
127 } else if constexpr (std::is_move_assignable_v<T>) {
128 core::call_ctor(&dst[idxDst]);
129 dst[idxDst] = GAIA_MOV(src[idxSrc]);
130 } else {
131 static_assert(std::is_move_constructible_v<T>);
132 core::call_ctor(&dst[idxDst], T(GAIA_MOV(src[idxSrc])));
133 }
134
135 GAIA_MSVC_WARNING_POP()
136 }
137
138 template <typename T>
139 void move_element_aos(T* GAIA_RESTRICT dst, T* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc) {
140 GAIA_MSVC_WARNING_PUSH()
141 GAIA_MSVC_WARNING_DISABLE(6385)
142
143 if constexpr (std::is_trivially_move_assignable_v<T>) {
144 memcpy(dst + idxDst, src + idxSrc, sizeof(T));
145 } else if constexpr (std::is_move_assignable_v<T>) {
146 dst[idxDst] = GAIA_MOV(src[idxSrc]);
147 } else {
148 static_assert(std::is_move_constructible_v<T>);
149 dst[idxDst] = T(GAIA_MOV(src[idxSrc]));
150 }
151
152 GAIA_MSVC_WARNING_POP()
153 }
154
155 template <typename T>
156 void move_elements_aos(T* GAIA_RESTRICT dst, T* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc) {
157 GAIA_MSVC_WARNING_PUSH()
158 GAIA_MSVC_WARNING_DISABLE(6385)
159
160 GAIA_ASSERT(idxSrc < idxDst);
161
162 if constexpr (std::is_trivially_move_assignable_v<T>) {
163 memcpy((void*)&dst[idxSrc], (const void*)&src[idxSrc], sizeof(T) * (idxDst - idxSrc));
164 } else if constexpr (std::is_move_assignable_v<T>) {
165 GAIA_FOR2(idxSrc, idxDst) dst[i] = GAIA_MOV(src[i]);
166 } else {
167 static_assert(std::is_move_constructible_v<T>);
168 GAIA_FOR2(idxSrc, idxDst) dst[i] = T(GAIA_MOV(src[i]));
169 }
170
171 GAIA_MSVC_WARNING_POP()
172 }
173
180 template <typename T>
181 void shift_elements_left_aos(T* dst, uint32_t idxDst, uint32_t idxSrc, uint32_t n) {
182 GAIA_MSVC_WARNING_PUSH()
183 GAIA_MSVC_WARNING_DISABLE(6385)
184
185 GAIA_ASSERT(idxSrc < idxDst);
186
187 if constexpr (std::is_trivially_copy_assignable_v<T> || std::is_trivially_move_assignable_v<T>) {
188 memmove((void*)&dst[idxSrc], (const void*)&dst[idxSrc + n], sizeof(T) * (idxDst - idxSrc));
189 }
190 // Move first if possible
191 else if constexpr (std::is_move_assignable_v<T>) {
192 GAIA_FOR2(idxSrc, idxDst) dst[i] = GAIA_MOV(dst[i + n]);
193 } else if constexpr (std::is_move_constructible_v<T>) {
194 GAIA_FOR2(idxSrc, idxDst) dst[i] = T(GAIA_MOV(dst[i + n]));
195 }
196 // Try to copy if moves are not possible
197 else if constexpr (std::is_copy_assignable_v<T>) {
198 GAIA_FOR2(idxSrc, idxDst) dst[i] = dst[i + n];
199 } else if constexpr (std::is_copy_constructible_v<T>) {
200 GAIA_FOR2(idxSrc, idxDst) dst[i] = T(dst[i + n]);
201 } else {
202 GAIA_ASSERT(false && "Not implemented");
203 }
204
205 GAIA_MSVC_WARNING_POP()
206 }
207
215 template <typename T>
216 void shift_elements_left_aos_fast(T* dst, uint32_t idxDst, uint32_t idxSrc, uint32_t n) {
217 GAIA_MSVC_WARNING_PUSH()
218 GAIA_MSVC_WARNING_DISABLE(6385)
219
220 GAIA_ASSERT(idxSrc < idxDst);
221
222 const auto max = idxDst - idxSrc - n;
223
224 if constexpr (std::is_trivially_copy_assignable_v<T> || std::is_trivially_move_assignable_v<T>) {
225 memcpy((void*)&dst[idxSrc], (const void*)&dst[idxSrc + n], sizeof(T) * max);
226 }
227 // Move first if possible
228 else if constexpr (std::is_move_assignable_v<T>) {
229 GAIA_FOR(max) dst[idxSrc + i] = GAIA_MOV(dst[idxSrc + i + n]);
230 } else if constexpr (std::is_move_constructible_v<T>) {
231 GAIA_FOR(max) dst[idxSrc + i] = T(GAIA_MOV(dst[idxSrc + i + n]));
232 }
233 // Try to copy if moves are not possible
234 else if constexpr (std::is_copy_assignable_v<T>) {
235 GAIA_FOR(max) dst[idxSrc + i] = dst[idxSrc + i + n];
236 } else if constexpr (std::is_copy_constructible_v<T>) {
237 GAIA_FOR(max) dst[idxSrc + i] = T(dst[idxSrc + i + n]);
238 } else {
239 GAIA_ASSERT(false && "Not implemented");
240 }
241
242 GAIA_MSVC_WARNING_POP()
243 }
244
252 template <typename T>
253 void shift_elements_left_soa(uint8_t* dst, uint32_t idxDst, uint32_t idxSrc, uint32_t n, uint32_t size) {
254 GAIA_MSVC_WARNING_PUSH()
255 GAIA_MSVC_WARNING_DISABLE(6385)
256
257 static_assert(mem::is_soa_layout_v<T>);
258
259 GAIA_ASSERT(idxSrc < idxDst);
260
261 GAIA_FOR2(idxSrc, idxDst) {
262 (data_view_policy_soa_set<T::gaia_Data_Layout, T>({std::span<uint8_t>{dst, size}}))[i] =
263 (data_view_policy_soa_get<T::gaia_Data_Layout, T>(
264 {std::span<const uint8_t>{(const uint8_t*)dst, size}}))[i + n];
265 }
266
267 GAIA_MSVC_WARNING_POP()
268 }
269
276 template <typename T>
277 void shift_elements_right_aos(T* dst, uint32_t idxDst, uint32_t idxSrc, uint32_t n) {
278 GAIA_MSVC_WARNING_PUSH()
279 GAIA_MSVC_WARNING_DISABLE(6385)
280
281 GAIA_ASSERT(idxSrc < idxDst);
282
283 const auto max = idxDst - idxSrc;
284 const auto idx = idxDst - 1;
285
286 if constexpr (std::is_trivially_copy_assignable_v<T> || std::is_trivially_move_assignable_v<T>) {
287 memmove(dst + idxSrc + n, dst + idxSrc, sizeof(T) * max);
288 }
289 // Move first if possible
290 else if constexpr (std::is_move_assignable_v<T>) {
291 GAIA_FOR(max) dst[idx - i + n] = GAIA_MOV(dst[idx - i]);
292 } else if constexpr (std::is_move_constructible_v<T>) {
293 GAIA_FOR(max) dst[idx - i + n] = T(GAIA_MOV(dst[idx - i]));
294 }
295 // Try to copy if moves are not possible
296 else if constexpr (std::is_copy_assignable_v<T>) {
297 GAIA_FOR(max) dst[idx - i + n] = dst[idx - i];
298 } else if constexpr (std::is_copy_constructible_v<T>) {
299 GAIA_FOR(max) dst[idx - i + n] = T(dst[idx - i]);
300 } else {
301 GAIA_ASSERT(false && "Not implemented");
302 }
303
304 GAIA_MSVC_WARNING_POP()
305 }
306
314 template <typename T>
315 void shift_elements_right_aos_fast(T* dst, uint32_t idxDst, uint32_t idxSrc, uint32_t n) {
316 GAIA_MSVC_WARNING_PUSH()
317 GAIA_MSVC_WARNING_DISABLE(6385)
318
319 GAIA_ASSERT(idxSrc + n < idxDst);
320
321 const auto max = idxDst - idxSrc - n;
322
323 if constexpr (std::is_trivially_copy_assignable_v<T> || std::is_trivially_move_assignable_v<T>) {
324 memcpy(dst + idxSrc + n, dst + idxSrc, sizeof(T) * max);
325 }
326 // Move/copy from the end to avoid overwriting data
327 else if constexpr (std::is_move_assignable_v<T>) {
328 GAIA_FOR(max) dst[idxSrc + i + n] = GAIA_MOV(dst[idxSrc + i]);
329 } else if constexpr (std::is_move_constructible_v<T>) {
330 GAIA_FOR(max) dst[idxSrc + i + n] = T(GAIA_MOV(dst[idxSrc + i]));
331 }
332 // Try to copy if moves are not possible
333 else if constexpr (std::is_copy_assignable_v<T>) {
334 GAIA_FOR(max) dst[idxSrc + i + n] = dst[idxSrc + i];
335 } else if constexpr (std::is_copy_constructible_v<T>) {
336 GAIA_FOR(max) dst[idxSrc + i + n] = T(dst[idxSrc + i]);
337 } else {
338 GAIA_ASSERT(false && "Not implemented");
339 }
340
341 GAIA_MSVC_WARNING_POP()
342 }
343
351 template <typename T>
352 void shift_elements_right_soa(uint8_t* dst, uint32_t idxDst, uint32_t idxSrc, uint32_t n, uint32_t size) {
353 GAIA_MSVC_WARNING_PUSH()
354 GAIA_MSVC_WARNING_DISABLE(6385)
355
356 static_assert(mem::is_soa_layout_v<T>);
357
358 GAIA_ASSERT(idxSrc < idxDst);
359
360 GAIA_FOR2(idxSrc, idxDst) {
361 (data_view_policy_soa_set<T::gaia_Data_Layout, T>({std::span<uint8_t>{dst, size}}))[i + n] =
362 (data_view_policy_soa_get<T::gaia_Data_Layout, T>(
363 {std::span<const uint8_t>{(const uint8_t*)dst, size}}))[i];
364 }
365
366 GAIA_MSVC_WARNING_POP()
367 }
368 } // namespace detail
369
370 GAIA_CLANG_WARNING_PUSH()
371 // Memory is aligned so we can silence this warning
372 GAIA_CLANG_WARNING_DISABLE("-Wcast-align")
373
383 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
384 void copy_ctor_element(
385 uint8_t* GAIA_RESTRICT dst, const uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
386 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
387 if GAIA_UNLIKELY (src == dst && idxSrc == idxDst)
388 return;
389
390 if constexpr (!SOA)
391 detail::copy_ctor_element_aos<T>((T*)dst, (const T*)src, idxDst, idxSrc);
392 else
393 detail::copy_element_soa<T>(dst, src, idxDst, idxSrc, sizeDst, sizeSrc);
394 }
395
406 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
407 void copy_element(
408 uint8_t* GAIA_RESTRICT dst, const uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
409 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
410 if GAIA_UNLIKELY (src == dst && idxSrc == idxDst)
411 return;
412
413 if constexpr (!SOA)
414 detail::copy_element_aos<T>((T*)dst, (const T*)src, idxDst, idxSrc);
415 else
416 detail::copy_element_soa<T>(dst, src, idxDst, idxSrc, sizeDst, sizeSrc);
417 }
418
429 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
430 void copy_elements(
431 uint8_t* GAIA_RESTRICT dst, const uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
432 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
433 GAIA_ASSERT(idxSrc <= idxDst);
434 if GAIA_UNLIKELY (idxSrc == idxDst)
435 return;
436
437 if constexpr (!SOA)
438 detail::copy_elements_aos<T>((T*)dst, (const T*)src, idxDst, idxSrc);
439 else
440 detail::copy_elements_soa<T>(dst, src, idxDst, idxSrc, sizeDst, sizeSrc);
441 }
442
452 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
453 void move_ctor_element(
454 uint8_t* GAIA_RESTRICT dst, uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
455 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
456 if GAIA_UNLIKELY (src == dst && idxSrc == idxDst)
457 return;
458
459 if constexpr (!SOA) {
460 if constexpr (is_movable<T>())
461 detail::move_ctor_element_aos<T>((T*)dst, (T*)src, idxDst, idxSrc);
462 else
463 detail::copy_ctor_element_aos<T>((T*)dst, (const T*)src, idxDst, idxSrc);
464 } else
465 detail::copy_element_soa<T>(dst, src, idxDst, idxSrc, sizeDst, sizeSrc);
466 }
467
478 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
479 void move_element(
480 uint8_t* GAIA_RESTRICT dst, uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
481 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
482 if GAIA_UNLIKELY (src == dst && idxSrc == idxDst)
483 return;
484
485 if constexpr (!SOA) {
486 if constexpr (is_movable<T>())
487 detail::move_element_aos<T>((T*)dst, (T*)src, idxDst, idxSrc);
488 else
489 detail::copy_element_aos<T>((T*)dst, (const T*)src, idxDst, idxSrc);
490 } else
491 detail::copy_element_soa<T>(dst, src, idxDst, idxSrc, sizeDst, sizeSrc);
492 }
493
504 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
505 void move_elements(
506 uint8_t* GAIA_RESTRICT dst, uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
507 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
508 GAIA_ASSERT(idxSrc <= idxDst);
509 if GAIA_UNLIKELY (idxSrc == idxDst)
510 return;
511
512 if constexpr (!SOA) {
513 if constexpr (is_movable<T>())
514 detail::move_elements_aos<T>((T*)dst, (T*)src, idxDst, idxSrc);
515 else
516 detail::copy_elements_aos<T>((T*)dst, (const T*)src, idxDst, idxSrc);
517 } else
518 detail::copy_elements_soa<T>(dst, src, idxDst, idxSrc, sizeDst, sizeSrc);
519 }
520
530 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
531 void swap_elements(
532 uint8_t* GAIA_RESTRICT dst, uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
533 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
534 if GAIA_UNLIKELY (src == dst && idxSrc == idxDst)
535 return;
536
537 if constexpr (!SOA) {
538 if constexpr (is_movable<T>()) {
539 auto* l = (T*)src;
540 auto* r = (T*)dst;
541 T tmp;
542 detail::move_element_aos<T>(&tmp, l, 0, idxSrc);
543 detail::move_element_aos<T>(l, r, idxSrc, idxDst);
544 detail::move_element_aos<T>(r, &tmp, idxDst, 0);
545 } else {
546 auto* l = (T*)src;
547 auto* r = (T*)dst;
548 T tmp;
549 detail::copy_element_aos<T>(&tmp, l, 0, idxSrc);
550 detail::copy_element_aos<T>(l, r, idxSrc, idxDst);
551 detail::copy_element_aos<T>(r, &tmp, idxDst, 0);
552 }
553 } else {
554 T tmp = mem::data_view_policy_soa_get<T::gaia_Data_Layout, T>{std::span{(const uint8_t*)src, sizeSrc}}[idxSrc];
555 detail::copy_element_soa<T>(src, dst, idxSrc, idxDst, sizeSrc, sizeDst);
556 mem::data_view_policy_soa_set<T::gaia_Data_Layout, T>{std::span{(const uint8_t*)dst, sizeDst}}[idxDst] = tmp;
557 }
558 }
559
567 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
568 void shift_elements_left(uint8_t* dst, uint32_t idxDst, uint32_t idxSrc, [[maybe_unused]] uint32_t size) {
569 GAIA_ASSERT(idxSrc <= idxDst);
570 if GAIA_UNLIKELY (idxSrc == idxDst)
571 return;
572
573 if constexpr (SOA)
574 detail::shift_elements_left_soa<T>(*dst, idxDst, idxSrc, 1, size);
575 else
576 detail::shift_elements_left_aos<T>((T*)dst, idxDst, idxSrc, 1);
577 }
578
587 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
588 void shift_elements_left_fast(
589 uint8_t* dst, uint32_t idxDst, uint32_t idxSrc, uint32_t n, [[maybe_unused]] uint32_t size) {
590 GAIA_ASSERT(idxSrc <= idxDst);
591 if GAIA_UNLIKELY (idxSrc == idxDst)
592 return;
593
594 if constexpr (SOA)
595 detail::shift_elements_left_soa<T>(*dst, idxDst, idxSrc, n, size);
596 else
597 detail::shift_elements_left_aos_fast<T>((T*)dst, idxDst, idxSrc, n);
598 }
599
607 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
608 void shift_elements_right(uint8_t* dst, uint32_t idxDst, uint32_t idxSrc, [[maybe_unused]] uint32_t size) {
609 GAIA_ASSERT(idxSrc <= idxDst);
610 if GAIA_UNLIKELY (idxSrc == idxDst)
611 return;
612
613 if constexpr (SOA)
614 detail::shift_elements_right_soa<T>(*dst, idxDst, idxSrc, 1, size);
615 else
616 detail::shift_elements_right_aos<T>((T*)dst, idxDst, idxSrc, 1);
617 }
618
627 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
628 void shift_elements_right_fast(
629 uint8_t* dst, uint32_t idxDst, uint32_t idxSrc, uint32_t n, [[maybe_unused]] uint32_t size) {
630 GAIA_ASSERT(idxSrc <= idxDst);
631 if GAIA_UNLIKELY (idxSrc == idxDst)
632 return;
633
634 if constexpr (SOA)
635 detail::shift_elements_right_soa<T>(*dst, idxDst, idxSrc, n, size);
636 else
637 detail::shift_elements_right_aos_fast<T>((T*)dst, idxDst, idxSrc, n);
638 }
639
640 GAIA_CLANG_WARNING_POP()
641 } // namespace mem
642} // namespace gaia
Definition span_impl.h:99
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9