Gaia-ECS v0.9.3
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/core/iterator.h"
12#include "gaia/core/utility.h"
13#include "gaia/mem/data_layout_policy.h"
14#include "gaia/mem/mem_utils.h"
15#include "gaia/mem/raw_data_holder.h"
16
17namespace gaia {
18 namespace cnt {
19 namespace sarr_ext_detail {
20 using difference_type = uint32_t;
21 using size_type = uint32_t;
22 } // namespace sarr_ext_detail
23
26 template <typename T, sarr_ext_detail::size_type N>
27 class sarr_ext {
28 public:
29 static_assert(N > 0);
30
31 using value_type = T;
32 using reference = T&;
33 using const_reference = const T&;
34 using pointer = T*;
35 using const_pointer = const T*;
37 using difference_type = sarr_ext_detail::difference_type;
38 using size_type = sarr_ext_detail::size_type;
39
40 using iterator = pointer;
41 using const_iterator = const_pointer;
43
44 static constexpr size_t value_size = sizeof(T);
45 static constexpr size_type extent = N;
46 static constexpr uint32_t allocated_bytes = view_policy::get_min_byte_size(0, N);
47
48 private:
50 size_type m_cnt = size_type(0);
51
52 public:
53 constexpr sarr_ext() noexcept = default;
54 constexpr sarr_ext(core::zero_t) noexcept {}
55
56 ~sarr_ext() {
57 core::call_dtor_n(data(), m_cnt);
58 }
59
60 constexpr sarr_ext(size_type count, const_reference value) noexcept {
61 resize(count, value);
62 }
63
64 constexpr sarr_ext(size_type count) noexcept {
65 resize(count);
66 }
67
68 template <typename InputIt>
69 constexpr sarr_ext(InputIt first, InputIt last) noexcept {
70 const auto count = (size_type)core::distance(first, last);
71 resize(count);
72
73 if constexpr (std::is_pointer_v<InputIt>) {
74 for (size_type i = 0; i < count; ++i)
75 operator[](i) = first[i];
76 } else if constexpr (std::is_same_v<typename InputIt::iterator_category, core::random_access_iterator_tag>) {
77 for (size_type i = 0; i < count; ++i)
78 operator[](i) = *(first[i]);
79 } else {
80 size_type i = 0;
81 for (auto it = first; it != last; ++it)
82 operator[](++i) = *it;
83 }
84 }
85
86 constexpr sarr_ext(std::initializer_list<T> il): sarr_ext(il.begin(), il.end()) {}
87
88 constexpr sarr_ext(const sarr_ext& other): sarr_ext(other.begin(), other.end()) {}
89
90 constexpr sarr_ext(sarr_ext&& other) noexcept: m_cnt(other.m_cnt) {
91 GAIA_ASSERT(core::addressof(other) != this);
92
93 core::call_ctor_raw_n(data(), extent);
94 mem::move_elements<T, false>(m_data, other.m_data, other.size(), 0, extent, other.extent);
95
96 other.m_cnt = size_type(0);
97 }
98
99 sarr_ext& operator=(std::initializer_list<T> il) {
100 *this = sarr_ext(il.begin(), il.end());
101 return *this;
102 }
103
104 constexpr sarr_ext& operator=(const sarr_ext& other) {
105 GAIA_ASSERT(core::addressof(other) != this);
106
107 resize(other.size());
108 mem::copy_elements<T, false>(
109 GAIA_ACC((uint8_t*)&m_data[0]), GAIA_ACC((const uint8_t*)&other.m_data[0]), other.size(), 0, extent,
110 other.extent);
111
112 return *this;
113 }
114
115 constexpr sarr_ext& operator=(sarr_ext&& other) noexcept {
116 GAIA_ASSERT(core::addressof(other) != this);
117
118 resize(other.m_cnt);
119 mem::move_elements<T, false>(
120 GAIA_ACC((uint8_t*)&m_data[0]), GAIA_ACC((uint8_t*)&other.m_data[0]), other.size(), 0, extent,
121 other.extent);
122
123 other.m_cnt = size_type(0);
124
125 return *this;
126 }
127
128 GAIA_CLANG_WARNING_PUSH()
129 // Memory is aligned so we can silence this warning
130 GAIA_CLANG_WARNING_DISABLE("-Wcast-align")
131
132 GAIA_NODISCARD constexpr pointer data() noexcept {
133 return GAIA_ACC((pointer)&m_data[0]);
134 }
135
136 GAIA_NODISCARD constexpr const_pointer data() const noexcept {
137 return GAIA_ACC((const_pointer)&m_data[0]);
138 }
139
140 GAIA_NODISCARD constexpr decltype(auto) operator[](size_type pos) noexcept {
141 GAIA_ASSERT(pos < size());
142 return view_policy::set({GAIA_ACC((typename view_policy::TargetCastType) & m_data[0]), extent}, pos);
143 }
144
145 GAIA_NODISCARD constexpr decltype(auto) operator[](size_type pos) const noexcept {
146 GAIA_ASSERT(pos < size());
147 return view_policy::get({GAIA_ACC((typename view_policy::TargetCastType) & m_data[0]), extent}, pos);
148 }
149
150 GAIA_CLANG_WARNING_POP()
151
152 constexpr void push_back(const T& arg) noexcept {
153 GAIA_ASSERT(size() < N);
154
155 auto* ptr = &data()[m_cnt++];
156 core::call_ctor(ptr, arg);
157 }
158
159 constexpr void push_back(T&& arg) noexcept {
160 GAIA_ASSERT(size() < N);
161
162 auto* ptr = &data()[m_cnt++];
163 core::call_ctor(ptr, GAIA_MOV(arg));
164 }
165
166 template <typename... Args>
167 constexpr decltype(auto) emplace_back(Args&&... args) noexcept {
168 GAIA_ASSERT(size() < N);
169
170 auto* ptr = &data()[m_cnt++];
171 core::call_ctor(ptr, GAIA_FWD(args)...);
172 return (reference)*ptr;
173 }
174
175 constexpr void pop_back() noexcept {
176 GAIA_ASSERT(!empty());
177
178 auto* ptr = &data()[m_cnt - 1];
179 core::call_dtor(ptr);
180
181 --m_cnt;
182 }
183
187 iterator insert(iterator pos, const T& arg) noexcept {
188 GAIA_ASSERT(size() < N);
189 GAIA_ASSERT(pos >= data());
190 GAIA_ASSERT(empty() || (pos < iterator(data() + size())));
191
192 const auto idxSrc = (size_type)core::distance(begin(), pos);
193 const auto idxDst = (size_type)core::distance(begin(), end());
194
195 mem::shift_elements_right<T, false>(m_data, idxDst, idxSrc, extent);
196
197 auto* ptr = &data()[idxSrc];
198 core::call_ctor(ptr, arg);
199
200 ++m_cnt;
201
202 return iterator(&data()[idxSrc]);
203 }
204
208 iterator insert(iterator pos, T&& arg) noexcept {
209 GAIA_ASSERT(size() < N);
210 GAIA_ASSERT(pos >= data());
211 GAIA_ASSERT(empty() || (pos < iterator(data() + size())));
212
213 const auto idxSrc = (size_type)core::distance(begin(), pos);
214 const auto idxDst = (size_type)core::distance(begin(), end());
215
216 mem::shift_elements_right<T, false>(m_data, idxDst, idxSrc, extent);
217
218 auto* ptr = &data()[idxSrc];
219 core::call_ctor(ptr, GAIA_MOV(arg));
220
221 ++m_cnt;
222
223 return iterator(&data()[idxSrc]);
224 }
225
228 constexpr iterator erase(iterator pos) noexcept {
229 GAIA_ASSERT(pos >= data());
230 GAIA_ASSERT(empty() || (pos < iterator(data() + size())));
231
232 if (empty())
233 return end();
234
235 const auto idxSrc = (size_type)core::distance(begin(), pos);
236 const auto idxDst = (size_type)core::distance(begin(), end()) - 1;
237
238 mem::shift_elements_left<T, false>(m_data, idxDst, idxSrc, extent);
239 // Destroy if it's the last element
240 auto* ptr = &data()[m_cnt - 1];
241 core::call_dtor(ptr);
242
243 --m_cnt;
244
245 return iterator(&data()[idxSrc]);
246 }
247
251 iterator erase(iterator first, iterator last) noexcept {
252 GAIA_ASSERT(first >= data())
253 GAIA_ASSERT(empty() || (first < iterator(data() + size())));
254 GAIA_ASSERT(last > first);
255 GAIA_ASSERT(last <= (data() + size()));
256
257 if (empty())
258 return end();
259
260 const auto idxSrc = (size_type)core::distance(begin(), first);
261 const auto idxDst = size();
262 const auto cnt = (size_type)(last - first);
263
264 mem::shift_elements_left_fast<T, false>(m_data, idxDst, idxSrc, cnt, extent);
265 // Destroy if it's the last element
266 core::call_dtor_n(&data()[m_cnt - cnt], cnt);
267
268 m_cnt -= cnt;
269
270 return iterator(&data()[idxSrc]);
271 }
272
274 iterator erase_at(size_type pos) noexcept {
275 GAIA_ASSERT(pos < size());
276
277 const auto idxSrc = pos;
278 const auto idxDst = (size_type)core::distance(begin(), end()) - 1;
279
280 mem::shift_elements_left<T, false>(m_data, idxDst, idxSrc, extent);
281 // Destroy if it's the last element
282 auto* ptr = &data()[m_cnt - 1];
283 core::call_dtor(ptr);
284
285 --m_cnt;
286
287 return iterator(&data()[idxSrc]);
288 }
289
290 constexpr void clear() noexcept {
291 resize(0);
292 }
293
294 constexpr void resize(size_type count) noexcept {
295 GAIA_ASSERT(count <= max_size());
296
297 // Resizing to a smaller size
298 if (count <= m_cnt) {
299 // Destroy elements at the end
300 core::call_dtor_n(&data()[count], size() - count);
301 } else
302 // Resizing to a bigger size but still within allocated capacity
303 {
304 // Construct new elements
305 core::call_ctor_n(&data()[size()], count - size());
306 }
307
308 m_cnt = count;
309 }
310
311 constexpr void resize(size_type count, const_reference value) noexcept {
312 const auto oldCount = m_cnt;
313 resize(count);
314
315 if constexpr (std::is_copy_constructible_v<value_type>) {
316 const value_type valueCopy = value;
317 for (size_type i = oldCount; i < m_cnt; ++i)
318 operator[](i) = valueCopy;
319 } else {
320 for (size_type i = oldCount; i < m_cnt; ++i)
321 operator[](i) = value;
322 }
323 }
324
328 template <typename Func>
329 auto retain(Func&& func) noexcept {
330 size_type erased = 0;
331 size_type idxDst = 0;
332 size_type idxSrc = 0;
333
334 while (idxSrc < m_cnt) {
335 if (func(operator[](idxSrc))) {
336 if (idxDst < idxSrc) {
337 auto* ptr = (uint8_t*)data();
338 mem::move_element<T, false>(ptr, ptr, idxDst, idxSrc, max_size(), max_size());
339 auto* ptr2 = &data()[idxSrc];
340 core::call_dtor(ptr2);
341 }
342 ++idxDst;
343 } else {
344 auto* ptr = &data()[idxSrc];
345 core::call_dtor(ptr);
346 ++erased;
347 }
348
349 ++idxSrc;
350 }
351
352 m_cnt -= erased;
353 return idxDst;
354 }
355
356 GAIA_NODISCARD constexpr size_type size() const noexcept {
357 return m_cnt;
358 }
359
360 GAIA_NODISCARD constexpr bool empty() const noexcept {
361 return size() == 0;
362 }
363
364 GAIA_NODISCARD constexpr size_type capacity() const noexcept {
365 return N;
366 }
367
368 GAIA_NODISCARD constexpr size_type max_size() const noexcept {
369 return N;
370 }
371
372 GAIA_NODISCARD constexpr decltype(auto) front() noexcept {
373 GAIA_ASSERT(!empty());
374 return (reference)*begin();
375 }
376
377 GAIA_NODISCARD constexpr decltype(auto) front() const noexcept {
378 GAIA_ASSERT(!empty());
379 return (const_reference)*begin();
380 }
381
382 GAIA_NODISCARD constexpr decltype(auto) back() noexcept {
383 GAIA_ASSERT(!empty());
384 return (reference) operator[](m_cnt - 1);
385 }
386
387 GAIA_NODISCARD constexpr decltype(auto) back() const noexcept {
388 GAIA_ASSERT(!empty());
389 return (const_reference) operator[](m_cnt - 1);
390 }
391
392 GAIA_NODISCARD constexpr auto begin() noexcept {
393 return iterator(data());
394 }
395
396 GAIA_NODISCARD constexpr auto begin() const noexcept {
397 return const_iterator(data());
398 }
399
400 GAIA_NODISCARD constexpr auto cbegin() const noexcept {
401 return const_iterator(data());
402 }
403
404 GAIA_NODISCARD constexpr auto rbegin() noexcept {
405 return iterator((pointer)&back());
406 }
407
408 GAIA_NODISCARD constexpr auto rbegin() const noexcept {
409 return const_iterator((pointer)&back());
410 }
411
412 GAIA_NODISCARD constexpr auto crbegin() const noexcept {
413 return const_iterator((pointer)&back());
414 }
415
416 GAIA_NODISCARD constexpr auto end() noexcept {
417 return iterator(GAIA_ACC((pointer)&m_data[0]) + size());
418 }
419
420 GAIA_NODISCARD constexpr auto end() const noexcept {
421 return const_iterator(GAIA_ACC((const_pointer)&m_data[0]) + size());
422 }
423
424 GAIA_NODISCARD constexpr auto cend() const noexcept {
425 return const_iterator(GAIA_ACC((const_pointer)&m_data[0]) + size());
426 }
427
428 GAIA_NODISCARD constexpr auto rend() noexcept {
429 return iterator(GAIA_ACC((pointer)&m_data[0]) - 1);
430 }
431
432 GAIA_NODISCARD constexpr auto rend() const noexcept {
433 return const_iterator(GAIA_ACC((const_pointer)&m_data[0]) - 1);
434 }
435
436 GAIA_NODISCARD constexpr auto crend() const noexcept {
437 return const_iterator(GAIA_ACC((const_pointer)&m_data[0]) - 1);
438 }
439
440 GAIA_NODISCARD constexpr bool operator==(const sarr_ext& other) const noexcept {
441 if (m_cnt != other.m_cnt)
442 return false;
443 const size_type n = size();
444 for (size_type i = 0; i < n; ++i)
445 if (!(operator[](i) == other[i]))
446 return false;
447 return true;
448 }
449
450 GAIA_NODISCARD constexpr bool operator!=(const sarr_ext& other) const noexcept {
451 return !operator==(other);
452 }
453 };
454
455 namespace detail {
456 template <typename T, uint32_t N, uint32_t... I>
457 constexpr sarr_ext<std::remove_cv_t<T>, N> to_sarray_impl(T (&a)[N], std::index_sequence<I...> /*no_name*/) {
458 return {{a[I]...}};
459 }
460 } // namespace detail
461
462 template <typename T, uint32_t N>
463 constexpr sarr_ext<std::remove_cv_t<T>, N> to_sarray(T (&a)[N]) {
464 return detail::to_sarray_impl(a, std::make_index_sequence<N>{});
465 }
466
467 } // namespace cnt
468
469} // namespace gaia
470
471namespace std {
472 template <typename T, uint32_t N>
473 struct tuple_size<gaia::cnt::sarr_ext<T, N>>: std::integral_constant<uint32_t, N> {};
474
475 template <size_t I, typename T, uint32_t N>
476 struct tuple_element<I, gaia::cnt::sarr_ext<T, N>> {
477 using type = T;
478 };
479} // namespace std
Array of elements of type.
Definition sarray_ext_impl.h:27
constexpr iterator erase(iterator pos) noexcept
Removes the element at pos.
Definition sarray_ext_impl.h:228
iterator insert(iterator pos, const T &arg) noexcept
Insert the element to the position given by iterator pos.
Definition sarray_ext_impl.h:187
iterator erase_at(size_type pos) noexcept
Removes the element at index.
Definition sarray_ext_impl.h:274
auto retain(Func &&func) noexcept
Removes all elements that fail the predicate.
Definition sarray_ext_impl.h:329
iterator insert(iterator pos, T &&arg) noexcept
Insert the element to the position given by iterator pos.
Definition sarray_ext_impl.h:208
iterator erase(iterator first, iterator last) noexcept
Removes the elements in the range [first, last)
Definition sarray_ext_impl.h:251
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9
Definition utility.h:87
View policy for accessing and storing data in the AoS way. Good for random access and when accessing ...
Definition data_layout_policy.h:112
Definition raw_data_holder.h:12