From 9732f0547ddd5409ecbe7f7b4d5e15aa51ebc2fc Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Tue, 5 Sep 2023 14:36:33 +0200 Subject: [PATCH] sparse_set/storage: drop length in favor of a temporary function to make the transition easier --- src/entt/entity/sparse_set.hpp | 8 ++++ src/entt/entity/storage.hpp | 84 ++++++++++++---------------------- 2 files changed, 38 insertions(+), 54 deletions(-) diff --git a/src/entt/entity/sparse_set.hpp b/src/entt/entity/sparse_set.hpp index 48cf89f21..28956a4fe 100644 --- a/src/entt/entity/sparse_set.hpp +++ b/src/entt/entity/sparse_set.hpp @@ -252,6 +252,14 @@ protected: /*! @brief Random access iterator type. */ using basic_iterator = internal::sparse_set_iterator; + /** + * @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(len); + } + /** * @brief Erases an entity from a sparse set. * @param it An iterator to the element to pop. diff --git a/src/entt/entity/storage.hpp b/src/entt/entity/storage.hpp index 7008da412..87bd780d3 100644 --- a/src/entt/entity/storage.hpp +++ b/src/entt/entity/storage.hpp @@ -967,7 +967,7 @@ class basic_storage 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(), deletion_policy::swap_only, allocator}, - length{} {} + : base_type{type_id(), 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 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 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(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