Gaia-ECS v1.0.0
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 {
15 template <typename T>
16 constexpr bool is_copyable() {
17 return std::is_trivially_copyable_v<T> || std::is_trivially_assignable_v<T, T> || //
18 std::is_copy_assignable_v<T> || std::is_copy_constructible_v<T>;
19 }
20
24 template <typename T>
25 constexpr bool is_movable() {
26 return std::is_trivially_move_assignable_v<T> || std::is_trivially_move_constructible_v<T> || //
27 std::is_move_assignable_v<T> || std::is_move_constructible_v<T>;
28 }
29
31 namespace detail {
32 template <typename T>
33 void copy_ctor_element_aos(T* GAIA_RESTRICT dst, const T* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc) {
34 GAIA_MSVC_WARNING_PUSH()
35 GAIA_MSVC_WARNING_DISABLE(6385)
36
37 if constexpr (std::is_trivially_copyable_v<T>) {
38 memcpy(dst + idxDst, src + idxSrc, sizeof(T));
39 } else if constexpr (std::is_copy_assignable_v<T>) {
40 // Prefer assignment path — it can be faster for types with data reuse
41 core::call_ctor(&dst[idxDst]);
42 dst[idxDst] = src[idxSrc];
43 } else {
44 static_assert(std::is_copy_constructible_v<T>);
45 core::call_ctor(&dst[idxDst], T(src[idxSrc]));
46 }
47
48 GAIA_MSVC_WARNING_POP()
49 }
50
51 template <typename T>
52 void copy_element_aos(T* GAIA_RESTRICT dst, const T* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc) {
53 GAIA_MSVC_WARNING_PUSH()
54 GAIA_MSVC_WARNING_DISABLE(6385)
55
56 if constexpr (std::is_trivially_copyable_v<T>) {
57 memcpy(dst + idxDst, src + idxSrc, sizeof(T));
58 } else if constexpr (std::is_copy_assignable_v<T>) {
59 dst[idxDst] = src[idxSrc];
60 } else {
61 static_assert(std::is_copy_constructible_v<T>);
62 dst[idxDst] = T(src[idxSrc]);
63 }
64
65 GAIA_MSVC_WARNING_POP()
66 }
67
68 template <typename T>
69 void copy_elements_aos(T* GAIA_RESTRICT dst, const T* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc) {
70 GAIA_MSVC_WARNING_PUSH()
71 GAIA_MSVC_WARNING_DISABLE(6385)
72
73 GAIA_ASSERT(idxSrc < idxDst);
74
75 const auto cnt = idxDst - idxSrc;
76
77 if constexpr (std::is_trivially_copyable_v<T>) {
78 memcpy(dst + idxSrc, src + idxSrc, sizeof(T) * cnt);
79 } else if constexpr (std::is_copy_assignable_v<T>) {
80 const T* s = src + idxSrc;
81 T* d = dst + idxSrc;
82 GAIA_FOR(cnt) d[i] = s[i];
83 } else {
84 static_assert(std::is_copy_constructible_v<T>);
85 const T* s = src + idxSrc;
86 T* d = dst + idxSrc;
87 GAIA_FOR(cnt) d[i] = T(s[i]);
88 }
89
90 GAIA_MSVC_WARNING_POP()
91 }
92
93 template <typename T>
94 void copy_element_soa(
95 uint8_t* GAIA_RESTRICT dst, const uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
96 uint32_t sizeDst, uint32_t sizeSrc) {
97 GAIA_MSVC_WARNING_PUSH()
98 GAIA_MSVC_WARNING_DISABLE(6385)
99
100 static_assert(mem::is_soa_layout_v<T>);
101
102 (data_view_policy_soa_set<T::gaia_Data_Layout, T>({std::span{dst, sizeDst}}))[idxDst] =
103 (data_view_policy_soa_get<T::gaia_Data_Layout, T>({std::span{(const uint8_t*)src, sizeSrc}}))[idxSrc];
104
105 GAIA_MSVC_WARNING_POP()
106 }
107
108 template <typename T>
109 void copy_elements_soa(
110 uint8_t* GAIA_RESTRICT dst, const uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
111 uint32_t sizeDst, uint32_t sizeSrc) {
112 GAIA_MSVC_WARNING_PUSH()
113 GAIA_MSVC_WARNING_DISABLE(6385)
114
115 static_assert(mem::is_soa_layout_v<T>);
116
117 GAIA_ASSERT(idxSrc < idxDst);
118
119 GAIA_FOR2(idxSrc, idxDst) {
120 (data_view_policy_soa_set<T::gaia_Data_Layout, T>({std::span{dst, sizeDst}}))[i] =
121 (data_view_policy_soa_get<T::gaia_Data_Layout, T>({std::span{(const uint8_t*)src, sizeSrc}}))[i];
122 }
123
124 GAIA_MSVC_WARNING_POP()
125 }
126
127 template <typename T>
128 void move_ctor_element_aos(T* GAIA_RESTRICT dst, T* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc) {
129 GAIA_MSVC_WARNING_PUSH()
130 GAIA_MSVC_WARNING_DISABLE(6385)
131
132 if constexpr (std::is_trivially_move_constructible_v<T> && std::is_trivially_destructible_v<T>) {
133 memcpy(dst + idxDst, src + idxSrc, sizeof(T));
134 } else if constexpr (std::is_move_assignable_v<T>) {
135 core::call_ctor(&dst[idxDst]);
136 dst[idxDst] = GAIA_MOV(src[idxSrc]);
137 } else {
138 static_assert(std::is_move_constructible_v<T>);
139 core::call_ctor(&dst[idxDst], T(GAIA_MOV(src[idxSrc])));
140 }
141
142 GAIA_MSVC_WARNING_POP()
143 }
144
145 template <typename T>
146 void move_element_aos(T* GAIA_RESTRICT dst, T* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc) {
147 GAIA_MSVC_WARNING_PUSH()
148 GAIA_MSVC_WARNING_DISABLE(6385)
149
150 if constexpr (std::is_trivially_move_assignable_v<T>) {
151 memcpy(dst + idxDst, src + idxSrc, sizeof(T));
152 } else if constexpr (std::is_move_assignable_v<T>) {
153 dst[idxDst] = GAIA_MOV(src[idxSrc]);
154 } else {
155 static_assert(std::is_move_constructible_v<T>);
156 dst[idxDst] = T(GAIA_MOV(src[idxSrc]));
157 }
158
159 GAIA_MSVC_WARNING_POP()
160 }
161
162 template <typename T>
163 void move_elements_aos(T* GAIA_RESTRICT dst, T* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc) {
164 GAIA_MSVC_WARNING_PUSH()
165 GAIA_MSVC_WARNING_DISABLE(6385)
166
167 GAIA_ASSERT(idxSrc < idxDst);
168
169 if constexpr (std::is_trivially_move_assignable_v<T>) {
170 memcpy((void*)&dst[idxSrc], (const void*)&src[idxSrc], sizeof(T) * (idxDst - idxSrc));
171 } else if constexpr (std::is_move_assignable_v<T>) {
172 GAIA_FOR2(idxSrc, idxDst) dst[i] = GAIA_MOV(src[i]);
173 } else {
174 static_assert(std::is_move_constructible_v<T>);
175 GAIA_FOR2(idxSrc, idxDst) dst[i] = T(GAIA_MOV(src[i]));
176 }
177
178 GAIA_MSVC_WARNING_POP()
179 }
180
187 template <typename T>
188 void shift_elements_left_aos(T* dst, uint32_t idxDst, uint32_t idxSrc, uint32_t n) {
189 GAIA_MSVC_WARNING_PUSH()
190 GAIA_MSVC_WARNING_DISABLE(6385)
191
192 GAIA_ASSERT(idxSrc < idxDst);
193
194 if constexpr (std::is_trivially_copy_assignable_v<T> || std::is_trivially_move_assignable_v<T>) {
195 memmove((void*)&dst[idxSrc], (const void*)&dst[idxSrc + n], sizeof(T) * (idxDst - idxSrc));
196 }
197 // Move first if possible
198 else if constexpr (std::is_move_assignable_v<T>) {
199 GAIA_FOR2(idxSrc, idxDst) dst[i] = GAIA_MOV(dst[i + n]);
200 } else if constexpr (std::is_move_constructible_v<T>) {
201 GAIA_FOR2(idxSrc, idxDst) dst[i] = T(GAIA_MOV(dst[i + n]));
202 }
203 // Try to copy if moves are not possible
204 else if constexpr (std::is_copy_assignable_v<T>) {
205 GAIA_FOR2(idxSrc, idxDst) dst[i] = dst[i + n];
206 } else if constexpr (std::is_copy_constructible_v<T>) {
207 GAIA_FOR2(idxSrc, idxDst) dst[i] = T(dst[i + n]);
208 } else {
209 GAIA_ASSERT(false && "Not implemented");
210 }
211
212 GAIA_MSVC_WARNING_POP()
213 }
214
222 template <typename T>
223 void shift_elements_left_aos_fast(T* dst, uint32_t idxDst, uint32_t idxSrc, uint32_t n) {
224 GAIA_MSVC_WARNING_PUSH()
225 GAIA_MSVC_WARNING_DISABLE(6385)
226
227 GAIA_ASSERT(idxSrc < idxDst);
228
229 const auto max = idxDst - idxSrc - n;
230
231 if constexpr (std::is_trivially_copy_assignable_v<T> || std::is_trivially_move_assignable_v<T>) {
232 memcpy((void*)&dst[idxSrc], (const void*)&dst[idxSrc + n], sizeof(T) * max);
233 }
234 // Move first if possible
235 else if constexpr (std::is_move_assignable_v<T>) {
236 GAIA_FOR(max) dst[idxSrc + i] = GAIA_MOV(dst[idxSrc + i + n]);
237 } else if constexpr (std::is_move_constructible_v<T>) {
238 GAIA_FOR(max) dst[idxSrc + i] = T(GAIA_MOV(dst[idxSrc + i + n]));
239 }
240 // Try to copy if moves are not possible
241 else if constexpr (std::is_copy_assignable_v<T>) {
242 GAIA_FOR(max) dst[idxSrc + i] = dst[idxSrc + i + n];
243 } else if constexpr (std::is_copy_constructible_v<T>) {
244 GAIA_FOR(max) dst[idxSrc + i] = T(dst[idxSrc + i + n]);
245 } else {
246 GAIA_ASSERT(false && "Not implemented");
247 }
248
249 GAIA_MSVC_WARNING_POP()
250 }
251
259 template <typename T>
260 void shift_elements_left_soa(uint8_t* dst, uint32_t idxDst, uint32_t idxSrc, uint32_t n, uint32_t size) {
261 GAIA_MSVC_WARNING_PUSH()
262 GAIA_MSVC_WARNING_DISABLE(6385)
263
264 static_assert(mem::is_soa_layout_v<T>);
265
266 GAIA_ASSERT(idxSrc < idxDst);
267
268 GAIA_FOR2(idxSrc, idxDst) {
269 (data_view_policy_soa_set<T::gaia_Data_Layout, T>({std::span<uint8_t>{dst, size}}))[i] =
270 (data_view_policy_soa_get<T::gaia_Data_Layout, T>(
271 {std::span<const uint8_t>{(const uint8_t*)dst, size}}))[i + n];
272 }
273
274 GAIA_MSVC_WARNING_POP()
275 }
276
283 template <typename T>
284 void shift_elements_right_aos(T* dst, uint32_t idxDst, uint32_t idxSrc, uint32_t n) {
285 GAIA_MSVC_WARNING_PUSH()
286 GAIA_MSVC_WARNING_DISABLE(6385)
287
288 GAIA_ASSERT(idxSrc < idxDst);
289
290 const auto max = idxDst - idxSrc;
291 const auto idx = idxDst - 1;
292
293 if constexpr (std::is_trivially_copy_assignable_v<T> || std::is_trivially_move_assignable_v<T>) {
294 memmove(dst + idxSrc + n, dst + idxSrc, sizeof(T) * max);
295 }
296 // Move first if possible
297 else if constexpr (std::is_move_assignable_v<T>) {
298 GAIA_FOR(max) dst[idx - i + n] = GAIA_MOV(dst[idx - i]);
299 } else if constexpr (std::is_move_constructible_v<T>) {
300 GAIA_FOR(max) dst[idx - i + n] = T(GAIA_MOV(dst[idx - i]));
301 }
302 // Try to copy if moves are not possible
303 else if constexpr (std::is_copy_assignable_v<T>) {
304 GAIA_FOR(max) dst[idx - i + n] = dst[idx - i];
305 } else if constexpr (std::is_copy_constructible_v<T>) {
306 GAIA_FOR(max) dst[idx - i + n] = T(dst[idx - i]);
307 } else {
308 GAIA_ASSERT(false && "Not implemented");
309 }
310
311 GAIA_MSVC_WARNING_POP()
312 }
313
321 template <typename T>
322 void shift_elements_right_aos_fast(T* dst, uint32_t idxDst, uint32_t idxSrc, uint32_t n) {
323 GAIA_MSVC_WARNING_PUSH()
324 GAIA_MSVC_WARNING_DISABLE(6385)
325
326 GAIA_ASSERT(idxSrc + n < idxDst);
327
328 const auto max = idxDst - idxSrc - n;
329
330 if constexpr (std::is_trivially_copy_assignable_v<T> || std::is_trivially_move_assignable_v<T>) {
331 memcpy(dst + idxSrc + n, dst + idxSrc, sizeof(T) * max);
332 }
333 // Move/copy from the end to avoid overwriting data
334 else if constexpr (std::is_move_assignable_v<T>) {
335 GAIA_FOR(max) dst[idxSrc + i + n] = GAIA_MOV(dst[idxSrc + i]);
336 } else if constexpr (std::is_move_constructible_v<T>) {
337 GAIA_FOR(max) dst[idxSrc + i + n] = T(GAIA_MOV(dst[idxSrc + i]));
338 }
339 // Try to copy if moves are not possible
340 else if constexpr (std::is_copy_assignable_v<T>) {
341 GAIA_FOR(max) dst[idxSrc + i + n] = dst[idxSrc + i];
342 } else if constexpr (std::is_copy_constructible_v<T>) {
343 GAIA_FOR(max) dst[idxSrc + i + n] = T(dst[idxSrc + i]);
344 } else {
345 GAIA_ASSERT(false && "Not implemented");
346 }
347
348 GAIA_MSVC_WARNING_POP()
349 }
350
358 template <typename T>
359 void shift_elements_right_soa(uint8_t* dst, uint32_t idxDst, uint32_t idxSrc, uint32_t n, uint32_t size) {
360 GAIA_MSVC_WARNING_PUSH()
361 GAIA_MSVC_WARNING_DISABLE(6385)
362
363 static_assert(mem::is_soa_layout_v<T>);
364
365 GAIA_ASSERT(idxSrc < idxDst);
366
367 GAIA_FOR2(idxSrc, idxDst) {
368 (data_view_policy_soa_set<T::gaia_Data_Layout, T>({std::span<uint8_t>{dst, size}}))[i + n] =
369 (data_view_policy_soa_get<T::gaia_Data_Layout, T>(
370 {std::span<const uint8_t>{(const uint8_t*)dst, size}}))[i];
371 }
372
373 GAIA_MSVC_WARNING_POP()
374 }
375 } // namespace detail
377
378 GAIA_CLANG_WARNING_PUSH()
379 // Memory is aligned so we can silence this warning
380 GAIA_CLANG_WARNING_DISABLE("-Wcast-align")
381
391 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
392 void copy_ctor_element(
393 uint8_t* GAIA_RESTRICT dst, const uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
394 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
395 if GAIA_UNLIKELY (src == dst && idxSrc == idxDst)
396 return;
397
398 if constexpr (!SOA)
399 detail::copy_ctor_element_aos<T>((T*)dst, (const T*)src, idxDst, idxSrc);
400 else
401 detail::copy_element_soa<T>(dst, src, idxDst, idxSrc, sizeDst, sizeSrc);
402 }
403
414 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
415 void copy_element(
416 uint8_t* GAIA_RESTRICT dst, const uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
417 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
418 if GAIA_UNLIKELY (src == dst && idxSrc == idxDst)
419 return;
420
421 if constexpr (!SOA)
422 detail::copy_element_aos<T>((T*)dst, (const T*)src, idxDst, idxSrc);
423 else
424 detail::copy_element_soa<T>(dst, src, idxDst, idxSrc, sizeDst, sizeSrc);
425 }
426
437 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
438 void copy_elements(
439 uint8_t* GAIA_RESTRICT dst, const uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
440 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
441 GAIA_ASSERT(idxSrc <= idxDst);
442 if GAIA_UNLIKELY (idxSrc == idxDst)
443 return;
444
445 if constexpr (!SOA)
446 detail::copy_elements_aos<T>((T*)dst, (const T*)src, idxDst, idxSrc);
447 else
448 detail::copy_elements_soa<T>(dst, src, idxDst, idxSrc, sizeDst, sizeSrc);
449 }
450
460 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
461 void move_ctor_element(
462 uint8_t* GAIA_RESTRICT dst, uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
463 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
464 if GAIA_UNLIKELY (src == dst && idxSrc == idxDst)
465 return;
466
467 if constexpr (!SOA) {
468 if constexpr (is_movable<T>())
469 detail::move_ctor_element_aos<T>((T*)dst, (T*)src, idxDst, idxSrc);
470 else
471 detail::copy_ctor_element_aos<T>((T*)dst, (const T*)src, idxDst, idxSrc);
472 } else
473 detail::copy_element_soa<T>(dst, src, idxDst, idxSrc, sizeDst, sizeSrc);
474 }
475
486 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
487 void move_element(
488 uint8_t* GAIA_RESTRICT dst, uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
489 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
490 if GAIA_UNLIKELY (src == dst && idxSrc == idxDst)
491 return;
492
493 if constexpr (!SOA) {
494 if constexpr (is_movable<T>())
495 detail::move_element_aos<T>((T*)dst, (T*)src, idxDst, idxSrc);
496 else
497 detail::copy_element_aos<T>((T*)dst, (const T*)src, idxDst, idxSrc);
498 } else
499 detail::copy_element_soa<T>(dst, src, idxDst, idxSrc, sizeDst, sizeSrc);
500 }
501
512 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
513 void move_elements(
514 uint8_t* GAIA_RESTRICT dst, uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
515 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
516 GAIA_ASSERT(idxSrc <= idxDst);
517 if GAIA_UNLIKELY (idxSrc == idxDst)
518 return;
519
520 if constexpr (!SOA) {
521 if constexpr (is_movable<T>())
522 detail::move_elements_aos<T>((T*)dst, (T*)src, idxDst, idxSrc);
523 else
524 detail::copy_elements_aos<T>((T*)dst, (const T*)src, idxDst, idxSrc);
525 } else
526 detail::copy_elements_soa<T>(dst, src, idxDst, idxSrc, sizeDst, sizeSrc);
527 }
528
538 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
539 void swap_elements(
540 uint8_t* GAIA_RESTRICT dst, uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
541 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
542 if GAIA_UNLIKELY (src == dst && idxSrc == idxDst)
543 return;
544
545 if constexpr (!SOA) {
546 if constexpr (is_movable<T>()) {
547 auto* l = (T*)src;
548 auto* r = (T*)dst;
549 T tmp;
550 detail::move_element_aos<T>(&tmp, l, 0, idxSrc);
551 detail::move_element_aos<T>(l, r, idxSrc, idxDst);
552 detail::move_element_aos<T>(r, &tmp, idxDst, 0);
553 } else {
554 auto* l = (T*)src;
555 auto* r = (T*)dst;
556 T tmp;
557 detail::copy_element_aos<T>(&tmp, l, 0, idxSrc);
558 detail::copy_element_aos<T>(l, r, idxSrc, idxDst);
559 detail::copy_element_aos<T>(r, &tmp, idxDst, 0);
560 }
561 } else {
562 T tmp = mem::data_view_policy_soa_get<T::gaia_Data_Layout, T>{std::span{(const uint8_t*)src, sizeSrc}}[idxSrc];
563 detail::copy_element_soa<T>(src, dst, idxSrc, idxDst, sizeSrc, sizeDst);
564 mem::data_view_policy_soa_set<T::gaia_Data_Layout, T>{std::span{(const uint8_t*)dst, sizeDst}}[idxDst] = tmp;
565 }
566 }
567
575 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
576 void shift_elements_left(uint8_t* dst, uint32_t idxDst, uint32_t idxSrc, [[maybe_unused]] uint32_t size) {
577 GAIA_ASSERT(idxSrc <= idxDst);
578 if GAIA_UNLIKELY (idxSrc == idxDst)
579 return;
580
581 if constexpr (SOA)
582 detail::shift_elements_left_soa<T>(*dst, idxDst, idxSrc, 1, size);
583 else
584 detail::shift_elements_left_aos<T>((T*)dst, idxDst, idxSrc, 1);
585 }
586
595 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
596 void shift_elements_left_fast(
597 uint8_t* dst, uint32_t idxDst, uint32_t idxSrc, uint32_t n, [[maybe_unused]] uint32_t size) {
598 GAIA_ASSERT(idxSrc <= idxDst);
599 if GAIA_UNLIKELY (idxSrc == idxDst)
600 return;
601
602 if constexpr (SOA)
603 detail::shift_elements_left_soa<T>(*dst, idxDst, idxSrc, n, size);
604 else
605 detail::shift_elements_left_aos_fast<T>((T*)dst, idxDst, idxSrc, n);
606 }
607
615 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
616 void shift_elements_right(uint8_t* dst, uint32_t idxDst, uint32_t idxSrc, [[maybe_unused]] uint32_t size) {
617 GAIA_ASSERT(idxSrc <= idxDst);
618 if GAIA_UNLIKELY (idxSrc == idxDst)
619 return;
620
621 if constexpr (SOA)
622 detail::shift_elements_right_soa<T>(*dst, idxDst, idxSrc, 1, size);
623 else
624 detail::shift_elements_right_aos<T>((T*)dst, idxDst, idxSrc, 1);
625 }
626
635 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
636 void shift_elements_right_fast(
637 uint8_t* dst, uint32_t idxDst, uint32_t idxSrc, uint32_t n, [[maybe_unused]] uint32_t size) {
638 GAIA_ASSERT(idxSrc <= idxDst);
639 if GAIA_UNLIKELY (idxSrc == idxDst)
640 return;
641
642 if constexpr (SOA)
643 detail::shift_elements_right_soa<T>(*dst, idxDst, idxSrc, n, size);
644 else
645 detail::shift_elements_right_aos_fast<T>((T*)dst, idxDst, idxSrc, n);
646 }
647
648 GAIA_CLANG_WARNING_POP()
649 } // namespace mem
650} // namespace gaia