Skip to content

Commit

Permalink
sparse_set: improved shrink_to_fit to also cleanup the sparse array
Browse files Browse the repository at this point in the history
  • Loading branch information
skypjack committed Jan 28, 2025
1 parent 7fe1a69 commit 476822e
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 2 deletions.
1 change: 0 additions & 1 deletion TODO
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ TODO:
* don't pass reactive storage by default to callback
* runtime types support for meta for types that aren't backed by C++ types
* built-in no-pagination storage - no_pagination page size as limits::max
* sparse_set shrink_to_fit argument for sparse array shrink policy (none, empty, deep, whatever)
* any cdynamic to support const ownership construction
* return meta context from meta objects
* allow passing arguments to meta setter/getter (we can fallback on meta invoke for everything probably)
26 changes: 26 additions & 0 deletions src/entt/entity/sparse_set.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,32 @@ class basic_sparse_set {

/*! @brief Requests the removal of unused capacity. */
virtual void shrink_to_fit() {
sparse_container_type other{sparse.get_allocator()};
const auto len = sparse.size();
size_type cnt{};

other.reserve(len);

for(auto &&elem: std::as_const(packed)) {
// also skip tombstones, if any
if(const auto page = pos_to_page(entity_to_pos(elem)); page < len && sparse[page] != nullptr) {
if(const auto sz = page + 1u; sz > other.size()) {
other.resize(sz, nullptr);
}

other[page] = std::exchange(sparse[page], nullptr);

if(++cnt == len) {
// early exit due to lack of pages
break;
}
}
}

release_sparse_pages();
sparse.swap(other);

sparse.shrink_to_fit();
packed.shrink_to_fit();
}

Expand Down
10 changes: 9 additions & 1 deletion test/entt/entity/sparse_set.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,15 @@ TYPED_TEST(SparseSet, Pagination) {

set.shrink_to_fit();

ASSERT_EQ(set.extent(), 2 * traits_type::page_size);
switch(policy) {
case entt::deletion_policy::swap_and_pop:
case entt::deletion_policy::in_place: {
ASSERT_EQ(set.extent(), 0u);
} break;
case entt::deletion_policy::swap_only: {
ASSERT_EQ(set.extent(), 2 * traits_type::page_size);
} break;
}
}
}

Expand Down

0 comments on commit 476822e

Please sign in to comment.