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) {
273 template <
typename InputIt>
274 darr_soa(InputIt first, InputIt last) {
275 const auto count = (size_type)core::distance(first, last);
278 if constexpr (std::is_pointer_v<InputIt>) {
279 for (size_type i = 0; i < count; ++i)
280 operator[](i) = first[i];
281 }
else if constexpr (std::is_same_v<typename InputIt::iterator_category, core::random_access_iterator_tag>) {
282 for (size_type i = 0; i < count; ++i)
283 operator[](i) = *(first[i]);
286 for (
auto it = first; it != last; ++it)
287 operator[](++i) = *it;
298 GAIA_ASSERT(m_pData ==
nullptr);
300 m_pData = other.m_pData;
304 other.m_cnt = size_type(0);
305 other.m_cap = size_type(0);
306 other.m_pData =
nullptr;
309 darr_soa& operator=(std::initializer_list<T> il) {
310 *
this =
darr_soa(il.begin(), il.end());
315 GAIA_ASSERT(core::addressof(other) !=
this);
317 resize(other.size());
318 mem::copy_elements<T, true>(
319 (uint8_t*)m_pData, (
const uint8_t*)other.m_pData, other.size(), 0, capacity(), other.capacity());
325 GAIA_ASSERT(core::addressof(other) !=
this);
328 view_policy::template free<Allocator>(m_pData, m_cap, m_cnt);
330 m_pData = other.m_pData;
334 other.m_pData =
nullptr;
335 other.m_cnt = size_type(0);
336 other.m_cap = size_type(0);
342 view_policy::template free<Allocator>(m_pData, m_cap, m_cnt);
345 GAIA_CLANG_WARNING_PUSH()
347 GAIA_CLANG_WARNING_DISABLE(
"-Wcast-align")
349 GAIA_NODISCARD pointer data()
noexcept {
350 return reinterpret_cast<pointer
>(m_pData);
353 GAIA_NODISCARD const_pointer data()
const noexcept {
354 return reinterpret_cast<const_pointer
>(m_pData);
357 GAIA_NODISCARD
decltype(
auto)
operator[](size_type pos)
noexcept {
358 GAIA_ASSERT(pos < size());
359 return view_policy::set({(
typename view_policy::TargetCastType)m_pData, capacity()}, pos);
362 GAIA_NODISCARD
decltype(
auto)
operator[](size_type pos)
const noexcept {
363 GAIA_ASSERT(pos < size());
364 return view_policy::get({(
typename view_policy::TargetCastType)m_pData, capacity()}, pos);
367 GAIA_CLANG_WARNING_POP()
369 void reserve(size_type cap) {
373 auto* pDataOld = m_pData;
374 m_pData = view_policy::template alloc<Allocator>(cap);
376 if (pDataOld !=
nullptr) {
377 view_policy::mem_add_block(m_pData, cap, m_cnt);
378 mem::move_elements<T, true>(m_pData, pDataOld, m_cnt, 0, cap, m_cap);
379 view_policy::template free<Allocator>(pDataOld, m_cap, m_cnt);
385 void resize(size_type count) {
390 if (m_pData ==
nullptr) {
392 m_pData = view_policy::template alloc<Allocator>(count);
393 view_policy::mem_add_block(m_pData, count, count);
402 view_policy::mem_pop_block(m_pData, m_cap, m_cnt, m_cnt - count);
409 if (count <= m_cap) {
410 view_policy::mem_pop_block(m_pData, m_cap, m_cnt, count - m_cnt);
416 auto* pDataOld = m_pData;
417 m_pData = view_policy::template alloc<Allocator>(count);
418 view_policy::mem_add_block(m_pData, count, count);
420 mem::move_elements<T, true>(m_pData, pDataOld, m_cnt, 0, count, m_cap);
422 view_policy::template free<Allocator>(pDataOld, m_cap, m_cnt);
428 void push_back(
const T& arg) {
431 operator[](m_cnt++) = arg;
434 void push_back(T&& arg) {
437 view_policy::mem_push_block(m_pData, m_cap, m_cnt, 1);
438 operator[](m_cnt++) = GAIA_MOV(arg);
441 template <
typename... Args>
442 decltype(
auto) emplace_back(Args&&... args) {
445 view_policy::mem_push_block(m_pData, m_cap, m_cnt, 1);
446 operator[](m_cnt++) = T(GAIA_FWD(args)...);
449 void pop_back()
noexcept {
450 GAIA_ASSERT(!empty());
452 view_policy::mem_pop_block(m_pData, m_cap, m_cnt, 1);
461 GAIA_ASSERT(pos >= data());
462 GAIA_ASSERT(empty() || (pos <
iterator(data() + size())));
464 const auto idxSrc = (size_type)core::distance(begin(), pos);
466 const auto idxDst = (size_type)core::distance(begin(), end()) + 1;
468 view_policy::mem_push_block(m_pData, m_cap, m_cnt, 1);
469 mem::shift_elements_right<T, true>(m_pData, idxDst, idxSrc, m_cap);
471 operator[](idxSrc) = arg;
475 return iterator(m_pData, capacity(), idxSrc);
482 GAIA_ASSERT(pos >= data());
483 GAIA_ASSERT(empty() || (pos <
iterator(data() + size())));
485 const auto idxSrc = (size_type)core::distance(begin(), pos);
487 const auto idxDst = (size_type)core::distance(begin(), end());
489 view_policy::mem_push_block(m_pData, m_cap, m_cnt, 1);
490 mem::shift_elements_right<T, true>(m_pData, idxDst, idxSrc, m_cap);
492 operator[](idxSrc) = GAIA_MOV(arg);
496 return iterator(m_pData, capacity(), idxSrc);
502 GAIA_ASSERT(pos >= data());
503 GAIA_ASSERT(empty() || (pos <
iterator(data() + size())));
508 const auto idxSrc = (size_type)core::distance(begin(), pos);
509 const auto idxDst = (size_type)core::distance(begin(), end()) - 1;
511 mem::shift_elements_left<T, true>(m_pData, idxDst, idxSrc, m_cap);
512 view_policy::mem_pop_block(m_pData, m_cap, m_cnt, 1);
516 return iterator(m_pData, capacity(), idxSrc);
523 GAIA_ASSERT(first >= data())
524 GAIA_ASSERT(empty() || (first <
iterator(data() + size())));
525 GAIA_ASSERT(last > first);
526 GAIA_ASSERT(last <=
iterator(data() + size()));
531 const auto idxSrc = (size_type)core::distance(begin(), first);
532 const auto idxDst = size();
533 const auto cnt = (size_type)(last - first);
535 mem::shift_elements_left_fast<T, true>(m_pData, idxDst, idxSrc, cnt, m_cap);
536 view_policy::mem_pop_block(m_pData, m_cap, m_cnt, cnt);
543 void clear() noexcept {
547 void shrink_to_fit() {
548 const auto cap = capacity();
549 const auto cnt = size();
554 auto* pDataOld = m_pData;
555 m_pData = view_policy::template alloc<Allocator>(m_cap = cnt);
556 view_policy::mem_add_block(m_pData, m_cap, m_cnt);
557 mem::move_elements<T, true>(m_pData, pDataOld, cnt, 0);
558 view_policy::template free<Allocator>(pDataOld, cap, cnt);
564 template <
typename Func>
566 size_type erased = 0;
567 size_type idxDst = 0;
568 size_type idxSrc = 0;
570 while (idxSrc < m_cnt) {
571 if (func(
operator[](idxSrc))) {
572 if (idxDst < idxSrc) {
573 mem::move_element<T, true>(m_pData, m_pData, idxDst, idxSrc, m_cap, m_cap);
574 auto* ptr = &data()[idxSrc];
575 core::call_dtor(ptr);
579 auto* ptr = &data()[idxSrc];
580 core::call_dtor(ptr);
587 view_policy::mem_pop_block(m_pData, m_cap, m_cnt, erased);
593 GAIA_NODISCARD size_type size() const noexcept {
597 GAIA_NODISCARD
bool empty() const noexcept {
601 GAIA_NODISCARD size_type capacity() const noexcept {
605 GAIA_NODISCARD size_type max_size() const noexcept {
606 return static_cast<size_type
>(-1);
609 GAIA_NODISCARD
decltype(
auto) front() noexcept {
610 GAIA_ASSERT(!empty());
614 GAIA_NODISCARD
decltype(
auto) front() const noexcept {
615 GAIA_ASSERT(!empty());
619 GAIA_NODISCARD
decltype(
auto) back() noexcept {
620 GAIA_ASSERT(!empty());
621 return operator[](m_cnt - 1);
624 GAIA_NODISCARD
decltype(
auto) back() const noexcept {
625 GAIA_ASSERT(!empty());
626 return operator[](m_cnt - 1);
629 GAIA_NODISCARD
auto begin() noexcept {
630 return iterator(m_pData, capacity(), 0);
633 GAIA_NODISCARD
auto begin() const noexcept {
634 return const_iterator(m_pData, capacity(), 0);
637 GAIA_NODISCARD
auto cbegin() const noexcept {
638 return const_iterator(m_pData, capacity(), 0);
641 GAIA_NODISCARD
auto rbegin() noexcept {
642 return iterator(m_pData, capacity(), size() - 1);
645 GAIA_NODISCARD
auto rbegin() const noexcept {
646 return const_iterator(m_pData, capacity(), size() - 1);
649 GAIA_NODISCARD
auto crbegin() const noexcept {
650 return const_iterator(m_pData, capacity(), size() - 1);
653 GAIA_NODISCARD
auto end() noexcept {
654 return iterator(m_pData, capacity(), size());
657 GAIA_NODISCARD
auto end() const noexcept {
658 return const_iterator(m_pData, capacity(), size());
661 GAIA_NODISCARD
auto cend() const noexcept {
662 return const_iterator(m_pData, capacity(), size());
665 GAIA_NODISCARD
auto rend() noexcept {
666 return iterator(m_pData, capacity(), -1);
669 GAIA_NODISCARD
auto rend() const noexcept {
670 return const_iterator(m_pData, capacity(), -1);
673 GAIA_NODISCARD
auto crend() const noexcept {
674 return const_iterator(m_pData, capacity(), -1);
677 GAIA_NODISCARD
bool operator==(
const darr_soa& other)
const noexcept {
678 if (m_cnt != other.m_cnt)
680 const size_type n = size();
681 for (size_type i = 0; i < n; ++i)
682 if (!(
operator[](i) == other[i]))
687 GAIA_NODISCARD
constexpr bool operator!=(
const darr_soa& other)
const noexcept {
688 return !operator==(other);
691 template <
size_t Item>
692 auto view_mut() noexcept {
693 return mem::data_view_policy<T::gaia_Data_Layout, T>::template set<Item>(
697 template <
size_t Item>
698 auto view() const noexcept {
699 return mem::data_view_policy<T::gaia_Data_Layout, T>::template get<Item>(