Michele Caini 7 лет назад
Родитель
Сommit
d6ef0956e6
1 измененных файлов с 38 добавлено и 20 удалено
  1. 38 20
      src/entt/entity/view.hpp

+ 38 - 20
src/entt/entity/view.hpp

@@ -459,6 +459,9 @@ class View final {
     template<typename Comp>
     using pool_type = SparseSet<Entity, Comp>;
 
+    template<typename Comp>
+    using component_iterator_type = typename pool_type<Comp>::const_iterator_type;
+
     using view_type = SparseSet<Entity>;
     using underlying_iterator_type = typename view_type::const_iterator_type;
     using unchecked_type = std::array<const view_type *, (sizeof...(Component) - 1)>;
@@ -566,11 +569,43 @@ class View final {
 
     template<typename Comp, typename Other>
     inline std::enable_if_t<std::is_same<Comp, Other>::value, const Other &>
-    get(const typename pool_type<Comp>::const_iterator_type &it, Entity) const ENTT_NOEXCEPT { return *it; }
+    get(const component_iterator_type<Comp> &it, Entity) const ENTT_NOEXCEPT { return *it; }
 
     template<typename Comp, typename Other>
     inline std::enable_if_t<!std::is_same<Comp, Other>::value, const Other &>
-    get(const typename pool_type<Comp>::const_iterator_type &, Entity entity) const ENTT_NOEXCEPT { return pool<Other>().get(entity); }
+    get(const component_iterator_type<Comp> &, Entity entity) const ENTT_NOEXCEPT { return pool<Other>().get(entity); }
+
+    template<typename Comp, typename Func, std::size_t... Indexes>
+    void each(const pool_type<Comp> &cpool, Func func, std::index_sequence<Indexes...>) const {
+        const auto other = unchecked(&cpool);
+        std::array<underlying_iterator_type, sizeof...(Component)> data{{cpool.view_type::cbegin(), std::get<Indexes>(other)->cbegin()...}};
+        auto raw = std::make_tuple(pool<Component>().cbegin()...);
+        const auto end = cpool.view_type::cend();
+        std::size_t pos{};
+
+        // we can directly use the raw iterators if pools are ordered
+        while(!pos && data[0] != end) {
+            for(pos = data.size() - 1; pos && *(data[pos]++) == *data[pos-1]; --pos);
+
+            if(!pos) {
+                func(*(data[0]++), *(std::get<component_iterator_type<Component>>(raw)++)...);
+            }
+        }
+
+        auto it = std::get<component_iterator_type<Comp>>(raw);
+        const auto ext = extent();
+
+        // fallback to visit what remains using indirections
+        for(; data[0] != end; ++data[0], ++it) {
+            const auto entity = *data[0];
+            const auto sz = size_type(entity & traits_type::entity_mask);
+
+            if(sz < ext && std::all_of(other.cbegin(), other.cend(), [entity](const view_type *view) { return view->fast(entity); })) {
+                // avoided at least the indirection due to the sparse set for the pivot type (see get for more details)
+                func(entity, get<Comp, Component>(it, entity)...);
+            }
+        }
+    }
 
 public:
     /*! @brief Input iterator type. */
@@ -832,26 +867,9 @@ public:
      */
     template<typename Func>
     void each(Func func) const {
-        auto iterate = [&func, this](const auto &cpool) {
-            const auto other = unchecked(&cpool);
-            const auto ext = extent();
-            auto raw = cpool.cbegin();
-
-            for(const auto entity: static_cast<const view_type &>(cpool)) {
-                const auto sz = size_type(entity & traits_type::entity_mask);
-
-                if(sz < ext && std::all_of(other.cbegin(), other.cend(), [entity](const view_type *view) { return view->fast(entity); })) {
-                    // avoided indirections due to the sparse set for the pivot type (see get for more details)
-                    func(entity, get<typename std::decay_t<decltype(cpool)>::object_type, Component>(raw, entity)...);
-                }
-
-                ++raw;
-            }
-        };
-
         const auto *view = candidate();
         using accumulator_type = int[];
-        accumulator_type accumulator = { (&pool<Component>() == view ? (iterate(pool<Component>()), 0) : 0)... };
+        accumulator_type accumulator = { (&pool<Component>() == view ? (each(pool<Component>(), std::move(func), std::make_index_sequence<sizeof...(Component)-1>{}), 0) : 0)... };
         (void)accumulator;
     }