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 memmove((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 const auto count = idxDst - idxSrc;
368 GAIA_FOR(count) {
369 const auto idx = idxDst - i - 1;
370 (data_view_policy_soa_set<T::gaia_Data_Layout, T>({std::span<uint8_t>{dst, size}}))[idx + n] =
371 (data_view_policy_soa_get<T::gaia_Data_Layout, T>(
372 {std::span<const uint8_t>{(const uint8_t*)dst, size}}))[idx];
373 }
374
375 GAIA_MSVC_WARNING_POP()
376 }
377 } // namespace detail
379
380 GAIA_CLANG_WARNING_PUSH()
381 // Memory is aligned so we can silence this warning
382 GAIA_CLANG_WARNING_DISABLE("-Wcast-align")
383
393 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
394 void copy_ctor_element(
395 uint8_t* GAIA_RESTRICT dst, const uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
396 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
397 if GAIA_UNLIKELY (src == dst && idxSrc == idxDst)
398 return;
399
400 if constexpr (!SOA)
401 detail::copy_ctor_element_aos<T>((T*)dst, (const T*)src, idxDst, idxSrc);
402 else
403 detail::copy_element_soa<T>(dst, src, idxDst, idxSrc, sizeDst, sizeSrc);
404 }
405
416 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
417 void copy_element(
418 uint8_t* GAIA_RESTRICT dst, const uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
419 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
420 if GAIA_UNLIKELY (src == dst && idxSrc == idxDst)
421 return;
422
423 if constexpr (!SOA)
424 detail::copy_element_aos<T>((T*)dst, (const T*)src, idxDst, idxSrc);
425 else
426 detail::copy_element_soa<T>(dst, src, idxDst, idxSrc, sizeDst, sizeSrc);
427 }
428
439 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
440 void copy_elements(
441 uint8_t* GAIA_RESTRICT dst, const uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
442 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
443 GAIA_ASSERT(idxSrc <= idxDst);
444 if GAIA_UNLIKELY (idxSrc == idxDst)
445 return;
446
447 if constexpr (!SOA)
448 detail::copy_elements_aos<T>((T*)dst, (const T*)src, idxDst, idxSrc);
449 else
450 detail::copy_elements_soa<T>(dst, src, idxDst, idxSrc, sizeDst, sizeSrc);
451 }
452
463 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
464 void move_ctor_element(
465 uint8_t* GAIA_RESTRICT dst, uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
466 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
467 if GAIA_UNLIKELY (src == dst && idxSrc == idxDst)
468 return;
469
470 if constexpr (!SOA) {
471 if constexpr (is_movable<T>())
472 detail::move_ctor_element_aos<T>((T*)dst, (T*)src, idxDst, idxSrc);
473 else
474 detail::copy_ctor_element_aos<T>((T*)dst, (const T*)src, idxDst, idxSrc);
475 } else
476 detail::copy_element_soa<T>(dst, src, idxDst, idxSrc, sizeDst, sizeSrc);
477 }
478
490 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
491 void move_element(
492 uint8_t* dst, uint8_t* src, uint32_t idxDst, uint32_t idxSrc,
493 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
494 if GAIA_UNLIKELY (src == dst && idxSrc == idxDst)
495 return;
496
497 if constexpr (!SOA) {
498 if constexpr (is_movable<T>())
499 detail::move_element_aos<T>((T*)dst, (T*)src, idxDst, idxSrc);
500 else
501 detail::copy_element_aos<T>((T*)dst, (const T*)src, idxDst, idxSrc);
502 } else
503 detail::copy_element_soa<T>(dst, src, idxDst, idxSrc, sizeDst, sizeSrc);
504 }
505
518 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
519 void move_elements(
520 uint8_t* GAIA_RESTRICT dst, uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
521 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
522 GAIA_ASSERT(idxSrc <= idxDst);
523 if GAIA_UNLIKELY (idxSrc == idxDst)
524 return;
525
526 if constexpr (!SOA) {
527 if constexpr (is_movable<T>())
528 detail::move_elements_aos<T>((T*)dst, (T*)src, idxDst, idxSrc);
529 else
530 detail::copy_elements_aos<T>((T*)dst, (const T*)src, idxDst, idxSrc);
531 } else
532 detail::copy_elements_soa<T>(dst, src, idxDst, idxSrc, sizeDst, sizeSrc);
533 }
534
541 template <typename T>
542 void move_ctor_elements(uint8_t* dst, uint8_t* src, uint32_t count) {
543 if (count == 0)
544 return;
545 if constexpr (std::is_trivially_copyable_v<T>) {
546 memcpy(dst, src, sizeof(T) * count);
547 } else {
548 GAIA_FOR(count) {
549 if constexpr (std::is_move_constructible_v<T>)
550 core::call_ctor(&((T*)dst)[i], GAIA_MOV(((T*)src)[i]));
551 else if constexpr (std::is_copy_constructible_v<T>)
552 core::call_ctor(&((T*)dst)[i], ((const T*)src)[i]);
553 else
554 move_ctor_element<T, false>(dst, src, i, i, count, count);
555 }
556 }
557 }
558
568 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
569 void swap_elements(
570 uint8_t* GAIA_RESTRICT dst, uint8_t* GAIA_RESTRICT src, uint32_t idxDst, uint32_t idxSrc,
571 [[maybe_unused]] uint32_t sizeDst, [[maybe_unused]] uint32_t sizeSrc) {
572 if GAIA_UNLIKELY (src == dst && idxSrc == idxDst)
573 return;
574
575 if constexpr (!SOA) {
576 if constexpr (is_movable<T>()) {
577 auto* l = (T*)src;
578 auto* r = (T*)dst;
579 T tmp;
580 detail::move_element_aos<T>(&tmp, l, 0, idxSrc);
581 detail::move_element_aos<T>(l, r, idxSrc, idxDst);
582 detail::move_element_aos<T>(r, &tmp, idxDst, 0);
583 } else {
584 auto* l = (T*)src;
585 auto* r = (T*)dst;
586 T tmp;
587 detail::copy_element_aos<T>(&tmp, l, 0, idxSrc);
588 detail::copy_element_aos<T>(l, r, idxSrc, idxDst);
589 detail::copy_element_aos<T>(r, &tmp, idxDst, 0);
590 }
591 } else {
592 T tmp = mem::data_view_policy_soa_get<T::gaia_Data_Layout, T>{std::span{(const uint8_t*)src, sizeSrc}}[idxSrc];
593 detail::copy_element_soa<T>(src, dst, idxSrc, idxDst, sizeSrc, sizeDst);
594 mem::data_view_policy_soa_set<T::gaia_Data_Layout, T>{std::span{(const uint8_t*)dst, sizeDst}}[idxDst] = tmp;
595 }
596 }
597
605 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
606 void shift_elements_left(uint8_t* dst, uint32_t idxDst, uint32_t idxSrc, [[maybe_unused]] uint32_t size) {
607 GAIA_ASSERT(idxSrc <= idxDst);
608 if GAIA_UNLIKELY (idxSrc == idxDst)
609 return;
610
611 if constexpr (SOA)
612 detail::shift_elements_left_soa<T>(dst, idxDst, idxSrc, 1, size);
613 else
614 detail::shift_elements_left_aos<T>((T*)dst, idxDst, idxSrc, 1);
615 }
616
625 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
626 void shift_elements_left_fast(
627 uint8_t* dst, uint32_t idxDst, uint32_t idxSrc, uint32_t n, [[maybe_unused]] uint32_t size) {
628 GAIA_ASSERT(idxSrc <= idxDst);
629 if GAIA_UNLIKELY (idxSrc == idxDst)
630 return;
631
632 if constexpr (SOA) {
633 if (idxSrc + n < idxDst)
634 detail::shift_elements_left_soa<T>(dst, idxDst - n, idxSrc, n, size);
635 } else
636 detail::shift_elements_left_aos_fast<T>((T*)dst, idxDst, idxSrc, n);
637 }
638
646 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
647 void shift_elements_right(uint8_t* dst, uint32_t idxDst, uint32_t idxSrc, [[maybe_unused]] uint32_t size) {
648 GAIA_ASSERT(idxSrc <= idxDst);
649 if GAIA_UNLIKELY (idxSrc == idxDst)
650 return;
651
652 if constexpr (SOA)
653 detail::shift_elements_right_soa<T>(dst, idxDst, idxSrc, 1, size);
654 else
655 detail::shift_elements_right_aos<T>((T*)dst, idxDst, idxSrc, 1);
656 }
657
666 template <typename T, bool SOA = mem::is_soa_layout_v<T>>
667 void shift_elements_right_fast(
668 uint8_t* dst, uint32_t idxDst, uint32_t idxSrc, uint32_t n, [[maybe_unused]] uint32_t size) {
669 GAIA_ASSERT(idxSrc <= idxDst);
670 if GAIA_UNLIKELY (idxSrc == idxDst)
671 return;
672
673 if constexpr (SOA)
674 detail::shift_elements_right_soa<T>(dst, idxDst, idxSrc, n, size);
675 else
676 detail::shift_elements_right_aos_fast<T>((T*)dst, idxDst, idxSrc, n);
677 }
678
679 GAIA_CLANG_WARNING_POP()
680 } // namespace mem
681} // namespace gaia