Просмотр исходного кода

registry:
* const thread safe implementation
* views created from const registires can refer placeholder pools (that is, they don't refresh)

Michele Caini 4 лет назад
Родитель
Сommit
e5d1ca2e3c
2 измененных файлов с 83 добавлено и 86 удалено
  1. 65 68
      src/entt/entity/registry.hpp
  2. 18 18
      test/entt/entity/view.cpp

+ 65 - 68
src/entt/entity/registry.hpp

@@ -63,20 +63,20 @@ class basic_registry {
 
         template<typename Component>
         void maybe_valid_if(basic_registry &owner, const Entity entt) {
-            [[maybe_unused]] const auto cpools = std::make_tuple(owner.assure<Owned>()...);
+            [[maybe_unused]] const auto cpools = std::forward_as_tuple(owner.assure<Owned>()...);
 
-            const auto is_valid = ((std::is_same_v<Component, Owned> || std::get<storage_type<Owned> *>(cpools)->contains(entt)) && ...)
-                                  && ((std::is_same_v<Component, Get> || owner.assure<Get>()->contains(entt)) && ...)
-                                  && ((std::is_same_v<Component, Exclude> || !owner.assure<Exclude>()->contains(entt)) && ...);
+            const auto is_valid = ((std::is_same_v<Component, Owned> || std::get<storage_type<Owned> &>(cpools).contains(entt)) && ...)
+                                  && ((std::is_same_v<Component, Get> || owner.assure<Get>().contains(entt)) && ...)
+                                  && ((std::is_same_v<Component, Exclude> || !owner.assure<Exclude>().contains(entt)) && ...);
 
             if constexpr(sizeof...(Owned) == 0) {
                 if(is_valid && !current.contains(entt)) {
                     current.emplace(entt);
                 }
             } else {
-                if(is_valid && !(std::get<0>(cpools)->index(entt) < current)) {
+                if(is_valid && !(std::get<0>(cpools).index(entt) < current)) {
                     const auto pos = current++;
-                    (std::get<storage_type<Owned> *>(cpools)->swap_elements(std::get<storage_type<Owned> *>(cpools)->data()[pos], entt), ...);
+                    (std::get<storage_type<Owned> &>(cpools).swap_elements(std::get<storage_type<Owned> &>(cpools).data()[pos], entt), ...);
                 }
             }
         }
@@ -85,9 +85,9 @@ class basic_registry {
             if constexpr(sizeof...(Owned) == 0) {
                 current.remove(entt);
             } else {
-                if(const auto cpools = std::make_tuple(owner.assure<Owned>()...); std::get<0>(cpools)->contains(entt) && (std::get<0>(cpools)->index(entt) < current)) {
+                if(const auto cpools = std::forward_as_tuple(owner.assure<Owned>()...); std::get<0>(cpools).contains(entt) && (std::get<0>(cpools).index(entt) < current)) {
                     const auto pos = --current;
-                    (std::get<storage_type<Owned> *>(cpools)->swap_elements(std::get<storage_type<Owned> *>(cpools)->data()[pos], entt), ...);
+                    (std::get<storage_type<Owned> &>(cpools).swap_elements(std::get<storage_type<Owned> &>(cpools).data()[pos], entt), ...);
                 }
             }
         }
@@ -102,24 +102,29 @@ class basic_registry {
     };
 
     template<typename Component>
-    [[nodiscard]] storage_type<Component> *assure() const {
+    [[nodiscard]] storage_type<Component> &assure() {
         static_assert(std::is_same_v<Component, std::decay_t<Component>>, "Non-decayed types not allowed");
         auto &&pdata = pools[type_id<Component>().hash()];
 
         if(!pdata.pool) {
             pdata.pool.reset(new storage_type<Component>{});
-            pdata.pool->context(forward_as_any(const_cast<basic_registry &>(*this)));
+            pdata.pool->context(forward_as_any(*this));
             pdata.info = &type_id<Component>();
         }
 
-        return static_cast<storage_type<Component> *>(pdata.pool.get());
+        return static_cast<storage_type<Component> &>(*pdata.pool);
     }
 
     template<typename Component>
-    [[nodiscard]] const storage_type<Component> *pool_if_exists() const ENTT_NOEXCEPT {
+    [[nodiscard]] const storage_type<Component> &assure() const {
         static_assert(std::is_same_v<Component, std::decay_t<Component>>, "Non-decayed types not allowed");
-        const auto it = pools.find(type_id<Component>().hash());
-        return (it == pools.end()) ? nullptr : static_cast<const storage_type<Component> *>(it->second.pool.get());
+
+        if(const auto it = pools.find(type_id<Component>().hash()); it != pools.cend()) {
+            return static_cast<storage_type<Component> &>(*it->second.pool);
+        }
+
+        static storage_type<Component> placeholder{};
+        return placeholder;
     }
 
     auto generate_identifier(const std::size_t pos) ENTT_NOEXCEPT {
@@ -203,8 +208,7 @@ public:
      */
     template<typename Component>
     [[nodiscard]] size_type size() const {
-        const auto *cpool = pool_if_exists<std::remove_const_t<Component>>();
-        return cpool ? cpool->size() : size_type{};
+        return assure<std::remove_const_t<Component>>().size();
     }
 
     /**
@@ -247,7 +251,7 @@ public:
         if constexpr(sizeof...(Component) == 0) {
             entities.reserve(cap);
         } else {
-            (assure<Component>()->reserve(cap), ...);
+            (assure<Component>().reserve(cap), ...);
         }
     }
 
@@ -258,8 +262,7 @@ public:
      */
     template<typename Component>
     [[nodiscard]] size_type capacity() const {
-        const auto *cpool = pool_if_exists<std::remove_const_t<Component>>();
-        return cpool ? cpool->capacity() : size_type{};
+        return assure<std::remove_const_t<Component>>().capacity();
     }
 
     /**
@@ -278,7 +281,7 @@ public:
      */
     template<typename... Component>
     void shrink_to_fit() {
-        (assure<Component>()->shrink_to_fit(), ...);
+        (assure<Component>().shrink_to_fit(), ...);
     }
 
     /**
@@ -297,7 +300,7 @@ public:
         if constexpr(sizeof...(Component) == 0) {
             return !alive();
         } else {
-            return [](const auto *...cpool) { return ((!cpool || cpool->empty()) && ...); }(pool_if_exists<std::remove_const_t<Component>>()...);
+            return (assure<std::remove_const_t<Component>>().empty() && ...);
         }
     }
 
@@ -576,7 +579,7 @@ public:
     template<typename Component, typename... Args>
     decltype(auto) emplace(const entity_type entity, Args &&...args) {
         ENTT_ASSERT(valid(entity), "Invalid entity");
-        return assure<Component>()->emplace(entity, std::forward<Args>(args)...);
+        return assure<Component>().emplace(entity, std::forward<Args>(args)...);
     }
 
     /**
@@ -593,7 +596,7 @@ public:
     template<typename Component, typename It>
     void insert(It first, It last, const Component &value = {}) {
         ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }), "Invalid entity");
-        assure<Component>()->insert(first, last, value);
+        assure<Component>().insert(first, last, value);
     }
 
     /**
@@ -612,7 +615,7 @@ public:
     void insert(EIt first, EIt last, CIt from) {
         static_assert(std::is_constructible_v<Component, typename std::iterator_traits<CIt>::value_type>, "Invalid value type");
         ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }), "Invalid entity");
-        assure<Component>()->insert(first, last, from);
+        assure<Component>().insert(first, last, from);
     }
 
     /**
@@ -630,11 +633,11 @@ public:
     template<typename Component, typename... Args>
     decltype(auto) emplace_or_replace(const entity_type entity, Args &&...args) {
         ENTT_ASSERT(valid(entity), "Invalid entity");
-        auto *cpool = assure<Component>();
+        auto &cpool = assure<Component>();
 
-        return cpool->contains(entity)
-                   ? cpool->patch(entity, [&args...](auto &...curr) { ((curr = Component{std::forward<Args>(args)...}), ...); })
-                   : cpool->emplace(entity, std::forward<Args>(args)...);
+        return cpool.contains(entity)
+                   ? cpool.patch(entity, [&args...](auto &...curr) { ((curr = Component{std::forward<Args>(args)...}), ...); })
+                   : cpool.emplace(entity, std::forward<Args>(args)...);
     }
 
     /**
@@ -664,7 +667,7 @@ public:
     template<typename Component, typename... Func>
     decltype(auto) patch(const entity_type entity, Func &&...func) {
         ENTT_ASSERT(valid(entity), "Invalid entity");
-        return assure<Component>()->patch(entity, std::forward<Func>(func)...);
+        return assure<Component>().patch(entity, std::forward<Func>(func)...);
     }
 
     /**
@@ -686,7 +689,7 @@ public:
      */
     template<typename Component, typename... Args>
     decltype(auto) replace(const entity_type entity, Args &&...args) {
-        return assure<Component>()->patch(entity, [&args...](auto &...curr) { ((curr = Component{std::forward<Args>(args)...}), ...); });
+        return assure<Component>().patch(entity, [&args...](auto &...curr) { ((curr = Component{std::forward<Args>(args)...}), ...); });
     }
 
     /**
@@ -703,7 +706,7 @@ public:
     size_type remove(const entity_type entity) {
         ENTT_ASSERT(valid(entity), "Invalid entity");
         static_assert(sizeof...(Component) > 0, "Provide one or more component types");
-        return (assure<Component>()->remove(entity) + ... + size_type{});
+        return (assure<Component>().remove(entity) + ... + size_type{});
     }
 
     /**
@@ -720,13 +723,13 @@ public:
     template<typename... Component, typename It>
     size_type remove(It first, It last) {
         static_assert(sizeof...(Component) > 0, "Provide one or more component types");
-        const auto cpools = std::make_tuple(assure<Component>()...);
+        const auto cpools = std::forward_as_tuple(assure<Component>()...);
         size_type count{};
 
         for(; first != last; ++first) {
             const auto entity = *first;
             ENTT_ASSERT(valid(entity), "Invalid entity");
-            count += (std::get<storage_type<Component> *>(cpools)->remove(entity) + ...);
+            count += (std::get<storage_type<Component> &>(cpools).remove(entity) + ...);
         }
 
         return count;
@@ -746,7 +749,7 @@ public:
     void erase(const entity_type entity) {
         ENTT_ASSERT(valid(entity), "Invalid entity");
         static_assert(sizeof...(Component) > 0, "Provide one or more component types");
-        (assure<Component>()->erase(entity), ...);
+        (assure<Component>().erase(entity), ...);
     }
 
     /**
@@ -762,12 +765,12 @@ public:
     template<typename... Component, typename It>
     void erase(It first, It last) {
         static_assert(sizeof...(Component) > 0, "Provide one or more component types");
-        const auto cpools = std::make_tuple(assure<Component>()...);
+        const auto cpools = std::forward_as_tuple(assure<Component>()...);
 
         for(; first != last; ++first) {
             const auto entity = *first;
             ENTT_ASSERT(valid(entity), "Invalid entity");
-            (std::get<storage_type<Component> *>(cpools)->erase(entity), ...);
+            (std::get<storage_type<Component> &>(cpools).erase(entity), ...);
         }
     }
 
@@ -783,7 +786,7 @@ public:
                 curr.second.pool->compact();
             }
         } else {
-            (assure<Component>()->compact(), ...);
+            (assure<Component>().compact(), ...);
         }
     }
 
@@ -800,7 +803,7 @@ public:
     template<typename... Component>
     [[nodiscard]] bool all_of(const entity_type entity) const {
         ENTT_ASSERT(valid(entity), "Invalid entity");
-        return [entity](const auto *...cpool) { return ((cpool && cpool->contains(entity)) && ...); }(pool_if_exists<std::remove_const_t<Component>>()...);
+        return (assure<std::remove_const_t<Component>>().contains(entity) && ...);
     }
 
     /**
@@ -817,7 +820,7 @@ public:
     template<typename... Component>
     [[nodiscard]] bool any_of(const entity_type entity) const {
         ENTT_ASSERT(valid(entity), "Invalid entity");
-        return [entity](const auto *...cpool) { return !((!cpool || !cpool->contains(entity)) && ...); }(pool_if_exists<std::remove_const_t<Component>>()...);
+        return (assure<std::remove_const_t<Component>>().contains(entity) || ...);
     }
 
     /**
@@ -836,9 +839,7 @@ public:
         ENTT_ASSERT(valid(entity), "Invalid entity");
 
         if constexpr(sizeof...(Component) == 1) {
-            const auto *cpool = pool_if_exists<std::remove_const_t<Component>...>();
-            ENTT_ASSERT(cpool, "Storage not available");
-            return cpool->get(entity);
+            return assure<std::remove_const_t<Component>...>().get(entity);
         } else {
             return std::forward_as_tuple(get<Component>(entity)...);
         }
@@ -847,10 +848,8 @@ public:
     /*! @copydoc get */
     template<typename... Component>
     [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entity) {
-        ENTT_ASSERT(valid(entity), "Invalid entity");
-
         if constexpr(sizeof...(Component) == 1) {
-            return (const_cast<Component &>(assure<std::remove_const_t<Component>>()->get(entity)), ...);
+            return (const_cast<Component &>(assure<std::remove_const_t<Component>>().get(entity)), ...);
         } else {
             return std::forward_as_tuple(get<Component>(entity)...);
         }
@@ -874,8 +873,8 @@ public:
     template<typename Component, typename... Args>
     [[nodiscard]] decltype(auto) get_or_emplace(const entity_type entity, Args &&...args) {
         ENTT_ASSERT(valid(entity), "Invalid entity");
-        auto *cpool = assure<Component>();
-        return cpool->contains(entity) ? cpool->get(entity) : cpool->emplace(entity, std::forward<Args>(args)...);
+        auto &cpool = assure<Component>();
+        return cpool.contains(entity) ? cpool.get(entity) : cpool.emplace(entity, std::forward<Args>(args)...);
     }
 
     /**
@@ -896,8 +895,8 @@ public:
         ENTT_ASSERT(valid(entity), "Invalid entity");
 
         if constexpr(sizeof...(Component) == 1) {
-            const auto *cpool = pool_if_exists<std::remove_const_t<Component>...>();
-            return (cpool && cpool->contains(entity)) ? std::addressof(cpool->get(entity)) : nullptr;
+            const auto &cpool = assure<std::remove_const_t<Component>...>();
+            return cpool.contains(entity) ? std::addressof(cpool.get(entity)) : nullptr;
         } else {
             return std::make_tuple(try_get<Component>(entity)...);
         }
@@ -906,8 +905,6 @@ public:
     /*! @copydoc try_get */
     template<typename... Component>
     [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entity) {
-        ENTT_ASSERT(valid(entity), "Invalid entity");
-
         if constexpr(sizeof...(Component) == 1) {
             return (const_cast<Component *>(std::as_const(*this).template try_get<Component>(entity)), ...);
         } else {
@@ -928,7 +925,7 @@ public:
 
             each([this](const auto entity) { release_entity(entity, entity_traits::to_version(entity) + 1u); });
         } else {
-            (assure<Component>()->clear(), ...);
+            (assure<Component>().clear(), ...);
         }
     }
 
@@ -1021,7 +1018,7 @@ public:
      */
     template<typename Component>
     [[nodiscard]] auto on_construct() {
-        return assure<Component>()->on_construct();
+        return assure<Component>().on_construct();
     }
 
     /**
@@ -1044,7 +1041,7 @@ public:
      */
     template<typename Component>
     [[nodiscard]] auto on_update() {
-        return assure<Component>()->on_update();
+        return assure<Component>().on_update();
     }
 
     /**
@@ -1069,7 +1066,7 @@ public:
      */
     template<typename Component>
     [[nodiscard]] auto on_destroy() {
-        return assure<Component>()->on_destroy();
+        return assure<Component>().on_destroy();
     }
 
     /**
@@ -1107,14 +1104,14 @@ public:
     template<typename... Component, typename... Exclude>
     [[nodiscard]] basic_view<Entity, get_t<std::add_const_t<Component>...>, exclude_t<Exclude...>> view(exclude_t<Exclude...> = {}) const {
         static_assert(sizeof...(Component) > 0, "Exclusion-only views are not supported");
-        return {*assure<std::remove_const_t<Component>>()..., *assure<Exclude>()...};
+        return {assure<std::remove_const_t<Component>>()..., assure<Exclude>()...};
     }
 
     /*! @copydoc view */
     template<typename... Component, typename... Exclude>
     [[nodiscard]] basic_view<Entity, get_t<Component...>, exclude_t<Exclude...>> view(exclude_t<Exclude...> = {}) {
         static_assert(sizeof...(Component) > 0, "Exclusion-only views are not supported");
-        return {*assure<std::remove_const_t<Component>>()..., *assure<Exclude>()...};
+        return {assure<std::remove_const_t<Component>>()..., assure<Exclude>()...};
     }
 
     /**
@@ -1200,7 +1197,7 @@ public:
 
         using handler_type = group_handler<exclude_t<Exclude...>, get_t<std::remove_const_t<Get>...>, std::remove_const_t<Owned>...>;
 
-        const auto cpools = std::make_tuple(assure<std::remove_const_t<Owned>>()..., assure<std::remove_const_t<Get>>()...);
+        const auto cpools = std::forward_as_tuple(assure<std::remove_const_t<Owned>>()..., assure<std::remove_const_t<Get>>()...);
         constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude);
         handler_type *handler = nullptr;
 
@@ -1265,13 +1262,13 @@ public:
                 }
             } else {
                 // we cannot iterate backwards because we want to leave behind valid entities in case of owned types
-                for(auto *first = std::get<0>(cpools)->data(), *last = first + std::get<0>(cpools)->size(); first != last; ++first) {
+                for(auto *first = std::get<0>(cpools).data(), *last = first + std::get<0>(cpools).size(); first != last; ++first) {
                     handler->template maybe_valid_if<type_list_element_t<0, type_list<std::remove_const_t<Owned>...>>>(*this, *first);
                 }
             }
         }
 
-        return {handler->current, *std::get<storage_type<std::remove_const_t<Owned>> *>(cpools)..., *std::get<storage_type<std::remove_const_t<Get>> *>(cpools)...};
+        return {handler->current, std::get<storage_type<std::remove_const_t<Owned>> &>(cpools)..., std::get<storage_type<std::remove_const_t<Get>> &>(cpools)...};
     }
 
     /*! @copydoc group */
@@ -1288,7 +1285,7 @@ public:
             return {};
         } else {
             using handler_type = group_handler<exclude_t<Exclude...>, get_t<std::remove_const_t<Get>...>, std::remove_const_t<Owned>...>;
-            return {static_cast<handler_type *>(it->group.get())->current, *pool_if_exists<std::remove_const_t<Owned>>()..., *pool_if_exists<std::remove_const_t<Get>>()...};
+            return {static_cast<handler_type *>(it->group.get())->current, assure<std::remove_const_t<Owned>>()..., assure<std::remove_const_t<Get>>()...};
         }
     }
 
@@ -1370,13 +1367,13 @@ public:
     template<typename Component, typename Compare, typename Sort = std_sort, typename... Args>
     void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
         ENTT_ASSERT(sortable<Component>(), "Cannot sort owned storage");
-        auto *cpool = assure<Component>();
+        auto &cpool = assure<Component>();
 
-        if constexpr(std::is_invocable_v<Compare, decltype(cpool->get({})), decltype(cpool->get({}))>) {
-            auto comp = [cpool, compare = std::move(compare)](const auto lhs, const auto rhs) { return compare(std::as_const(cpool->get(lhs)), std::as_const(cpool->get(rhs))); };
-            cpool->sort(std::move(comp), std::move(algo), std::forward<Args>(args)...);
+        if constexpr(std::is_invocable_v<Compare, decltype(cpool.get({})), decltype(cpool.get({}))>) {
+            auto comp = [&cpool, compare = std::move(compare)](const auto lhs, const auto rhs) { return compare(std::as_const(cpool.get(lhs)), std::as_const(cpool.get(rhs))); };
+            cpool.sort(std::move(comp), std::move(algo), std::forward<Args>(args)...);
         } else {
-            cpool->sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
+            cpool.sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
         }
     }
 
@@ -1407,7 +1404,7 @@ public:
     template<typename To, typename From>
     void sort() {
         ENTT_ASSERT(sortable<To>(), "Cannot sort owned storage");
-        assure<To>()->respect(*assure<From>());
+        assure<To>().respect(assure<From>());
     }
 
     /**
@@ -1576,7 +1573,7 @@ public:
     }
 
 private:
-    mutable dense_hash_map<id_type, pool_data, identity> pools{};
+    dense_hash_map<id_type, pool_data, identity> pools{};
     dense_hash_map<id_type, basic_any<0u>, identity> vars{};
     std::vector<group_data> groups{};
     std::vector<entity_type> entities{};

+ 18 - 18
test/entt/entity/view.cpp

@@ -135,18 +135,18 @@ TEST(SingleComponentView, LazyTypeFromConstRegistry) {
     ASSERT_TRUE(cview);
     ASSERT_TRUE(eview);
 
-    ASSERT_NE(cview.raw(), nullptr);
-    ASSERT_NE(eview.data(), nullptr);
-
-    ASSERT_FALSE(cview.empty());
-    ASSERT_EQ(eview.size(), 1u);
-    ASSERT_TRUE(cview.contains(entity));
-
-    ASSERT_NE(cview.begin(), cview.end());
-    ASSERT_NE(eview.rbegin(), eview.rend());
-    ASSERT_NE(eview.find(entity), eview.end());
-    ASSERT_EQ(cview.front(), entity);
-    ASSERT_EQ(eview.back(), entity);
+    ASSERT_EQ(cview.raw(), nullptr);
+    ASSERT_EQ(eview.data(), nullptr);
+
+    ASSERT_TRUE(cview.empty());
+    ASSERT_EQ(eview.size(), 0u);
+    ASSERT_FALSE(cview.contains(entity));
+
+    ASSERT_EQ(cview.begin(), cview.end());
+    ASSERT_EQ(eview.rbegin(), eview.rend());
+    ASSERT_EQ(eview.find(entity), eview.end());
+    ASSERT_NE(cview.front(), entity);
+    ASSERT_NE(eview.back(), entity);
 }
 
 TEST(SingleComponentView, ElementAccess) {
@@ -572,13 +572,13 @@ TEST(MultiComponentView, LazyTypesFromConstRegistry) {
 
     ASSERT_TRUE(view);
 
-    ASSERT_EQ(view.size_hint(), 1u);
-    ASSERT_TRUE(view.contains(entity));
+    ASSERT_EQ(view.size_hint(), 0u);
+    ASSERT_FALSE(view.contains(entity));
 
-    ASSERT_NE(view.begin(), view.end());
-    ASSERT_NE(view.find(entity), view.end());
-    ASSERT_EQ(view.front(), entity);
-    ASSERT_EQ(view.back(), entity);
+    ASSERT_EQ(view.begin(), view.end());
+    ASSERT_EQ(view.find(entity), view.end());
+    ASSERT_NE(view.front(), entity);
+    ASSERT_NE(view.back(), entity);
 }
 
 TEST(MultiComponentView, LazyExcludedTypeFromConstRegistry) {