Gaia-ECS v1.0.0
A simple and powerful entity component system
Loading...
Searching...
No Matches
sarray_ext_impl.h
1#pragma once
2#include "gaia/config/config.h"
3
4#include <cstddef>
5#include <initializer_list>
6#include <new>
7#include <tuple>
8#include <type_traits>
9#include <utility>
10
11#include "gaia/cnt/impl/array_utils.h"
12#include "gaia/core/iterator.h"
13#include "gaia/core/utility.h"
14#include "gaia/mem/data_layout_policy.h"
15#include "gaia/mem/mem_utils.h"
16#include "gaia/mem/raw_data_holder.h"
17
18namespace gaia {
19 namespace cnt {
21 namespace sarr_ext_detail {
22 using difference_type = int32_t;
23 using size_type = uint32_t;
24 } // namespace sarr_ext_detail
26
29 template <typename T, sarr_ext_detail::size_type N>
30 class sarr_ext {
31 public:
32 static_assert(N > 0);
33
35 using value_type = T;
37 using reference = T&;
39 using const_reference = const T&;
41 using pointer = T*;
43 using const_pointer = const T*;
47 using difference_type = sarr_ext_detail::difference_type;
49 using size_type = sarr_ext_detail::size_type;
50
61
63 static constexpr size_t value_size = sizeof(T);
65 static constexpr size_type extent = N;
68
69 private:
70 mem::raw_data_holder<T, allocated_bytes> m_data;
71 size_type m_cnt = size_type(0);
72
73 public:
74 constexpr sarr_ext() noexcept = default;
76 constexpr sarr_ext(core::zero_t) noexcept {}
77
78 ~sarr_ext() {
79 core::call_dtor_n(data(), m_cnt);
80 }
81
85 constexpr sarr_ext(size_type count, const_reference value) noexcept {
86 resize(count, value);
87 }
88
91 constexpr sarr_ext(size_type count) noexcept {
92 resize(count);
93 }
94
99 template <typename InputIt>
100 constexpr sarr_ext(InputIt first, InputIt last) noexcept {
101 const auto count = (size_type)core::distance(first, last);
102 resize(count);
103
104 if constexpr (std::is_pointer_v<InputIt>) {
105 for (size_type i = 0; i < count; ++i)
106 operator[](i) = first[i];
107 } else if constexpr (std::is_same_v<typename InputIt::iterator_category, core::random_access_iterator_tag>) {
108 for (size_type i = 0; i < count; ++i)
109 operator[](i) = *(first[i]);
110 } else {
111 size_type i = 0;
112 for (auto it = first; it != last; ++it)
113 operator[](i++) = *it;
114 }
115 }
116
119 constexpr sarr_ext(std::initializer_list<T> il): sarr_ext(il.begin(), il.end()) {}
120
123 constexpr sarr_ext(const sarr_ext& other): sarr_ext(other.begin(), other.end()) {}
124
127 constexpr sarr_ext(sarr_ext&& other) noexcept: m_cnt(other.m_cnt) {
128 GAIA_ASSERT(core::addressof(other) != this);
129
130 core::call_ctor_raw_n(data(), extent);
131 mem::move_elements<T, false>(m_data, other.m_data, other.size(), 0, extent, other.extent);
132
133 other.m_cnt = size_type(0);
134 }
135
139 sarr_ext& operator=(std::initializer_list<T> il) {
140 *this = sarr_ext(il.begin(), il.end());
141 return *this;
142 }
143
147 constexpr sarr_ext& operator=(const sarr_ext& other) {
148 GAIA_ASSERT(core::addressof(other) != this);
149
150 resize(other.size());
151 mem::copy_elements<T, false>(
152 GAIA_ACC((uint8_t*)&m_data[0]), GAIA_ACC((const uint8_t*)&other.m_data[0]), other.size(), 0, extent,
153 other.extent);
154
155 return *this;
156 }
157
161 constexpr sarr_ext& operator=(sarr_ext&& other) noexcept {
162 GAIA_ASSERT(core::addressof(other) != this);
163
164 resize(other.m_cnt);
165 mem::move_elements<T, false>(
166 GAIA_ACC((uint8_t*)&m_data[0]), GAIA_ACC((uint8_t*)&other.m_data[0]), other.size(), 0, extent,
167 other.extent);
168
169 other.m_cnt = size_type(0);
170
171 return *this;
172 }
173
174 GAIA_CLANG_WARNING_PUSH()
175 // Memory is aligned so we can silence this warning
176 GAIA_CLANG_WARNING_DISABLE("-Wcast-align")
177
180 GAIA_NODISCARD constexpr pointer data() noexcept {
181 return GAIA_ACC((pointer)&m_data[0]);
182 }
183
186 GAIA_NODISCARD constexpr const_pointer data() const noexcept {
187 return GAIA_ACC((const_pointer)&m_data[0]);
188 }
189
193 GAIA_NODISCARD constexpr decltype(auto) operator[](size_type pos) noexcept {
194 GAIA_ASSERT(pos < size());
195 return view_policy::set({GAIA_ACC((typename view_policy::TargetCastType) & m_data[0]), extent}, pos);
196 }
197
201 GAIA_NODISCARD constexpr decltype(auto) operator[](size_type pos) const noexcept {
202 GAIA_ASSERT(pos < size());
203 return view_policy::get({GAIA_ACC((typename view_policy::TargetCastType) & m_data[0]), extent}, pos);
204 }
205
206 GAIA_CLANG_WARNING_POP()
207
208
211 GAIA_ASSERT(size() < N);
212
213 auto* ptr = &data()[m_cnt++];
214 core::call_ctor(ptr, arg);
215 }
216
219 constexpr void push_back(T&& arg) noexcept {
220 GAIA_ASSERT(size() < N);
221
222 auto* ptr = &data()[m_cnt++];
223 core::call_ctor(ptr, GAIA_MOV(arg));
224 }
225
230 template <typename... Args>
231 constexpr decltype(auto) emplace_back(Args&&... args) noexcept {
232 GAIA_ASSERT(size() < N);
233
234 auto* ptr = &data()[m_cnt++];
235 core::call_ctor(ptr, GAIA_FWD(args)...);
236 return (reference)*ptr;
237 }
238
240 constexpr void pop_back() noexcept {
241 GAIA_ASSERT(!empty());
242
243 auto* ptr = &data()[m_cnt - 1];
244 core::call_dtor(ptr);
245
246 --m_cnt;
247 }
248
253 iterator insert(iterator pos, const T& arg) noexcept {
254 GAIA_ASSERT(size() < N);
255 GAIA_ASSERT(pos >= data());
256 GAIA_ASSERT(pos <= iterator(data() + size()));
257
258 const auto idxSrc = (size_type)core::distance(begin(), pos);
259 const auto idxDst = (size_type)core::distance(begin(), end());
260
261 T value(arg);
262 auto* ptr = &data()[idxSrc];
263 if (idxSrc == idxDst) {
264 core::call_ctor(ptr, std::move_if_noexcept(value));
265 } else {
266 mem::move_ctor_elements<T>((uint8_t*)&data()[idxDst], (uint8_t*)&data()[idxDst - 1], 1);
267 mem::shift_elements_right<T, false>(m_data, idxDst - 1, idxSrc, extent);
268 mem::move_element<T, false>((uint8_t*)ptr, (uint8_t*)&value, 0, 0, 1, 1);
269 }
270
271 ++m_cnt;
272
273 return iterator(&data()[idxSrc]);
274 }
275
281 GAIA_ASSERT(size() < N);
282 GAIA_ASSERT(pos >= data());
283 GAIA_ASSERT(pos <= iterator(data() + size()));
284
285 const auto idxSrc = (size_type)core::distance(begin(), pos);
286 const auto idxDst = (size_type)core::distance(begin(), end());
287
288 T value(GAIA_MOV(arg));
289 auto* ptr = &data()[idxSrc];
290 if (idxSrc == idxDst) {
291 core::call_ctor(ptr, std::move_if_noexcept(value));
292 } else {
293 mem::move_ctor_elements<T>((uint8_t*)&data()[idxDst], (uint8_t*)&data()[idxDst - 1], 1);
294 mem::shift_elements_right<T, false>(m_data, idxDst - 1, idxSrc, extent);
295 mem::move_element<T, false>((uint8_t*)ptr, (uint8_t*)&value, 0, 0, 1, 1);
296 }
297
298 ++m_cnt;
299
300 return iterator(&data()[idxSrc]);
301 }
302
306 constexpr iterator erase(iterator pos) noexcept {
307 GAIA_ASSERT(pos >= data());
308 GAIA_ASSERT(empty() || (pos < iterator(data() + size())));
309
310 if (empty())
311 return end();
312
313 const auto idxSrc = (size_type)core::distance(begin(), pos);
314 const auto idxDst = (size_type)core::distance(begin(), end()) - 1;
315
316 mem::shift_elements_left<T, false>(m_data, idxDst, idxSrc, extent);
317 // Destroy if it's the last element
318 auto* ptr = &data()[m_cnt - 1];
319 core::call_dtor(ptr);
320
321 --m_cnt;
322
323 return iterator(&data()[idxSrc]);
324 }
325
330 iterator erase(iterator first, iterator last) noexcept {
331 GAIA_ASSERT(first >= data())
332 GAIA_ASSERT(empty() || (first < iterator(data() + size())));
333 GAIA_ASSERT(last > first);
334 GAIA_ASSERT(last <= (data() + size()));
335
336 if (empty())
337 return end();
338
339 const auto idxSrc = (size_type)core::distance(begin(), first);
340 const auto idxDst = size();
341 const auto cnt = (size_type)(last - first);
342
343 mem::shift_elements_left_fast<T, false>(m_data, idxDst, idxSrc, cnt, extent);
344 // Destroy if it's the last element
345 core::call_dtor_n(&data()[m_cnt - cnt], cnt);
346
347 m_cnt -= cnt;
348
349 return iterator(&data()[idxSrc]);
350 }
351
355 GAIA_ASSERT(pos < size());
356
357 const auto idxSrc = pos;
358 const auto idxDst = (size_type)core::distance(begin(), end()) - 1;
359
360 mem::shift_elements_left<T, false>(m_data, idxDst, idxSrc, extent);
361 // Destroy if it's the last element
362 auto* ptr = &data()[m_cnt - 1];
363 core::call_dtor(ptr);
364
365 --m_cnt;
366
367 return iterator(&data()[idxSrc]);
368 }
369
371 constexpr void clear() noexcept {
372 resize(0);
373 }
374
377 constexpr void resize(size_type count) noexcept {
378 GAIA_ASSERT(count <= max_size());
379
380 // Resizing to a smaller size
381 if (count <= m_cnt) {
382 // Destroy elements at the end
383 core::call_dtor_n(&data()[count], size() - count);
384 } else
385 // Resizing to a bigger size but still within allocated capacity
386 {
387 // Construct new elements
388 core::call_ctor_n(&data()[size()], count - size());
389 }
390
391 m_cnt = count;
392 }
393
397 constexpr void resize(size_type count, const_reference value) noexcept {
398 const auto oldCount = m_cnt;
399 resize(count);
400
401 if constexpr (std::is_copy_constructible_v<value_type>) {
402 const value_type valueCopy = value;
403 for (size_type i = oldCount; i < m_cnt; ++i)
404 operator[](i) = valueCopy;
405 } else {
406 for (size_type i = oldCount; i < m_cnt; ++i)
407 operator[](i) = value;
408 }
409 }
410
416 template <typename Func>
417 auto retain(Func&& func) noexcept {
418 return detail::retain_array<false>(*this, m_cnt, func);
419 }
420
423 GAIA_NODISCARD constexpr size_type size() const noexcept {
424 return m_cnt;
425 }
426
429 GAIA_NODISCARD constexpr bool empty() const noexcept {
430 return size() == 0;
431 }
432
435 GAIA_NODISCARD constexpr size_type capacity() const noexcept {
436 return N;
437 }
438
441 GAIA_NODISCARD constexpr size_type max_size() const noexcept {
442 return N;
443 }
444
447 GAIA_NODISCARD constexpr decltype(auto) front() noexcept {
448 GAIA_ASSERT(!empty());
449 return (reference)*begin();
450 }
451
454 GAIA_NODISCARD constexpr decltype(auto) front() const noexcept {
455 GAIA_ASSERT(!empty());
456 return (const_reference)*begin();
457 }
458
461 GAIA_NODISCARD constexpr decltype(auto) back() noexcept {
462 GAIA_ASSERT(!empty());
463 return (reference) operator[](m_cnt - 1);
464 }
465
468 GAIA_NODISCARD constexpr decltype(auto) back() const noexcept {
469 GAIA_ASSERT(!empty());
470 return (const_reference) operator[](m_cnt - 1);
471 }
472
475 GAIA_NODISCARD constexpr auto begin() noexcept {
476 return iterator(data());
477 }
478
481 GAIA_NODISCARD constexpr auto begin() const noexcept {
482 return const_iterator(data());
483 }
484
487 GAIA_NODISCARD constexpr auto cbegin() const noexcept {
488 return const_iterator(data());
489 }
490
493 GAIA_NODISCARD constexpr auto rbegin() noexcept {
494 return reverse_iterator(end());
495 }
496
499 GAIA_NODISCARD constexpr auto rbegin() const noexcept {
500 return const_reverse_iterator(end());
501 }
502
505 GAIA_NODISCARD constexpr auto crbegin() const noexcept {
507 }
508
511 GAIA_NODISCARD constexpr auto end() noexcept {
512 return iterator(data() + size());
513 }
514
517 GAIA_NODISCARD constexpr auto end() const noexcept {
518 return const_iterator(data() + size());
519 }
520
523 GAIA_NODISCARD constexpr auto cend() const noexcept {
524 return const_iterator(data() + size());
525 }
526
529 GAIA_NODISCARD constexpr auto rend() noexcept {
530 return reverse_iterator(begin());
531 }
532
535 GAIA_NODISCARD constexpr auto rend() const noexcept {
537 }
538
541 GAIA_NODISCARD constexpr auto crend() const noexcept {
543 }
544
548 GAIA_NODISCARD constexpr bool operator==(const sarr_ext& other) const noexcept {
549 if (m_cnt != other.m_cnt)
550 return false;
551 const size_type n = size();
552 for (size_type i = 0; i < n; ++i)
553 if (!(operator[](i) == other[i]))
554 return false;
555 return true;
556 }
557
561 GAIA_NODISCARD constexpr bool operator!=(const sarr_ext& other) const noexcept {
562 return !operator==(other);
563 }
564 };
565
567 namespace detail {
568 template <typename T, uint32_t N, uint32_t... I>
569 constexpr sarr_ext<std::remove_cv_t<T>, N> to_sarray_impl(T (&a)[N], std::index_sequence<I...> /*no_name*/) {
570 return {{a[I]...}};
571 }
572 } // namespace detail
574
580 template <typename T, uint32_t N>
581 constexpr sarr_ext<std::remove_cv_t<T>, N> to_sarray(T (&a)[N]) {
582 return detail::to_sarray_impl(a, std::make_index_sequence<N>{});
583 }
584
585 } // namespace cnt
586
587 namespace core {
589 template <typename T, cnt::sarr_ext_detail::size_type N>
590 struct fixed_capacity<cnt::sarr_ext<T, N>>: std::integral_constant<uint32_t, (uint32_t)N> {};
591 } // namespace core
592
593} // namespace gaia
594
596namespace std {
597 template <typename T, uint32_t N>
598 struct tuple_size<gaia::cnt::sarr_ext<T, N>>: std::integral_constant<uint32_t, N> {};
599
600 template <size_t I, typename T, uint32_t N>
601 struct tuple_element<I, gaia::cnt::sarr_ext<T, N>> {
602 using type = T;
603 };
604} // namespace std
Array of elements of type.
Definition darray_ext_impl.h:31
GAIA_NODISCARD size_type size() const noexcept
Returns the number of elements.
Definition darray_ext_impl.h:561
GAIA_NODISCARD auto begin() noexcept
Returns an iterator to the first element.
Definition darray_ext_impl.h:613
GAIA_NODISCARD auto end() noexcept
Returns an iterator one past the last element.
Definition darray_ext_impl.h:649
darr_ext_detail::size_type size_type
Unsigned type used for sizes and indices.
Definition darray_ext_impl.h:50
static constexpr size_type extent
Fixed capacity of the container.
Definition darray_ext_impl.h:66
darr_ext_detail::difference_type difference_type
Type used for iterator differences.
Definition darray_ext_impl.h:48
Array of elements of type.
Definition sarray_ext_impl.h:30
constexpr sarr_ext(size_type count) noexcept
Constructs a container with the requested number of value-initialized elements.
Definition sarray_ext_impl.h:91
GAIA_NODISCARD constexpr decltype(auto) back() noexcept
Accesses the last element.
Definition sarray_ext_impl.h:461
GAIA_NODISCARD constexpr bool operator!=(const sarr_ext &other) const noexcept
Checks whether two containers differ.
Definition sarray_ext_impl.h:561
GAIA_NODISCARD constexpr auto cbegin() const noexcept
Returns a read-only iterator to the first element.
Definition sarray_ext_impl.h:487
constexpr void clear() noexcept
Removes all elements.
Definition sarray_ext_impl.h:371
core::reverse_iterator< iterator, difference_type > reverse_iterator
Mutable reverse random-access iterator type.
Definition sarray_ext_impl.h:56
constexpr void push_back(const T &arg) noexcept
Appends an element.
Definition sarray_ext_impl.h:210
sarr_ext & operator=(std::initializer_list< T > il)
Replaces the elements from an initializer list.
Definition sarray_ext_impl.h:139
core::reverse_iterator< const_iterator, difference_type > const_reverse_iterator
Read-only reverse random-access iterator type.
Definition sarray_ext_impl.h:58
pointer iterator
Mutable random-access iterator type.
Definition sarray_ext_impl.h:52
constexpr iterator erase(iterator pos) noexcept
Removes the element at pos.
Definition sarray_ext_impl.h:306
T * pointer
Mutable element pointer type.
Definition sarray_ext_impl.h:41
constexpr sarr_ext & operator=(sarr_ext &&other) noexcept
Move-assigns the container.
Definition sarray_ext_impl.h:161
GAIA_NODISCARD constexpr auto crend() const noexcept
Returns the read-only reverse traversal sentinel preceding the first element.
Definition sarray_ext_impl.h:541
constexpr sarr_ext(InputIt first, InputIt last) noexcept
Constructs a container from an iterator range.
Definition sarray_ext_impl.h:100
sarr_ext_detail::difference_type difference_type
Type used for iterator differences.
Definition sarray_ext_impl.h:47
GAIA_NODISCARD constexpr const_pointer data() const noexcept
Returns a pointer to the element storage.
Definition sarray_ext_impl.h:186
GAIA_NODISCARD constexpr auto begin() const noexcept
Returns an iterator to the first element.
Definition sarray_ext_impl.h:481
iterator insert(iterator pos, const T &arg) noexcept
Insert the element to the position given by iterator pos.
Definition sarray_ext_impl.h:253
static constexpr size_t value_size
Size of one element in bytes.
Definition sarray_ext_impl.h:63
constexpr sarr_ext(std::initializer_list< T > il)
Constructs a container from an initializer list.
Definition sarray_ext_impl.h:119
constexpr void pop_back() noexcept
Removes the last element.
Definition sarray_ext_impl.h:240
GAIA_NODISCARD constexpr auto begin() noexcept
Returns an iterator to the first element.
Definition sarray_ext_impl.h:475
const T * const_pointer
Read-only element pointer type.
Definition sarray_ext_impl.h:43
GAIA_NODISCARD constexpr auto rend() const noexcept
Returns the reverse traversal sentinel preceding the first element.
Definition sarray_ext_impl.h:535
constexpr void push_back(T &&arg) noexcept
Appends an element.
Definition sarray_ext_impl.h:219
iterator erase_at(size_type pos) noexcept
Definition sarray_ext_impl.h:354
GAIA_NODISCARD constexpr auto end() noexcept
Returns an iterator one past the last element.
Definition sarray_ext_impl.h:511
GAIA_NODISCARD constexpr size_type capacity() const noexcept
Returns the number of elements that fit without reallocation.
Definition sarray_ext_impl.h:435
GAIA_NODISCARD constexpr bool empty() const noexcept
Checks whether the container has no elements.
Definition sarray_ext_impl.h:429
constexpr void resize(size_type count, const_reference value) noexcept
Changes the size and initializes new elements from a value.
Definition sarray_ext_impl.h:397
GAIA_NODISCARD constexpr decltype(auto) operator[](size_type pos) noexcept
Accesses an element without bounds checking in optimized builds.
Definition sarray_ext_impl.h:193
auto retain(Func &&func) noexcept
Removes all elements that fail the predicate. The predicate may modify its element but must not chang...
Definition sarray_ext_impl.h:417
GAIA_NODISCARD constexpr auto crbegin() const noexcept
Returns a read-only reverse traversal iterator to the last element.
Definition sarray_ext_impl.h:505
GAIA_NODISCARD constexpr pointer data() noexcept
Returns a pointer to the element storage.
Definition sarray_ext_impl.h:180
constexpr sarr_ext(sarr_ext &&other) noexcept
Move-constructs a container.
Definition sarray_ext_impl.h:127
constexpr sarr_ext & operator=(const sarr_ext &other)
Copy-assigns the container.
Definition sarray_ext_impl.h:147
GAIA_NODISCARD constexpr auto end() const noexcept
Returns an iterator one past the last element.
Definition sarray_ext_impl.h:517
GAIA_NODISCARD constexpr bool operator==(const sarr_ext &other) const noexcept
Compares two containers element by element.
Definition sarray_ext_impl.h:548
iterator insert(iterator pos, T &&arg) noexcept
Insert the element to the position given by iterator pos.
Definition sarray_ext_impl.h:280
static constexpr size_type extent
Fixed capacity of the container.
Definition sarray_ext_impl.h:65
GAIA_NODISCARD constexpr auto rbegin() noexcept
Returns a reverse traversal iterator to the last element.
Definition sarray_ext_impl.h:493
GAIA_NODISCARD constexpr auto cend() const noexcept
Returns a read-only iterator one past the last element.
Definition sarray_ext_impl.h:523
constexpr void resize(size_type count) noexcept
Changes the number of elements.
Definition sarray_ext_impl.h:377
GAIA_NODISCARD constexpr size_type max_size() const noexcept
Returns the maximum number of elements supported by this container.
Definition sarray_ext_impl.h:441
const_pointer const_iterator
Read-only random-access iterator type.
Definition sarray_ext_impl.h:54
GAIA_NODISCARD constexpr decltype(auto) back() const noexcept
Accesses the last element.
Definition sarray_ext_impl.h:468
iterator erase(iterator first, iterator last) noexcept
Removes the elements in the range [first, last)
Definition sarray_ext_impl.h:330
GAIA_NODISCARD constexpr decltype(auto) front() const noexcept
Accesses the first element.
Definition sarray_ext_impl.h:454
GAIA_NODISCARD constexpr size_type size() const noexcept
Returns the number of elements.
Definition sarray_ext_impl.h:423
GAIA_NODISCARD constexpr auto rbegin() const noexcept
Returns a reverse traversal iterator to the last element.
Definition sarray_ext_impl.h:499
GAIA_NODISCARD constexpr decltype(auto) front() noexcept
Accesses the first element.
Definition sarray_ext_impl.h:447
constexpr sarr_ext(const sarr_ext &other)
Copy-constructs a container.
Definition sarray_ext_impl.h:123
static constexpr uint32_t allocated_bytes
Number of bytes reserved by the inline storage.
Definition sarray_ext_impl.h:67
sarr_ext_detail::size_type size_type
Unsigned type used for sizes and indices.
Definition sarray_ext_impl.h:49
constexpr sarr_ext(size_type count, const_reference value) noexcept
Constructs a container with copies of a value.
Definition sarray_ext_impl.h:85
GAIA_NODISCARD constexpr auto rend() noexcept
Returns the reverse traversal sentinel preceding the first element.
Definition sarray_ext_impl.h:529
constexpr decltype(auto) emplace_back(Args &&... args) noexcept
Constructs and appends an element.
Definition sarray_ext_impl.h:231
Random-access iterator that traverses an underlying iterator in reverse. The stored iterator denotes ...
Definition iterator.h:24
Compile-time capacity of a container that can never grow. Zero for containers that can....
Definition utility.h:44
View policy for accessing and storing data in the AoS way. Good for random access and when accessing ...
Definition data_layout_policy.h:160
static GAIA_NODISCARD constexpr uint32_t get_min_byte_size(uintptr_t addr, size_t cnt) noexcept
Calculates the bytes required for a value range.
Definition data_layout_policy.h:173
std::add_pointer_t< ValueType > TargetCastType
Pointer type used to address stored values.
Definition data_layout_policy.h:162
GAIA_NODISCARD static constexpr ValueType & set(std::span< ValueType > s, size_t idx) noexcept
Returns a mutable value reference from an AoS span.
Definition data_layout_policy.h:234
GAIA_NODISCARD static constexpr const ValueType & get(std::span< const ValueType > s, size_t idx) noexcept
Returns a read-only value reference from an AoS span.
Definition data_layout_policy.h:226