213 static_assert(mem::is_soa_layout_v<T>,
"darr_soa can be used only with soa types");
216 using value_type = T;
217 using reference = T&;
218 using const_reference =
const T&;
220 using const_pointer =
const T*;
222 using difference_type = darr_soa_detail::difference_type;
223 using size_type = darr_soa_detail::size_type;
230 uint8_t* m_pData =
nullptr;
231 size_type m_cnt = size_type(0);
232 size_type m_cap = size_type(0);
235 const auto cnt = size();
236 const auto cap = capacity();
239 if GAIA_LIKELY (cap != 0 && cnt < cap)
243 if GAIA_UNLIKELY (m_pData ==
nullptr) {
244 m_pData = view_policy::template alloc<Allocator>(m_cap = 4);
250 m_cap = (cap * 3 + 1) / 2;
252 auto* pDataOld = m_pData;
253 m_pData = view_policy::template alloc<Allocator>(m_cap);
254 view_policy::mem_add_block(m_pData, m_cap, cnt);
255 mem::move_elements<T, true>(m_pData, pDataOld, cnt, 0, m_cap, cap);
256 view_policy::template free<Allocator>(pDataOld, cap, cnt);
263 darr_soa(size_type count, const_reference value) {
264 resize(count, value);
271 template <
typename InputIt>
272 darr_soa(InputIt first, InputIt last) {
273 const auto count = (size_type)core::distance(first, last);
276 if constexpr (std::is_pointer_v<InputIt>) {
277 for (size_type i = 0; i < count; ++i)
278 operator[](i) = first[i];
279 }
else if constexpr (std::is_same_v<typename InputIt::iterator_category, core::random_access_iterator_tag>) {
280 for (size_type i = 0; i < count; ++i)
281 operator[](i) = *(first[i]);
284 for (
auto it = first; it != last; ++it)
285 operator[](++i) = *it;
296 GAIA_ASSERT(m_pData ==
nullptr);
298 m_pData = other.m_pData;
302 other.m_cnt = size_type(0);
303 other.m_cap = size_type(0);
304 other.m_pData =
nullptr;
307 darr_soa& operator=(std::initializer_list<T> il) {
308 *
this =
darr_soa(il.begin(), il.end());
313 GAIA_ASSERT(core::addressof(other) !=
this);
315 resize(other.size());
316 mem::copy_elements<T, true>(
317 (uint8_t*)m_pData, (
const uint8_t*)other.m_pData, other.size(), 0, capacity(), other.capacity());
323 GAIA_ASSERT(core::addressof(other) !=
this);
326 view_policy::template free<Allocator>(m_pData, m_cap, m_cnt);
328 m_pData = other.m_pData;
332 other.m_pData =
nullptr;
333 other.m_cnt = size_type(0);
334 other.m_cap = size_type(0);
340 view_policy::template free<Allocator>(m_pData, m_cap, m_cnt);
343 GAIA_CLANG_WARNING_PUSH()
345 GAIA_CLANG_WARNING_DISABLE(
"-Wcast-align")
347 GAIA_NODISCARD pointer data()
noexcept {
348 return reinterpret_cast<pointer
>(m_pData);
351 GAIA_NODISCARD const_pointer data()
const noexcept {
352 return reinterpret_cast<const_pointer
>(m_pData);
355 GAIA_NODISCARD
decltype(
auto)
operator[](size_type pos)
noexcept {
356 GAIA_ASSERT(pos < size());
357 return view_policy::set({(
typename view_policy::TargetCastType)m_pData, capacity()}, pos);
360 GAIA_NODISCARD
decltype(
auto)
operator[](size_type pos)
const noexcept {
361 GAIA_ASSERT(pos < size());
362 return view_policy::get({(
typename view_policy::TargetCastType)m_pData, capacity()}, pos);
365 GAIA_CLANG_WARNING_POP()
367 void reserve(size_type cap) {
371 auto* pDataOld = m_pData;
372 m_pData = view_policy::template alloc<Allocator>(cap);
374 if (pDataOld !=
nullptr) {
375 view_policy::mem_add_block(m_pData, cap, m_cnt);
376 mem::move_elements<T, true>(m_pData, pDataOld, m_cnt, 0, cap, m_cap);
377 view_policy::template free<Allocator>(pDataOld, m_cap, m_cnt);
383 void resize(size_type count) {
388 if (m_pData ==
nullptr) {
390 m_pData = view_policy::template alloc<Allocator>(count);
391 view_policy::mem_add_block(m_pData, count, count);
400 view_policy::mem_pop_block(m_pData, m_cap, m_cnt, m_cnt - count);
407 if (count <= m_cap) {
408 view_policy::mem_pop_block(m_pData, m_cap, m_cnt, count - m_cnt);
414 auto* pDataOld = m_pData;
415 m_pData = view_policy::template alloc<Allocator>(count);
416 view_policy::mem_add_block(m_pData, count, count);
418 mem::move_elements<T, true>(m_pData, pDataOld, m_cnt, 0, count, m_cap);
420 view_policy::template free<Allocator>(pDataOld, m_cap, m_cnt);
426 void resize(size_type count, const_reference value) {
427 const auto oldCount = m_cnt;
430 if constexpr (std::is_copy_constructible_v<value_type>) {
431 const value_type valueCopy = value;
432 for (size_type i = oldCount; i < m_cnt; ++i)
433 operator[](i) = valueCopy;
435 for (size_type i = oldCount; i < m_cnt; ++i)
436 operator[](i) = value;
440 void push_back(
const T& arg) {
443 operator[](m_cnt++) = arg;
446 void push_back(T&& arg) {
449 view_policy::mem_push_block(m_pData, m_cap, m_cnt, 1);
450 operator[](m_cnt++) = GAIA_MOV(arg);
453 template <
typename... Args>
454 decltype(
auto) emplace_back(Args&&... args) {
457 view_policy::mem_push_block(m_pData, m_cap, m_cnt, 1);
458 operator[](m_cnt++) = T(GAIA_FWD(args)...);
461 void pop_back()
noexcept {
462 GAIA_ASSERT(!empty());
464 view_policy::mem_pop_block(m_pData, m_cap, m_cnt, 1);
473 GAIA_ASSERT(pos >= data());
474 GAIA_ASSERT(empty() || (pos <
iterator(data() + size())));
476 const auto idxSrc = (size_type)core::distance(begin(), pos);
478 const auto idxDst = (size_type)core::distance(begin(), end()) + 1;
480 view_policy::mem_push_block(m_pData, m_cap, m_cnt, 1);
481 mem::shift_elements_right<T, true>(m_pData, idxDst, idxSrc, m_cap);
483 operator[](idxSrc) = arg;
487 return iterator(m_pData, capacity(), idxSrc);
494 GAIA_ASSERT(pos >= data());
495 GAIA_ASSERT(empty() || (pos <
iterator(data() + size())));
497 const auto idxSrc = (size_type)core::distance(begin(), pos);
499 const auto idxDst = (size_type)core::distance(begin(), end());
501 view_policy::mem_push_block(m_pData, m_cap, m_cnt, 1);
502 mem::shift_elements_right<T, true>(m_pData, idxDst, idxSrc, m_cap);
504 operator[](idxSrc) = GAIA_MOV(arg);
508 return iterator(m_pData, capacity(), idxSrc);
514 GAIA_ASSERT(pos >= data());
515 GAIA_ASSERT(empty() || (pos <
iterator(data() + size())));
520 const auto idxSrc = (size_type)core::distance(begin(), pos);
521 const auto idxDst = (size_type)core::distance(begin(), end()) - 1;
523 mem::shift_elements_left<T, true>(m_pData, idxDst, idxSrc, m_cap);
524 view_policy::mem_pop_block(m_pData, m_cap, m_cnt, 1);
528 return iterator(m_pData, capacity(), idxSrc);
535 GAIA_ASSERT(first >= data())
536 GAIA_ASSERT(empty() || (first <
iterator(data() + size())));
537 GAIA_ASSERT(last > first);
538 GAIA_ASSERT(last <=
iterator(data() + size()));
543 const auto idxSrc = (size_type)core::distance(begin(), first);
544 const auto idxDst = size();
545 const auto cnt = (size_type)(last - first);
547 mem::shift_elements_left_fast<T, true>(m_pData, idxDst, idxSrc, cnt, m_cap);
548 view_policy::mem_pop_block(m_pData, m_cap, m_cnt, cnt);
555 void clear() noexcept {
559 void shrink_to_fit() {
560 const auto cap = capacity();
561 const auto cnt = size();
566 auto* pDataOld = m_pData;
567 m_pData = view_policy::template alloc<Allocator>(m_cap = cnt);
568 view_policy::mem_add_block(m_pData, m_cap, m_cnt);
569 mem::move_elements<T, true>(m_pData, pDataOld, cnt, 0);
570 view_policy::template free<Allocator>(pDataOld, cap, cnt);
576 template <
typename Func>
578 size_type erased = 0;
579 size_type idxDst = 0;
580 size_type idxSrc = 0;
582 while (idxSrc < m_cnt) {
583 if (func(
operator[](idxSrc))) {
584 if (idxDst < idxSrc) {
585 mem::move_element<T, true>(m_pData, m_pData, idxDst, idxSrc, m_cap, m_cap);
586 auto* ptr = &data()[idxSrc];
587 core::call_dtor(ptr);
591 auto* ptr = &data()[idxSrc];
592 core::call_dtor(ptr);
599 view_policy::mem_pop_block(m_pData, m_cap, m_cnt, erased);
605 GAIA_NODISCARD size_type size() const noexcept {
609 GAIA_NODISCARD
bool empty() const noexcept {
613 GAIA_NODISCARD size_type capacity() const noexcept {
617 GAIA_NODISCARD size_type max_size() const noexcept {
618 return static_cast<size_type
>(-1);
621 GAIA_NODISCARD
decltype(
auto) front() noexcept {
622 GAIA_ASSERT(!empty());
626 GAIA_NODISCARD
decltype(
auto) front() const noexcept {
627 GAIA_ASSERT(!empty());
631 GAIA_NODISCARD
decltype(
auto) back() noexcept {
632 GAIA_ASSERT(!empty());
633 return operator[](m_cnt - 1);
636 GAIA_NODISCARD
decltype(
auto) back() const noexcept {
637 GAIA_ASSERT(!empty());
638 return operator[](m_cnt - 1);
641 GAIA_NODISCARD
auto begin() noexcept {
642 return iterator(m_pData, capacity(), 0);
645 GAIA_NODISCARD
auto begin() const noexcept {
646 return const_iterator(m_pData, capacity(), 0);
649 GAIA_NODISCARD
auto cbegin() const noexcept {
650 return const_iterator(m_pData, capacity(), 0);
653 GAIA_NODISCARD
auto rbegin() noexcept {
654 return iterator(m_pData, capacity(), size() - 1);
657 GAIA_NODISCARD
auto rbegin() const noexcept {
658 return const_iterator(m_pData, capacity(), size() - 1);
661 GAIA_NODISCARD
auto crbegin() const noexcept {
662 return const_iterator(m_pData, capacity(), size() - 1);
665 GAIA_NODISCARD
auto end() noexcept {
666 return iterator(m_pData, capacity(), size());
669 GAIA_NODISCARD
auto end() const noexcept {
670 return const_iterator(m_pData, capacity(), size());
673 GAIA_NODISCARD
auto cend() const noexcept {
674 return const_iterator(m_pData, capacity(), size());
677 GAIA_NODISCARD
auto rend() noexcept {
678 return iterator(m_pData, capacity(), -1);
681 GAIA_NODISCARD
auto rend() const noexcept {
682 return const_iterator(m_pData, capacity(), -1);
685 GAIA_NODISCARD
auto crend() const noexcept {
686 return const_iterator(m_pData, capacity(), -1);
689 GAIA_NODISCARD
bool operator==(
const darr_soa& other)
const noexcept {
690 if (m_cnt != other.m_cnt)
692 const size_type n = size();
693 for (size_type i = 0; i < n; ++i)
694 if (!(
operator[](i) == other[i]))
699 GAIA_NODISCARD
constexpr bool operator!=(
const darr_soa& other)
const noexcept {
700 return !operator==(other);
703 template <
size_t Item>
704 auto view_mut() noexcept {
705 return mem::data_view_policy<T::gaia_Data_Layout, T>::template set<Item>(
709 template <
size_t Item>
710 auto view() const noexcept {
711 return mem::data_view_policy<T::gaia_Data_Layout, T>::template get<Item>(