sparse_set/storage: drop length in favor of a temporary function to make the transition easier

This commit is contained in:
Michele Caini
2023-09-05 14:36:33 +02:00
parent 9c9a71af74
commit 9732f0547d
2 changed files with 38 additions and 54 deletions

View File

@@ -252,6 +252,14 @@ protected:
/*! @brief Random access iterator type. */
using basic_iterator = internal::sparse_set_iterator<packed_container_type>;
/**
* @brief Temporary function to make the transition easier. Don't use me.
* @param len The length to use.
*/
void swap_only_length_temporary_function(const std::size_t len) {
head = static_cast<underlying_type>(len);
}
/**
* @brief Erases an entity from a sparse set.
* @param it An iterator to the element to pop.

View File

@@ -967,7 +967,7 @@ class basic_storage<Entity, Entity, Allocator>
private:
void swap_or_move([[maybe_unused]] const std::size_t lhs, [[maybe_unused]] const std::size_t rhs) override {
ENTT_ASSERT(((lhs < length) + (rhs < length)) != 1u, "Cross swapping is not supported");
ENTT_ASSERT(((lhs < base_type::free_list()) + (rhs < base_type::free_list())) != 1u, "Cross swapping is not supported");
}
protected:
@@ -978,24 +978,18 @@ protected:
*/
void pop(underlying_iterator first, underlying_iterator last) override {
for(; first != last; ++first) {
if(const auto pos = base_type::index(*first); pos < length) {
if(const auto pos = base_type::index(*first); pos < base_type::free_list()) {
base_type::bump(local_traits_type::next(*first));
if(const size_type slot = length - 1u; pos != slot) {
if(const size_type slot = base_type::free_list() - 1u; pos != slot) {
base_type::swap_elements(base_type::data()[pos], base_type::data()[slot]);
}
--length;
base_type::swap_only_length_temporary_function(base_type::free_list() - 1u);
}
}
}
/*! @brief Erases all entities of a sparse set. */
void pop_all() override {
length = 0u;
base_type::pop_all();
}
/**
* @brief Assigns an entity to a storage.
* @param hint A valid identifier.
@@ -1037,16 +1031,14 @@ public:
* @param allocator The allocator to use.
*/
explicit basic_storage(const allocator_type &allocator)
: base_type{type_id<value_type>(), deletion_policy::swap_only, allocator},
length{} {}
: base_type{type_id<value_type>(), deletion_policy::swap_only, allocator} {}
/**
* @brief Move constructor.
* @param other The instance to move from.
*/
basic_storage(basic_storage &&other) noexcept
: base_type{std::move(other)},
length{std::exchange(other.length, size_type{})} {}
: base_type{std::move(other)} {}
/**
* @brief Allocator-extended move constructor.
@@ -1054,8 +1046,7 @@ public:
* @param allocator The allocator to use.
*/
basic_storage(basic_storage &&other, const allocator_type &allocator) noexcept
: base_type{std::move(other), allocator},
length{std::exchange(other.length, size_type{})} {}
: base_type{std::move(other), allocator} {}
/**
* @brief Move assignment operator.
@@ -1064,7 +1055,6 @@ public:
*/
basic_storage &operator=(basic_storage &&other) noexcept {
base_type::operator=(std::move(other));
length = std::exchange(other.length, size_type{});
return *this;
}
@@ -1078,7 +1068,7 @@ public:
* @param entt A valid identifier.
*/
void get([[maybe_unused]] const entity_type entt) const noexcept {
ENTT_ASSERT(base_type::index(entt) < length, "The requested entity is not a live one");
ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
}
/**
@@ -1092,30 +1082,18 @@ public:
* @return Returns an empty tuple.
*/
[[nodiscard]] std::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept {
ENTT_ASSERT(base_type::index(entt) < length, "The requested entity is not a live one");
ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
return std::tuple{};
}
/**
* @brief Exchanges the contents with those of a given storage.
* @param other Storage to exchange the content with.
*/
void swap(basic_storage &other) {
using std::swap;
base_type::swap(other);
swap(length, other.length);
}
/**
* @brief Creates a new identifier or recycles a destroyed one.
* @return A valid identifier.
*/
entity_type emplace() {
if(length == base_type::size()) {
return *base_type::try_emplace(entity_at(length++), true);
}
return base_type::operator[](length++);
const auto len = base_type::free_list();
base_type::swap_only_length_temporary_function(len + 1u);
return (len == base_type::size()) ? *base_type::try_emplace(entity_at(len), true) : base_type::operator[](len);
}
/**
@@ -1137,13 +1115,13 @@ public:
base_type::try_emplace(entity_at(base_type::size()), true);
}
base_type::swap_elements(base_type::data()[pos], base_type::data()[length]);
++length;
} else if(const auto idx = base_type::index(curr); idx < length) {
base_type::swap_elements(base_type::data()[pos], base_type::data()[base_type::free_list()]);
base_type::swap_only_length_temporary_function(base_type::free_list() + 1u);
} else if(const auto idx = base_type::index(curr); idx < base_type::free_list()) {
return emplace();
} else {
base_type::swap_elements(base_type::data()[idx], base_type::data()[length]);
++length;
base_type::swap_elements(base_type::data()[idx], base_type::data()[base_type::free_list()]);
base_type::swap_only_length_temporary_function(base_type::free_list() + 1u);
}
base_type::bump(hint);
@@ -1171,12 +1149,13 @@ public:
*/
template<typename It>
void insert(It first, It last) {
for(const auto sz = base_type::size(); first != last && length != sz; ++first, ++length) {
*first = base_type::operator[](length);
for(const auto sz = base_type::size(); first != last && base_type::free_list() != sz; ++first, base_type::swap_only_length_temporary_function(base_type::free_list() + 1u)) {
*first = base_type::operator[](base_type::free_list());
}
for(; first != last; ++first) {
*first = *base_type::try_emplace(entity_at(length++), true);
*first = *base_type::try_emplace(entity_at(base_type::free_list()), true);
base_type::swap_only_length_temporary_function(base_type::free_list() + 1u);
}
}
@@ -1189,15 +1168,15 @@ public:
*/
template<typename It>
size_type pack(It first, It last) {
size_type len = length;
size_type len = base_type::free_list();
for(; first != last; ++first, --len) {
const auto pos = base_type::index(*first);
ENTT_ASSERT(pos < length, "Invalid element");
ENTT_ASSERT(pos < base_type::free_list(), "Invalid element");
base_type::swap_elements(base_type::data()[pos], base_type::data()[static_cast<size_type>(len - 1u)]);
}
return (length - len);
return (base_type::free_list() - len);
}
/**
@@ -1205,7 +1184,7 @@ public:
* @return The number of elements considered still in use.
*/
[[nodiscard]] size_type in_use() const noexcept {
return length;
return base_type::free_list();
}
/**
@@ -1214,7 +1193,7 @@ public:
*/
void in_use(const size_type len) noexcept {
ENTT_ASSERT(!(len > base_type::size()), "Invalid length");
length = len;
base_type::swap_only_length_temporary_function(len);
}
/**
@@ -1225,12 +1204,12 @@ public:
* @return An iterable object to use to _visit_ the storage.
*/
[[nodiscard]] iterable each() noexcept {
return {internal::extended_storage_iterator{base_type::end() - length}, internal::extended_storage_iterator{base_type::end()}};
return {internal::extended_storage_iterator{base_type::end() - base_type::free_list()}, internal::extended_storage_iterator{base_type::end()}};
}
/*! @copydoc each */
[[nodiscard]] const_iterable each() const noexcept {
return {internal::extended_storage_iterator{base_type::cend() - length}, internal::extended_storage_iterator{base_type::cend()}};
return {internal::extended_storage_iterator{base_type::cend() - base_type::free_list()}, internal::extended_storage_iterator{base_type::cend()}};
}
/**
@@ -1241,16 +1220,13 @@ public:
* @return A reverse iterable object to use to _visit_ the storage.
*/
[[nodiscard]] reverse_iterable reach() noexcept {
return {internal::extended_storage_iterator{base_type::rbegin()}, internal::extended_storage_iterator{base_type::rbegin() + length}};
return {internal::extended_storage_iterator{base_type::rbegin()}, internal::extended_storage_iterator{base_type::rbegin() + base_type::free_list()}};
}
/*! @copydoc reach */
[[nodiscard]] const_reverse_iterable reach() const noexcept {
return {internal::extended_storage_iterator{base_type::crbegin()}, internal::extended_storage_iterator{base_type::crbegin() + length}};
return {internal::extended_storage_iterator{base_type::crbegin()}, internal::extended_storage_iterator{base_type::crbegin() + base_type::free_list()}};
}
private:
size_type length;
};
} // namespace entt