23template <
typename Component,
typename Allocator = std::allocator<Component>>
35 using iterator =
typename std::vector<optional_t, Allocator>::iterator;
36 using const_iterator =
typename std::vector<optional_t, Allocator>::const_iterator;
50 return std::visit([&](
auto& storage) ->
reference {
return storage[idx]; }, _storage);
60 return std::visit([&](
auto const& storage) ->
const_reference {
return storage[idx]; }, _storage);
69 if (std::holds_alternative<sparse_storage_t>(_storage)) {
70 auto& sparse = std::get<sparse_storage_t>(_storage);
71 return sparse.begin();
73 auto& dense = std::get<dense_storage_t>(_storage);
84 if (std::holds_alternative<sparse_storage_t>(_storage)) {
85 auto& sparse = std::get<sparse_storage_t>(_storage);
86 return sparse.begin();
88 auto& dense = std::get<dense_storage_t>(_storage);
99 if (std::holds_alternative<sparse_storage_t>(_storage)) {
100 auto& sparse = std::get<sparse_storage_t>(_storage);
101 return sparse.cbegin();
103 auto& dense = std::get<dense_storage_t>(_storage);
104 return dense.cbegin();
114 if (std::holds_alternative<sparse_storage_t>(_storage)) {
115 auto& sparse = std::get<sparse_storage_t>(_storage);
118 auto& dense = std::get<dense_storage_t>(_storage);
129 if (std::holds_alternative<sparse_storage_t>(_storage)) {
130 auto& sparse = std::get<sparse_storage_t>(_storage);
133 auto& dense = std::get<dense_storage_t>(_storage);
144 if (std::holds_alternative<sparse_storage_t>(_storage)) {
145 auto& sparse = std::get<sparse_storage_t>(_storage);
146 return sparse.cend();
148 auto& dense = std::get<dense_storage_t>(_storage);
159 if (std::holds_alternative<sparse_storage_t>(_storage)) {
160 auto& sparse = std::get<sparse_storage_t>(_storage);
161 return sparse.size();
163 auto& dense = std::get<dense_storage_t>(_storage);
175 if (std::holds_alternative<sparse_storage_t>(_storage)) {
176 auto& sparse = std::get<sparse_storage_t>(_storage);
177 sparse.insert_at(
id, component);
179 auto& dense = std::get<dense_storage_t>(_storage);
180 dense.insert_at(
id, component);
191 if (std::holds_alternative<sparse_storage_t>(_storage)) {
192 auto& sparse = std::get<sparse_storage_t>(_storage);
193 sparse.insert_at(
id, std::forward<Component>(component));
195 auto& dense = std::get<dense_storage_t>(_storage);
196 dense.insert_at(
id, std::forward<Component>(component));
207 template <
typename... Params>
209 if (std::holds_alternative<sparse_storage_t>(_storage)) {
210 auto& sparse = std::get<sparse_storage_t>(_storage);
211 if (
id >= sparse.size()) {
212 sparse.resize(
id + 1);
215 sparse[id].emplace(std::forward<Params>(params)...);
217 auto& dense = std::get<dense_storage_t>(_storage);
219 dense.emplace_at(
id, std::forward<Params>(params)...);
230 if (std::holds_alternative<sparse_storage_t>(_storage)) {
231 const auto& sparse = std::get<sparse_storage_t>(_storage);
232 if (
id < sparse.size()) {
236 const auto& dense = std::get<dense_storage_t>(_storage);
237 if (
id < dense.size()) {
250 if (std::holds_alternative<sparse_storage_t>(_storage)) {
251 auto& sparse = std::get<sparse_storage_t>(_storage);
252 if (
id < sparse.size()) {
256 auto& dense = std::get<dense_storage_t>(_storage);
257 if (
id < dense.size()) {
269 if (std::holds_alternative<sparse_storage_t>(_storage)) {
270 auto& sparse = std::get<sparse_storage_t>(_storage);
271 sparse.resize(new_size);
282 if (std::holds_alternative<sparse_storage_t>(_storage)) {
283 auto& sparse = std::get<sparse_storage_t>(_storage);
284 size_type filled = std::count_if(sparse.begin(), sparse.end(), [](
const auto& opt) { return opt.has_value(); });
285 if (filled >= dense_threshold) {
287 migrate_storage(dense);
288 _storage = std::move(dense);
291 auto& dense = std::get<dense_storage_t>(_storage);
292 if (dense.size() <= sparse_threshold) {
294 migrate_storage(sparse);
295 _storage = std::move(sparse);
304 using ComponentStorage = std::variant<sparse_storage_t, dense_storage_t>;
305 ComponentStorage _storage;
313 template <
typename NewContainer>
314 void migrate_storage(NewContainer& new_storage) {
315 if (std::holds_alternative<sparse_storage_t>(_storage)) {
316 const auto& sparse = std::get<sparse_storage_t>(_storage);
317 for (
size_type i = 0; i < sparse.size(); ++i) {
319 new_storage.insert_at(i, *sparse[i]);
323 const auto& dense = std::get<dense_storage_t>(_storage);
324 size_type max_id = *std::max_element(dense.begin(), dense.end());
325 new_storage.resize(max_id + 1);
326 for (
size_type i = 0; i < dense.size(); ++i) {
327 new_storage[i] = dense[i];
Manages a collection of components associated with entities in an ECS (Entity-Component-System) archi...
Component value_type
Type aliases for convenience.
const_iterator end() const
Returns a const iterator to the end of the component container.
iterator end()
Returns an iterator to the end of the component container.
typename std::vector< optional_t, Allocator >::iterator iterator
std::optional< Component > get(const value_type &id) const
Retrieves a component by its id.
reference operator[](size_t idx)
Accesses the component at a given index.
void emplace_at(size_type id, Params &&... params)
Constructs and inserts a component at a specific ID.
size_type size() const
Returns the number of components stored in the array.
void insert_at(size_type id, const Component &component)
Inserts a component at a specific ID.
typename std::vector< optional_t, Allocator >::const_iterator const_iterator
const_iterator cbegin() const
Returns a const iterator to the beginning of the component container.
ComponentContainer()
Default constructor.
const_reference operator[](size_t idx) const
Accesses the component at a given index (const version).
const optional_t & const_reference
typename sparse_storage_t::size_type size_type
const_iterator cend() const
Returns a const iterator to the end of the component container.
iterator begin()
Returns an iterator to the beginning of the component container.
void optimize_storage(size_type sparse_threshold, size_type dense_threshold)
Optimizes the storage type based on thresholds for sparse and dense storage.
std::optional< Component > optional_t
void resize(size_type new_size)
Resizes the container to a new size.
const_iterator begin() const
Returns a const iterator to the beginning of the component container.
void erase(size_type id)
Removes a component at a specific ID.
void insert_at(size_type id, Component &&component)
Inserts a component at a specific ID (move version).
A container that provides dense storage for components with a mapping between entity IDs and componen...
A container that provides sparse storage for optional components.
typename container_t::size_type size_type