Przeglądaj źródła

improved multi component view

Michele Caini 7 lat temu
rodzic
commit
70608df843

+ 0 - 1
TODO

@@ -21,4 +21,3 @@
 * add a sort of "fast each" for when users know they are not to add/remove components, it can use directly raw access and improve even further performance
 * types defined at runtime that refer to the same compile-time type (but to different pools) are possible, the library is almost there
 * view/group iterators that return entities and components? I'd still like to have it :-)
-* use try_get in the multi component view (each), it should have better perf

+ 2 - 25
src/entt/core/type_traits.hpp

@@ -2,6 +2,7 @@
 #define ENTT_CORE_TYPE_TRAITS_HPP
 
 
+#include <tuple>
 #include <type_traits>
 #include "../core/hashed_string.hpp"
 
@@ -10,32 +11,8 @@ namespace entt {
 
 
 /*! @brief A class to use to push around lists of types, nothing more. */
-template<typename...>
-struct type_list {};
-
-
-/**
- * @brief Concatenates multiple type lists into one.
- * @tparam Type List of types.
- * @return The given type list.
- */
 template<typename... Type>
-constexpr auto type_list_cat(type_list<Type...> = type_list<>{}) {
-    return type_list<Type...>{};
-}
-
-
-/**
- * @brief Concatenates multiple type lists into one.
- * @tparam Type List of types.
- * @tparam Other List of types.
- * @tparam List Type list instances.
- * @return A type list that is the concatenation of the given type lists.
- */
-template<typename... Type, typename... Other, typename... List>
-constexpr auto type_list_cat(type_list<Type...>, type_list<Other...>, List...) {
-    return type_list_cat(type_list<Type..., Other...>{}, List{}...);
-}
+using type_list = std::tuple<Type *...>;
 
 
 /*! @brief Traits class used mainly to push things across boundaries. */

+ 1 - 1
src/entt/entity/registry.hpp

@@ -1217,7 +1217,7 @@ public:
     void orphans(Func func) const {
         static_assert(std::is_invocable_v<Func, entity_type>);
 
-        each([func = std::move(func), this](const auto entity) {
+        each([&func, this](const auto entity) {
             if(orphan(entity)) {
                 func(entity);
             }

+ 18 - 46
src/entt/entity/view.hpp

@@ -10,7 +10,6 @@
 #include <algorithm>
 #include <type_traits>
 #include "../config/config.h"
-#include "../core/type_traits.hpp"
 #include "entt_traits.hpp"
 #include "sparse_set.hpp"
 #include "fwd.hpp"
@@ -66,7 +65,7 @@ class basic_view {
     using pool_type = std::conditional_t<std::is_const_v<Comp>, const sparse_set<Entity, std::remove_const_t<Comp>>, sparse_set<Entity, Comp>>;
 
     template<typename Comp>
-    using component_iterator_type = decltype(std::declval<pool_type<Comp>>().begin());
+    using component_type = std::remove_reference_t<decltype(std::declval<pool_type<Comp>>().get(0))>;
 
     using underlying_iterator_type = typename sparse_set<Entity>::iterator_type;
     using unchecked_type = std::array<const sparse_set<Entity> *, (sizeof...(Component) - 1)>;
@@ -161,50 +160,23 @@ class basic_view {
         return other;
     }
 
-    template<typename Comp, typename Other>
-    inline Other & get([[maybe_unused]] component_iterator_type<Comp> it, [[maybe_unused]] const Entity entt) const ENTT_NOEXCEPT {
-        if constexpr(std::is_same_v<Comp, Other>) {
-            return *it;
-        } else {
-            return std::get<pool_type<Other> *>(pools)->get(entt);
-        }
-    }
-
-    template<typename Comp, typename Func, auto... Indexes>
-    void each(pool_type<Comp> *cpool, Func func, std::index_sequence<Indexes...>) const {
-        const auto other = unchecked(cpool);
-        std::array<underlying_iterator_type, sizeof...(Indexes)> data{{std::get<Indexes>(other)->begin()...}};
-        const auto extent = std::min({ std::get<pool_type<Component> *>(pools)->extent()... });
-        auto raw = std::make_tuple(std::get<pool_type<Component> *>(pools)->begin()...);
-        const auto end = cpool->sparse_set<Entity>::end();
-        auto begin = cpool->sparse_set<Entity>::begin();
-
-        // we can directly use the raw iterators if pools are ordered
-        if constexpr(std::is_invocable_v<Func, std::add_lvalue_reference_t<Component>...>) {
-            for(; ((begin != end) && ... && (*begin == *(std::get<Indexes>(data)++))); ++begin) {
-                func(*(std::get<component_iterator_type<Component>>(raw)++)...);
-            }
-        } else {
-            while(((begin != end) && ... && (*begin == *(std::get<Indexes>(data)++)))) {
-                func(*(begin++), *(std::get<component_iterator_type<Component>>(raw)++)...);
-            }
-        }
+    template<typename Comp, typename... Other, typename Func>
+    void each(std::tuple<Comp *, Other *...> pack, Func func) const {
+        const auto end = std::get<pool_type<Comp> *>(pools)->sparse_set<Entity>::end();
+        auto begin = std::get<pool_type<Comp> *>(pools)->sparse_set<Entity>::begin();
+        auto raw = std::get<pool_type<Comp> *>(pools)->begin();
 
-        // fallback to visit what remains using indirections
-        while(begin != end) {
-            const auto entt = *(begin++);
-            const auto it = std::get<component_iterator_type<Comp>>(raw)++;
-            const auto sz = size_type(entt & traits_type::entity_mask);
+        std::for_each(begin, end, [&pack, &func, &raw, this](const auto entity) {
+            std::get<component_type<Comp> *>(pack) = &*raw++;
 
-            if(((sz < extent) && ... && std::get<Indexes>(other)->unsafe_has(entt))) {
-                // avoided at least the indirection due to the sparse set for the pivot type (see get for more details)
+            if(((std::get<component_type<Other> *>(pack) = std::get<pool_type<Other> *>(pools)->try_get(entity)) && ...)) {
                 if constexpr(std::is_invocable_v<Func, std::add_lvalue_reference_t<Component>...>) {
-                    func(get<Comp, Component>(it, entt)...);
+                    func(*std::get<component_type<Component> *>(pack)...);
                 } else {
-                    func(entt, get<Comp, Component>(it, entt)...);
+                    func(entity, *std::get<component_type<Component> *>(pack)...);
                 }
             }
-        }
+        });
     }
 
 public:
@@ -403,9 +375,9 @@ public:
      * @param func A valid function object.
      */
     template<typename Func>
-    void each(Func func) const {
+    inline void each(Func func) const {
         const auto *view = candidate();
-        ((std::get<pool_type<Component> *>(pools) == view ? each<Component>(std::get<pool_type<Component> *>(pools), std::move(func), std::make_index_sequence<sizeof...(Component)-1>{}) : void()), ...);
+        ((std::get<pool_type<Component> *>(pools) == view ? each<Component>(std::move(func)) : void()), ...);
     }
 
     /**
@@ -423,7 +395,7 @@ public:
      * void(Component &...);
      * @endcode
      *
-     * The pool of the suggested component is used to drive iterations. The
+     * The pool of the suggested component is used to lead the iterations. The
      * returned entities will therefore respect the order of the pool associated
      * with that type.<br/>
      * It is no longer guaranteed that the performance is the best possible, but
@@ -433,8 +405,8 @@ public:
      * @param func A valid function object.
      */
     template<typename Comp, typename Func>
-    void each(Func func) const {
-        each<Comp>(std::get<pool_type<Comp> *>(pools), std::move(func), std::make_index_sequence<sizeof...(Component)-1>{});
+    inline void each(Func func) const {
+        each(std::tuple_cat(std::tuple<Comp *>{}, std::conditional_t<std::is_same_v<Comp *, Component *>, std::tuple<>, std::tuple<Component *>>{}...), std::move(func));
     }
 
 private:
@@ -658,7 +630,7 @@ public:
         if constexpr(std::is_invocable_v<Func, std::add_lvalue_reference_t<Component>>) {
             std::for_each(pool->begin(), pool->end(), std::move(func));
         } else {
-            std::for_each(pool->sparse_set<Entity>::begin(), pool->sparse_set<Entity>::end(), [func = std::move(func), raw = pool->begin()](const auto entt) mutable {
+            std::for_each(pool->sparse_set<Entity>::begin(), pool->sparse_set<Entity>::end(), [&func, raw = pool->begin()](const auto entt) mutable {
                 func(entt, *(raw++));
             });
         }

+ 0 - 1
test/CMakeLists.txt

@@ -87,7 +87,6 @@ SETUP_AND_ADD_TEST(family entt/core/family.cpp)
 SETUP_AND_ADD_TEST(hashed_string entt/core/hashed_string.cpp)
 SETUP_AND_ADD_TEST(ident entt/core/ident.cpp)
 SETUP_AND_ADD_TEST(monostate entt/core/monostate.cpp)
-SETUP_AND_ADD_TEST(type_traits entt/core/type_traits.cpp)
 SETUP_AND_ADD_TEST(utility entt/core/utility.cpp)
 
 # Test entity

+ 0 - 22
test/entt/core/type_traits.cpp

@@ -1,22 +0,0 @@
-#include <type_traits>
-#include <gtest/gtest.h>
-#include <entt/core/type_traits.hpp>
-
-TEST(TypeTraits, TypeList) {
-    static_assert(std::is_same_v<
-        decltype(entt::type_list_cat()),
-        entt::type_list<>
-    >);
-
-    static_assert(std::is_same_v<
-        decltype(entt::type_list_cat(entt::type_list<int>{})),
-        entt::type_list<int>
-    >);
-
-    static_assert(std::is_same_v<
-        decltype(entt::type_list_cat(entt::type_list<int, char>{}, entt::type_list<>{}, entt::type_list<double, void>{})),
-        entt::type_list<int, char, double, void>
-    >);
-
-    SUCCEED();
-}