Last active
June 4, 2025 20:24
-
-
Save furrz/ca4a657fd5de9f973fc9b55ddaae7412 to your computer and use it in GitHub Desktop.
multi_vector - A little C++ SoA container
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #pragma once | |
| #include <tuple> | |
| #include <vector> | |
| /** multi_vector | |
| * The beginnings of a structure-of-arrays vector. | |
| * (Currently append-only. | |
| * Just makes iteration and appending friendlier and less error-prone.) | |
| * @author PrinceZyntaks | |
| * @date 2025-06-04 | |
| */ | |
| template<typename ...Types> | |
| struct multi_vector { | |
| using tuple_type = std::tuple<std::vector<Types> ...>; | |
| using tuple_size = std::tuple_size<tuple_type>; | |
| static constexpr auto index_sequence = | |
| std::make_index_sequence<tuple_size::value>{}; | |
| template<bool Const> | |
| struct iterator_impl { | |
| using iterator_category = std::forward_iterator_tag; | |
| using difference_type = ptrdiff_t; | |
| using value_type = std::conditional_t<Const, | |
| std::tuple<const Types&...>, | |
| std::tuple<Types&...>>; | |
| using self = iterator_impl<Const>; | |
| tuple_type& container; | |
| size_t index; | |
| template<size_t... Indices> | |
| [[nodiscard]] value_type construct_tuple_impl(std::index_sequence<Indices...>) const { | |
| return std::make_tuple(std::ref(std::get<Indices>(container)[index])...); | |
| } | |
| [[nodiscard]] value_type operator*() const { | |
| constexpr size_t tuple_size = tuple_size::value; | |
| return construct_tuple_impl(index_sequence); | |
| } | |
| self& operator++() { index++; return *this; } | |
| self operator++(int) { iterator tmp = *this; ++(*this); return tmp; } | |
| friend bool operator== (const self& a, const self& b) { return a.index == b.index && &a.container == &b.container; } | |
| friend bool operator!=(const self& a, const self& b) { return !(a == b); } | |
| }; | |
| using iterator = iterator_impl<false>; | |
| using const_iterator = iterator_impl<true>; | |
| size_t size() const { return std::get<0>(vectors).size(); } | |
| void emplace_back(const Types& ...values) { | |
| constexpr size_t tuple_size = tuple_size::value; | |
| emplace_back_impl(values..., index_sequence); | |
| } | |
| [[nodiscard]] iterator begin() { return { vectors, 0 }; } | |
| [[nodiscard]] iterator end() { return { vectors, size() }; } | |
| [[nodiscard]] const_iterator cbegin() const { return { vectors, 0 }; } | |
| [[nodiscard]] const_iterator cend() const { return { vectors, size() }; } | |
| private: | |
| template<size_t... Indices> | |
| void emplace_back_impl(Types ...values, std::index_sequence<Indices...>) { | |
| (void) std::initializer_list { | |
| (std::get<Indices>(vectors).emplace_back(values), 0)... | |
| }; | |
| } | |
| std::tuple<std::vector<Types> ...> vectors; | |
| }; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment