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