218 using data_type = std::tuple<std::vector<Ts>...>;
220 template <
class... Us>
221 using zip_view_type = std::ranges::zip_view<std::ranges::ref_view<Us>...>;
223 using value_type = std::tuple<Ts...>;
224 using size_type = std::size_t;
225 using difference_type = std::ptrdiff_t;
226 using reference = std::tuple<Ts&...>;
227 using const_reference = std::tuple<Ts
const&...>;
228 using iterator = std::ranges::iterator_t<zip_view_type<std::vector<Ts>...>>;
229 using const_iterator = std::ranges::iterator_t<zip_view_type<std::vector<Ts>
const...>>;
230 using reverse_iterator = std::reverse_iterator<iterator>;
231 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
233 template <
class... Us>
234 requires(0 <
sizeof...(Us))
240 using indices = std::index_sequence_for<Ts...>;
249 constexpr SoA()
noexcept =
default;
251 constexpr explicit SoA(size_type count) { resize(count); }
253 constexpr SoA(size_type count, value_type
const& value) { resize(count, value); }
255 template <std::input_iterator InputIt>
256 constexpr SoA(InputIt first, InputIt last)
261 template <std::ranges::input_range R>
262 constexpr SoA(std::from_range_t, R&& range)
264 assign_range(std::forward<R>(range));
267 constexpr SoA(std::vector<Ts>... vecs) : data_(std::move(vecs)...) {}
269 constexpr SoA(
SoA const& other) =
default;
271 constexpr SoA(
SoA&& other)
noexcept =
default;
273 constexpr SoA(std::initializer_list<value_type> init) :
SoA(init.begin(), init.end()) {}
275 template <
class... Args>
276 requires(0 <
sizeof...(Args)) &&
277 (
requires { detail::wrap_data(std::declval<Args>()); } && ...)
278 constexpr SoA(Args&&... args)
279 : data_(std::tuple_cat(detail::wrap_data(std::forward<Args>(args))...))
281 if constexpr (
sizeof...(Args) > 1) {
282 size_type
const s = size();
283 auto const check = [s](
auto const& vec) {
284 if (vec.size() != s) {
285 throw std::invalid_argument(
"SoA: merged components must have the same size");
288 std::apply([&check](
auto const&... vecs) { (check(vecs), ...); }, data_);
298 constexpr ~SoA() =
default;
306 constexpr SoA& operator=(
SoA const& rhs) =
default;
308 constexpr SoA& operator=(
SoA&& rhs)
noexcept =
default;
310 constexpr SoA& operator=(std::initializer_list<value_type> ilist)
322 constexpr void assign(size_type count, value_type
const& value)
324 assign_impl(count, value, indices{});
327 template <std::input_iterator I, std::sentinel_for<I> S>
328 constexpr void assign(I first, S last)
330 assign_range(std::ranges::subrange(first, last));
333 constexpr void assign(std::initializer_list<value_type> ilist)
335 assign(ilist.begin(), ilist.end());
338 template <std::ranges::input_range R>
339 requires(std::same_as<std::ranges::range_value_t<R>, value_type>)
340 constexpr void assign_range(R&& range)
342 assign_range_impl(std::forward<R>(range), std::make_index_sequence<
sizeof...(Ts)>{});
352 [[nodiscard]]
constexpr std::span<T> view()
354 return std::span{std::get<std::vector<T>>(data_)};
358 [[nodiscard]]
constexpr std::span<T const> view()
const
360 return std::span{std::get<std::vector<T>>(data_)};
363 template <std::
size_t I>
364 [[nodiscard]]
constexpr std::span<std::tuple_element_t<I, value_type>> view()
366 return std::span{std::get<I>(data_)};
369 template <std::
size_t I>
370 [[nodiscard]]
constexpr std::span<std::tuple_element_t<I, value_type>
const> view()
373 return std::span{std::get<I>(data_)};
382 [[nodiscard]]
constexpr reference operator[](size_type pos)
384 return operator[](pos, indices{});
387 [[nodiscard]]
constexpr const_reference operator[](size_type pos)
const
389 return operator[](pos, indices{});
392 [[nodiscard]]
constexpr reference at(size_type pos)
395 return operator[](pos);
398 [[nodiscard]]
constexpr const_reference at(size_type pos)
const
401 return operator[](pos);
404 [[nodiscard]]
constexpr reference front() {
return operator[](0u); }
406 [[nodiscard]]
constexpr const_reference front()
const {
return operator[](0u); }
408 [[nodiscard]]
constexpr reference back() {
return operator[](size() - 1); }
410 [[nodiscard]]
constexpr const_reference back()
const {
return operator[](size() - 1); }
412 [[nodiscard]]
constexpr data_type* data()
noexcept {
return &data_; }
414 [[nodiscard]]
constexpr data_type
const* data()
const noexcept {
return &data_; }
422 [[nodiscard]]
constexpr iterator begin()
noexcept {
return get_view().begin(); }
424 [[nodiscard]]
constexpr const_iterator begin()
const noexcept
426 return get_view().begin();
429 [[nodiscard]]
constexpr const_iterator cbegin()
const noexcept {
return begin(); }
431 [[nodiscard]]
constexpr iterator end()
noexcept {
return get_view().end(); }
433 [[nodiscard]]
constexpr const_iterator end()
const noexcept {
return get_view().end(); }
435 [[nodiscard]]
constexpr const_iterator cend()
const noexcept {
return end(); }
437 [[nodiscard]]
constexpr reverse_iterator rbegin()
noexcept
439 return reverse_iterator(end());
442 [[nodiscard]]
constexpr const_reverse_iterator rbegin()
const noexcept
444 return const_reverse_iterator(end());
447 [[nodiscard]]
constexpr const_reverse_iterator crbegin()
const noexcept
452 [[nodiscard]]
constexpr reverse_iterator rend()
noexcept
454 return reverse_iterator(begin());
457 [[nodiscard]]
constexpr const_reverse_iterator rend()
const noexcept
459 return const_reverse_iterator(begin());
462 [[nodiscard]]
constexpr const_reverse_iterator crend()
const noexcept {
return rend(); }
470 [[nodiscard]]
constexpr bool empty()
const noexcept
472 return std::get<0>(data_).empty();
475 [[nodiscard]]
constexpr size_type size()
const noexcept
477 return std::get<0>(data_).size();
480 [[nodiscard]]
constexpr size_type max_size()
const noexcept
482 return max_size_impl(indices{});
485 constexpr void reserve(size_type new_cap) { reserve(new_cap, indices{}); }
487 [[nodiscard]]
constexpr size_type capacity()
const noexcept
489 return capacity_impl(indices{});
492 constexpr void shrink_to_fit() { shrink_to_fit_impl(indices{}); }
500 constexpr void clear()
noexcept { clear_impl(indices{}); }
502 constexpr iterator insert(iterator pos, value_type
const& value)
504 return insert_impl(pos, value, indices{});
507 constexpr iterator insert(iterator pos, value_type&& value)
509 return insert_impl(pos, std::move(value), indices{});
512 constexpr iterator insert(iterator pos, size_type count, value_type
const& value)
514 return insert_impl(pos, count, value, indices{});
517 template <std::input_iterator I, std::sentinel_for<I> S>
518 constexpr iterator insert(iterator pos, I first, S last)
520 return insert_impl(pos, first, last, indices{});
523 constexpr iterator insert(iterator pos, std::initializer_list<value_type> ilist)
525 return insert(pos, ilist.begin(), ilist.end());
528 template <std::ranges::input_range R>
529 constexpr iterator insert_range(iterator pos, R&& rg)
531 return insert_range_impl(pos, std::forward<R>(rg), indices{});
534 template <
class... Us>
535 constexpr iterator emplace(iterator pos, Us&&... us)
537 static_assert(
sizeof...(Us) ==
sizeof...(Ts),
"SoA: invalid number of arguments");
538 std::size_t
const idx = std::distance(begin(), pos);
539 emplace_impl(pos, std::forward<Us>(us)...);
540 return begin() + idx;
543 constexpr iterator erase(iterator pos) {
return erase_impl(pos, indices{}); }
545 constexpr iterator erase(iterator first, iterator last)
547 return erase_impl(first, last, indices{});
550 constexpr void push_back(value_type
const& value) { push_back_impl(value, indices{}); }
552 constexpr void push_back(value_type&& value)
554 push_back_impl(std::move(value), indices{});
557 template <
class... Us>
558 constexpr void push_back(Us&&... us)
560 emplace_back(std::forward<Us>(us)...);
564 template <
class... Us>
565 constexpr reference emplace_back(Us&&... us)
567 static_assert(
sizeof...(Us) ==
sizeof...(Ts),
"SoA: invalid number of arguments");
568 emplace_back_impl(std::forward<Us>(us)...);
572 template <std::ranges::input_range R>
573 constexpr void append_range(R&& rg)
575 append_range_impl(std::forward<R>(rg), indices{});
578 constexpr void pop_back() { pop_back_impl(indices{}); }
580 constexpr void resize(size_type count) { resize_impl(count, indices{}); }
582 constexpr void resize(size_type count, value_type
const& value)
584 resize_impl(count, value, indices{});
587 constexpr void swap(
SoA& other)
noexcept { swap_impl(other, indices{}); }
589 friend constexpr void swap(
SoA& lhs,
SoA& rhs)
noexcept { lhs.swap(rhs); }
591 template <std::
size_t I>
592 [[nodiscard]]
constexpr std::tuple_element_t<I, value_type>&
get(size_type pos)
594 return std::get<I>(data_)[pos];
597 template <std::
size_t I>
598 [[nodiscard]]
constexpr std::tuple_element_t<I, value_type>
const&
get(
601 return std::get<I>(data_)[pos];
605 [[nodiscard]]
constexpr T&
get(size_type pos)
607 static_assert(contains_type_v<T, Ts...>,
"SoA: type not found");
608 static_assert(is_unique_v<Ts...>,
"SoA: type is not unique, use get<I>(pos) instead");
609 return std::get<index_v<T, Ts...>>(data_)[pos];
613 [[nodiscard]]
constexpr T
const&
get(size_type pos)
const
615 static_assert(contains_type_v<T, Ts...>,
"SoA: type not found");
616 static_assert(is_unique_v<Ts...>,
"SoA: type is not unique, use get<I>(pos) instead");
617 return std::get<index_v<T, Ts...>>(data_)[pos];
621 constexpr void check_index(size_type pos)
const
624 throw std::out_of_range(
"SoA::at: index " + std::to_string(pos) +
625 " is out of range for size " + std::to_string(size()));
629 template <std::size_t... Is>
630 constexpr void assign_impl(size_type count, value_type
const& value,
631 std::index_sequence<Is...>)
633 (std::get<Is>(data_).assign(count, std::get<Is>(value)), ...);
636 template <std::ranges::input_range R, std::size_t... Is>
637 constexpr void assign_range_impl(R&& range, std::index_sequence<Is...>)
639 (std::get<Is>(data_).assign(std::views::elements<Is>(range).begin(),
640 std::views::elements<Is>(range).end()),
644 template <std::size_t... Is>
645 [[nodiscard]]
constexpr reference operator[](size_type pos, std::index_sequence<Is...>)
647 return std::tie(std::get<Is>(data_)[pos]...);
650 template <std::size_t... Is>
651 [[nodiscard]]
constexpr const_reference operator[](size_type pos,
652 std::index_sequence<Is...>)
const
654 return std::tie(std::get<Is>(data_)[pos]...);
657 template <std::size_t... Is>
658 [[nodiscard]]
constexpr size_type max_size_impl(
659 std::index_sequence<Is...>)
const noexcept
661 return std::min({std::get<Is>(data_).max_size()...});
664 template <std::size_t... Is>
665 constexpr void reserve_impl(size_type new_cap, std::index_sequence<Is...>)
667 (std::get<Is>(data_).reserve(new_cap), ...);
670 template <std::size_t... Is>
671 [[nodiscard]]
constexpr size_type capacity_impl(
672 std::index_sequence<Is...>)
const noexcept
674 return std::min({std::get<Is>(data_).capacity()...});
677 template <std::size_t... Is>
678 constexpr void shrink_to_fit_impl(std::index_sequence<Is...>)
680 (std::get<Is>(data_).shrink_to_fit(), ...);
683 template <std::size_t... Is>
684 constexpr void clear_impl(std::index_sequence<Is...>)
noexcept
686 (std::get<Is>(data_).clear(), ...);
689 template <std::size_t... Is>
690 constexpr iterator insert_impl(iterator pos, value_type
const& value,
691 std::index_sequence<Is...>)
693 std::size_t
const idx = std::distance(begin(), pos);
694 (std::get<Is>(data_).insert(std::get<Is>(data_).begin() + idx, std::get<Is>(value)),
696 return begin() + idx;
699 template <std::size_t... Is>
700 constexpr iterator insert_impl(iterator pos, value_type&& value,
701 std::index_sequence<Is...>)
703 std::size_t
const idx = std::distance(begin(), pos);
704 (std::get<Is>(data_).insert(std::get<Is>(data_).begin() + idx,
705 std::move(std::get<Is>(value))),
707 return begin() + idx;
710 template <std::size_t... Is>
711 constexpr iterator insert_impl(iterator pos, size_type count, value_type
const& value,
712 std::index_sequence<Is...>)
714 std::size_t
const idx = std::distance(begin(), pos);
715 (std::get<Is>(data_).insert(std::get<Is>(data_).begin() + idx, count,
716 std::get<Is>(value)),
718 return begin() + idx;
721 template <std::input_iterator I, std::sentinel_for<I> S, std::
size_t... Is>
722 constexpr iterator insert_impl(iterator pos, I first, S last,
723 std::index_sequence<Is...>)
725 std::size_t
const idx = std::distance(begin(), pos);
726 auto rg = std::ranges::subrange(first, last);
727 (std::get<Is>(data_).insert(std::get<Is>(data_).begin() + idx,
728 std::views::elements<Is>(rg).begin(),
729 std::views::elements<Is>(rg).end()),
731 return begin() + idx;
734 template <std::ranges::input_range R, std::size_t... Is>
735 constexpr iterator insert_range_impl(iterator pos, R&& rg, std::index_sequence<Is...>)
737 std::size_t
const idx = std::distance(begin(), pos);
738 (std::get<Is>(data_).insert(std::get<Is>(data_).begin() + idx,
739 std::views::elements<Is>(rg).begin(),
740 std::views::elements<Is>(rg).end()),
742 return begin() + idx;
745 template <
class... Us>
746 constexpr void emplace_impl(iterator pos, Us&&... us)
748 emplace_impl(pos, indices{}, std::forward<Us>(us)...);
751 template <std::size_t... Is,
class... Us>
752 constexpr void emplace_impl(iterator pos, std::index_sequence<Is...>, Us&&... us)
754 std::size_t
const idx = std::distance(begin(), pos);
755 (std::get<Is>(data_).emplace(std::get<Is>(data_).begin() + idx, std::forward<Us>(us)),
759 template <std::size_t... Is>
760 constexpr iterator erase_impl(iterator pos, std::index_sequence<Is...>)
762 auto const idx = std::distance(begin(), pos);
763 (std::get<Is>(data_).erase(std::get<Is>(data_).begin() + idx), ...);
764 return begin() + idx;
767 template <std::size_t... Is>
768 constexpr iterator erase_impl(iterator first, iterator last, std::index_sequence<Is...>)
770 auto const f_idx = std::distance(begin(), first);
771 auto const l_idx = std::distance(begin(), last);
772 (std::get<Is>(data_).erase(std::get<Is>(data_).begin() + f_idx,
773 std::get<Is>(data_).begin() + l_idx),
775 return begin() + f_idx;
778 template <std::size_t... Is>
779 constexpr void push_back_impl(value_type
const& value, std::index_sequence<Is...>)
781 (std::get<Is>(data_).push_back(std::get<Is>(value)), ...);
784 template <std::size_t... Is>
785 constexpr void push_back_impl(value_type&& value, std::index_sequence<Is...>)
787 (std::get<Is>(data_).push_back(std::move(std::get<Is>(value))), ...);
790 template <
class... Us>
791 constexpr void emplace_back_impl(Us&&... us)
793 emplace_back_impl(indices{}, std::forward<Us>(us)...);
796 template <std::size_t... Is,
class... Us>
797 constexpr void emplace_back_impl(std::index_sequence<Is...>, Us&&... us)
799 (std::get<Is>(data_).emplace_back(std::forward<Us>(us)), ...);
802 template <std::ranges::input_range R, std::size_t... Is>
803 constexpr void append_range_impl(R&& range, std::index_sequence<Is...>)
805 (std::get<Is>(data_).append_range(std::views::elements<Is>(range)), ...);
808 template <std::size_t... Is>
809 constexpr void pop_back_impl(std::index_sequence<Is...>)
811 (std::get<Is>(data_).pop_back(), ...);
814 template <std::size_t... Is>
815 constexpr void resize_impl(size_type count, std::index_sequence<Is...>)
817 (std::get<Is>(data_).resize(count), ...);
820 template <std::size_t... Is>
821 constexpr void resize_impl(size_type count, value_type
const& value,
822 std::index_sequence<Is...>)
824 (std::get<Is>(data_).resize(count, std::get<Is>(value)), ...);
827 template <std::size_t... Is>
828 constexpr void swap_impl(
SoA& other, std::index_sequence<Is...>)
noexcept
830 (std::get<Is>(data_).swap(std::get<Is>(other.data_)), ...);
833 [[nodiscard]]
constexpr auto get_view()
noexcept {
return get_view(indices{}); }
835 [[nodiscard]]
constexpr auto get_view()
const noexcept {
return get_view(indices{}); }
837 template <std::size_t... Is>
838 [[nodiscard]]
constexpr auto get_view(std::index_sequence<Is...>)
noexcept
840 return std::views::zip(std::ranges::ref_view(std::get<Is>(data_))...);
843 template <std::size_t... Is>
844 [[nodiscard]]
constexpr auto get_view(std::index_sequence<Is...>)
const noexcept
846 return std::views::zip(std::ranges::ref_view(std::get<Is>(data_))...);