瀏覽代碼

entity/*: use pool introspection rather than is_empty for filtering

Michele Caini 5 年之前
父節點
當前提交
6f1366dbb5
共有 5 個文件被更改,包括 96 次插入138 次删除
  1. 43 71
      src/entt/entity/group.hpp
  2. 2 2
      src/entt/entity/pool.hpp
  3. 2 2
      src/entt/entity/registry.hpp
  4. 8 9
      src/entt/entity/snapshot.hpp
  5. 41 54
      src/entt/entity/view.hpp

+ 43 - 71
src/entt/entity/group.hpp

@@ -74,17 +74,14 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>> final {
     class iterable_group final {
         friend class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>>;
 
-        template<typename, typename>
-        class iterable_group_iterator;
-
-        template<typename It, typename... Type>
-        class iterable_group_iterator<It, type_list<Type...>> final {
+        template<typename It>
+        class iterable_group_iterator final {
             friend class iterable_group;
 
             template<typename... Args>
             iterable_group_iterator(It from, const std::tuple<pool_type<Get> *...> &args) ENTT_NOEXCEPT
                 : it{from},
-                  pools{std::get<pool_type<Type> *>(args)...}
+                  pools{args}
             {}
 
         public:
@@ -105,7 +102,7 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>> final {
 
             [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
                 const auto entt = *it;
-                return std::tuple_cat(std::make_tuple(entt), std::forward_as_tuple(std::get<pool_type<Type> *>(pools)->get(entt)...));
+                return std::tuple_cat(std::make_tuple(entt), std::get<pool_type<Get> *>(pools)->get_as_tuple(entt)...);
             }
 
             [[nodiscard]] bool operator==(const iterable_group_iterator &other) const ENTT_NOEXCEPT {
@@ -118,7 +115,7 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>> final {
 
         private:
             It it;
-            const std::tuple<pool_type<Type> *...> pools;
+            const std::tuple<pool_type<Get> *...> pools;
         };
 
         iterable_group(basic_sparse_set<Entity> &ref, const std::tuple<pool_type<Get> *...> &cpools)
@@ -127,14 +124,8 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>> final {
         {}
 
     public:
-        using iterator = iterable_group_iterator<
-            typename basic_sparse_set<Entity>::iterator,
-            type_list_cat_t<std::conditional_t<is_empty_v<Get>, type_list<>, type_list<Get>>...>
-        >;
-        using reverse_iterator = iterable_group_iterator<
-            typename basic_sparse_set<Entity>::reverse_iterator,
-            type_list_cat_t<std::conditional_t<is_empty_v<Get>, type_list<>, type_list<Get>>...>
-        >;
+        using iterator = iterable_group_iterator<typename basic_sparse_set<Entity>::iterator>;
+        using reverse_iterator = iterable_group_iterator<typename basic_sparse_set<Entity>::reverse_iterator>;
 
         [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
             return { handler->begin(), pools };
@@ -162,17 +153,6 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>> final {
           pools{&gpool...}
     {}
 
-    template<typename Func, typename... Weak>
-    void traverse(Func func, type_list<Weak...>) const {
-        for(const auto entt: *handler) {
-            if constexpr(std::is_invocable_v<Func, entity_type, decltype(get<Weak>({}))...>) {
-                func(entt, std::get<pool_type<Weak> *>(pools)->get(entt)...);
-            } else {
-                func(std::get<pool_type<Weak> *>(pools)->get(entt)...);
-            }
-        }
-    }
-
 public:
     /*! @brief Underlying entity identifier. */
     using entity_type = Entity;
@@ -405,17 +385,11 @@ public:
         ENTT_ASSERT(contains(entt));
 
         if constexpr(sizeof...(Component) == 0) {
-            return std::tuple_cat([entt](auto *cpool) {
-                if constexpr(is_empty_v<typename std::remove_reference_t<decltype(*cpool)>::value_type>) {
-                    return std::tuple{};
-                } else {
-                    return std::forward_as_tuple(cpool->get(entt));
-                }
-            }(std::get<pool_type<Get> *>(pools))...);
+            return std::tuple_cat(std::get<pool_type<Get> *>(pools)->get_as_tuple(entt)...);
         } else if constexpr(sizeof...(Component) == 1) {
             return (std::get<pool_type<Component> *>(pools)->get(entt), ...);
         } else {
-            return std::forward_as_tuple(get<Component>(entt)...);
+            return std::tuple_cat(std::get<pool_type<Component> *>(pools)->get_as_tuple(entt)...);
         }
     }
 
@@ -443,7 +417,13 @@ public:
      */
     template<typename Func>
     void each(Func func) const {
-        traverse(std::move(func), (std::conditional_t<is_empty_v<Get>, type_list<>, type_list<Get>>{} + ...));
+        for(const auto entt: *handler) {
+            if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::make_tuple(entt), get({})))>) {
+                std::apply(func, std::tuple_cat(std::make_tuple(entt), get(entt)));
+            } else {
+                std::apply(func, get(entt));
+            }
+        }
     }
 
     /**
@@ -599,18 +579,18 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> final
     class iterable_group final {
         friend class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...>;
 
-        template<typename, typename, typename>
+        template<typename, typename>
         class iterable_group_iterator;
 
-        template<typename It, typename... OIt, typename... Type>
-        class iterable_group_iterator<It, type_list<OIt...>, type_list<Type...>> final {
+        template<typename It, typename... OIt>
+        class iterable_group_iterator<It, type_list<OIt...>> final {
             friend class iterable_group;
 
             template<typename... Other>
             iterable_group_iterator(It from, const std::tuple<Other...> &other, const std::tuple<pool_type<Get> *...> &cpools) ENTT_NOEXCEPT
                 : it{from},
                   owned{std::get<OIt>(other)...},
-                  get{std::get<pool_type<Type> *>(cpools)...}
+                  get{cpools}
             {}
 
         public:
@@ -633,7 +613,7 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> final
                 return std::tuple_cat(
                     std::make_tuple(*it),
                     std::forward_as_tuple(*std::get<OIt>(owned)...),
-                    std::forward_as_tuple(std::get<pool_type<Type> *>(get)->get(*it)...)
+                    std::get<pool_type<Get> *>(get)->get_as_tuple(*it)...
                 );
             }
 
@@ -648,7 +628,7 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> final
         private:
             It it;
             std::tuple<OIt...> owned;
-            std::tuple<pool_type<Type> *...> get;
+            std::tuple<pool_type<Get> *...> get;
         };
 
         iterable_group(std::tuple<pool_type<Owned> *..., pool_type<Get> *...> cpools, const std::size_t &extent)
@@ -659,13 +639,11 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> final
     public:
         using iterator = iterable_group_iterator<
             typename basic_sparse_set<Entity>::iterator,
-            type_list_cat_t<std::conditional_t<is_empty_v<Owned>, type_list<>, type_list<decltype(std::declval<pool_type<Owned>>().end())>>...>,
-            type_list_cat_t<std::conditional_t<is_empty_v<Get>, type_list<>, type_list<Get>>...>
+            type_list_cat_t<std::conditional_t<std::tuple_size_v<decltype(std::declval<pool_type<Owned>>().get_as_tuple({}))> == 0, type_list<>, type_list<decltype(std::declval<pool_type<Owned>>().end())>>...>
         >;
         using reverse_iterator = iterable_group_iterator<
             typename basic_sparse_set<Entity>::reverse_iterator,
-            type_list_cat_t<std::conditional_t<is_empty_v<Owned>, type_list<>, type_list<decltype(std::declval<pool_type<Owned>>().rbegin())>>...>,
-            type_list_cat_t<std::conditional_t<is_empty_v<Get>, type_list<>, type_list<Get>>...>
+            type_list_cat_t<std::conditional_t<std::tuple_size_v<decltype(std::declval<pool_type<Owned>>().get_as_tuple({}))> == 0, type_list<>, type_list<decltype(std::declval<pool_type<Owned>>().rbegin())>>...>
         >;
 
         [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
@@ -710,22 +688,6 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> final
           length{&extent}
     {}
 
-    template<typename Func, typename... Strong, typename... Weak>
-    void traverse(Func func, type_list<Strong...>, type_list<Weak...>) const {
-        [[maybe_unused]] auto it = std::make_tuple((std::get<pool_type<Strong> *>(pools)->end() - *length)...);
-        [[maybe_unused]] auto data = std::get<0>(pools)->basic_sparse_set<entity_type>::end() - *length;
-
-        for(auto next = *length; next; --next) {
-            const auto entt = *(data++);
-
-            if constexpr(std::is_invocable_v<Func, entity_type, decltype(get<Strong>({}))..., decltype(get<Weak>({}))...>) {
-                func(entt, *(std::get<decltype(std::get<pool_type<Strong> *>(pools)->end())>(it)++)..., std::get<pool_type<Weak> *>(pools)->get(entt)...);
-            } else {
-                func(*(std::get<decltype(std::get<pool_type<Strong> *>(pools)->end())>(it)++)..., std::get<pool_type<Weak> *>(pools)->get(entt)...);
-            }
-        }
-    }
-
 public:
     /*! @brief Underlying entity identifier. */
     using entity_type = Entity;
@@ -951,14 +913,10 @@ public:
 
         if constexpr(sizeof...(Component) == 0) {
             auto filter = [entt, index = std::get<0>(pools)->index(entt)](auto *cpool) {
-                using value_type = typename std::remove_reference_t<decltype(*cpool)>::value_type;
-
-                if constexpr(is_empty_v<value_type>) {
-                    return std::tuple{};
-                } else if constexpr((std::is_same_v<value_type, std::remove_const_t<Owned>> || ...)) {
+                if constexpr(std::tuple_size_v<decltype(cpool->get_as_tuple({}))> != 0 && (std::is_same_v<typename std::remove_reference_t<decltype(*cpool)>::value_type, std::remove_const_t<Owned>> || ...)) {
                     return std::forward_as_tuple(cpool->raw()[index]);
                 } else {
-                    return std::forward_as_tuple(cpool->get(entt));
+                    return cpool->get_as_tuple(entt);
                 }
             };
 
@@ -994,9 +952,23 @@ public:
      */
     template<typename Func>
     void each(Func func) const {
-        traverse(std::move(func),
-            (std::conditional_t<is_empty_v<Owned>, type_list<>, type_list<Owned>>{} + ...),
-            (type_list<>{} + ... + std::conditional_t<is_empty_v<Get>, type_list<>, type_list<Get>>{}));
+        auto owned = std::tuple_cat([length = *length](auto *cpool) {
+            if constexpr(std::tuple_size_v<decltype(cpool->get_as_tuple({}))> == 0) {
+                return std::make_tuple();
+            } else {
+                return std::make_tuple(cpool->end() - length);
+            }
+        }(std::get<pool_type<Owned> *>(pools))...);
+
+        for(const auto entt: *this) {
+            auto args = std::tuple_cat(std::apply([](auto &&... curr) { return std::forward_as_tuple(*curr++...); }, owned), std::get<pool_type<Get> *>(pools)->get_as_tuple(entt)...);
+
+            if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::make_tuple(entt), get({})))>) {
+                std::apply(func, std::tuple_cat(std::make_tuple(entt), args));
+            } else {
+                std::apply(func, args);
+            }
+        }
     }
 
     /**

+ 2 - 2
src/entt/entity/pool.hpp

@@ -179,7 +179,7 @@ struct sigh_storage_mixin: Type {
         Type::emplace(owner, entity, std::forward<Args>(args)...);
         construction.publish(owner, entity);
 
-        if constexpr(!is_empty_v<value_type>) {
+        if constexpr(std::tuple_size_v<decltype(Type::get_as_tuple({}))> != 0) {
             return this->get(entity);
         }
     }
@@ -244,7 +244,7 @@ struct sigh_storage_mixin: Type {
      */
     template<typename... Func>
     decltype(auto) patch(basic_registry<entity_type> &owner, const entity_type entity, [[maybe_unused]] Func &&... func) {
-        if constexpr(is_empty_v<value_type>) {
+        if constexpr(std::tuple_size_v<decltype(Type::get_as_tuple({}))> == 0) {
             update.publish(owner, entity);
         } else {
             Type::patch(owner, entity, std::forward<Func>(func)...);

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

@@ -813,7 +813,7 @@ public:
         if constexpr(sizeof...(Component) == 1) {
             return (assure<Component>().get(entity), ...);
         } else {
-            return std::forward_as_tuple(get<Component>(entity)...);
+            return std::tuple_cat(assure<Component>().get_as_tuple(entity)...);
         }
     }
 
@@ -825,7 +825,7 @@ public:
         if constexpr(sizeof...(Component) == 1) {
             return (assure<Component>().get(entity), ...);
         } else {
-            return std::forward_as_tuple(get<Component>(entity)...);
+            return std::tuple_cat(assure<Component>().get_as_tuple(entity)...);
         }
     }
 

+ 8 - 9
src/entt/entity/snapshot.hpp

@@ -3,13 +3,15 @@
 
 
 #include <array>
-#include <vector>
 #include <cstddef>
-#include <utility>
 #include <iterator>
+#include <tuple>
 #include <type_traits>
 #include <unordered_map>
+#include <utility>
+#include <vector>
 #include "../config/config.h"
+#include "../core/type_traits.hpp"
 #include "entity.hpp"
 #include "fwd.hpp"
 
@@ -36,17 +38,14 @@ class basic_snapshot {
 
     template<typename Component, typename Archive, typename It>
     void get(Archive &archive, std::size_t sz, It first, It last) const {
+        const auto view = reg->view<std::add_const_t<Component>>();
         archive(typename traits_type::entity_type(sz));
 
         while(first != last) {
             const auto entt = *(first++);
 
             if(reg->template has<Component>(entt)) {
-                if constexpr(std::is_empty_v<Component>) {
-                    archive(entt);
-                } else {
-                    archive(entt, reg->template get<Component>(entt));
-                }
+                std::apply(archive, std::tuple_cat(std::make_tuple(entt), view.get(entt)));
             }
         }
     }
@@ -173,7 +172,7 @@ class basic_snapshot_loader {
 
         entity_type entt{};
 
-        if constexpr(std::is_empty_v<Type>) {
+        if constexpr(std::tuple_size_v<decltype(reg->view<Type>().get({}))> == 0) {
             while(length--) {
                 archive(entt);
                 const auto entity = reg->valid(entt) ? entt : reg->create(entt);
@@ -392,7 +391,7 @@ class basic_continuous_loader {
 
         entity_type entt{};
 
-        if constexpr(std::is_empty_v<Other>) {
+        if constexpr(std::tuple_size_v<decltype(reg->view<Other>().get({}))> == 0) {
             while(length--) {
                 archive(entt);
                 restore(entt);

+ 41 - 54
src/entt/entity/view.hpp

@@ -71,7 +71,6 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> final {
     template<typename Comp>
     using pool_type = pool_t<Entity, Comp>;
 
-    using return_type = type_list_cat_t<std::conditional_t<is_empty_v<Component>, type_list<>, type_list<Component>>...>;
     using unchecked_type = std::array<const basic_sparse_set<Entity> *, (sizeof...(Component) - 1)>;
 
     template<typename It>
@@ -230,7 +229,7 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> final {
     {}
 
     [[nodiscard]] const basic_sparse_set<Entity> * candidate() const ENTT_NOEXCEPT {
-        return (std::min)({ static_cast<const basic_sparse_set<Entity> *>(std::get<pool_type<Component> *>(pools))... }, [](const auto *lhs, const auto *rhs) {
+        return (std::min)({ static_cast<const basic_sparse_set<entity_type> *>(std::get<pool_type<Component> *>(pools))... }, [](const auto *lhs, const auto *rhs) {
             return lhs->size() < rhs->size();
         });
     }
@@ -243,43 +242,43 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> final {
     }
 
     template<typename It, typename Pool>
-    [[nodiscard]] decltype(auto) get([[maybe_unused]] It &it, [[maybe_unused]] Pool *cpool, [[maybe_unused]] const Entity entt) const {
+    [[nodiscard]] auto get_as_tuple([[maybe_unused]] It &it, [[maybe_unused]] Pool *cpool, [[maybe_unused]] const Entity entt) const {
         if constexpr(std::is_same_v<typename std::iterator_traits<It>::value_type, typename Pool::value_type>) {
-            return *it;
+            return std::forward_as_tuple(*it);
         } else {
-            return cpool->get(entt);
+            return cpool->get_as_tuple(entt);
         }
     }
 
-    template<typename Comp, typename Func, typename... Type>
-    void traverse(Func func, type_list<Type...>) const {
-        if constexpr(std::disjunction_v<std::is_same<Comp, Type>...>) {
-            auto it = std::get<pool_type<Comp> *>(pools)->begin();
-
+    template<typename Comp, typename Func>
+    void traverse(Func func) const {
+        if constexpr(std::tuple_size_v<decltype(std::declval<pool_type<Comp>>().get_as_tuple({}))> == 0) {
             for(const auto entt: static_cast<const basic_sparse_set<entity_type> &>(*std::get<pool_type<Comp> *>(pools))) {
                 if(((std::is_same_v<Comp, Component> || std::get<pool_type<Component> *>(pools)->contains(entt)) && ...)
                     && !(std::get<const pool_type<Exclude> *>(filter)->contains(entt) || ...))
                 {
-                    if constexpr(std::is_invocable_v<Func, entity_type, decltype(get<Type>({}))...>) {
-                        func(entt, get(it, std::get<pool_type<Type> *>(pools), entt)...);
+                    if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::make_tuple(entt), get({})))>) {
+                        std::apply(func, std::tuple_cat(std::make_tuple(entt), get(entt)));
                     } else {
-                        func(get(it, std::get<pool_type<Type> *>(pools), entt)...);
+                        std::apply(func, get(entt));
                     }
                 }
-
-                ++it;
             }
         } else {
+            auto it = std::get<pool_type<Comp> *>(pools)->begin();
+
             for(const auto entt: static_cast<const basic_sparse_set<entity_type> &>(*std::get<pool_type<Comp> *>(pools))) {
                 if(((std::is_same_v<Comp, Component> || std::get<pool_type<Component> *>(pools)->contains(entt)) && ...)
                     && !(std::get<const pool_type<Exclude> *>(filter)->contains(entt) || ...))
                 {
-                    if constexpr(std::is_invocable_v<Func, entity_type, decltype(get<Type>({}))...>) {
-                        func(entt, std::get<pool_type<Type> *>(pools)->get(entt)...);
+                    if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::make_tuple(entt), get({})))>) {
+                        std::apply(func, std::tuple_cat(std::make_tuple(entt), get_as_tuple(it, std::get<pool_type<Component> *>(pools), entt)...));
                     } else {
-                        func(std::get<pool_type<Type> *>(pools)->get(entt)...);
+                        std::apply(func, std::tuple_cat(get_as_tuple(it, std::get<pool_type<Component> *>(pools), entt)...));
                     }
                 }
+
+                ++it;
             }
         }
     }
@@ -423,17 +422,11 @@ public:
         ENTT_ASSERT(contains(entt));
 
         if constexpr(sizeof...(Comp) == 0) {
-            return std::tuple_cat([entt](auto *cpool) {
-                if constexpr(is_empty_v<typename std::remove_reference_t<decltype(*cpool)>::value_type>) {
-                    return std::tuple{};
-                } else {
-                    return std::forward_as_tuple(cpool->get(entt));
-                }
-            }(std::get<pool_type<Component> *>(pools))...);
+            return std::tuple_cat(std::get<pool_type<Component> *>(pools)->get_as_tuple(entt)...);
         } else if constexpr(sizeof...(Comp) == 1) {
             return (std::get<pool_type<Comp> *>(pools)->get(entt), ...);
         } else {
-            return std::forward_as_tuple(get<Comp>(entt)...);
+            return std::tuple_cat(std::get<pool_type<Comp> *>(pools)->get_as_tuple(entt)...);
         }
     }
 
@@ -461,7 +454,7 @@ public:
      */
     template<typename Func>
     void each(Func func) const {
-        ((std::get<pool_type<Component> *>(pools) == view ? traverse<Component>(std::move(func), return_type{}) : void()), ...);
+        ((std::get<pool_type<Component> *>(pools) == view ? traverse<Component>(std::move(func)) : void()), ...);
     }
 
     /**
@@ -483,7 +476,7 @@ public:
     template<typename Comp, typename Func>
     void each(Func func) const {
         use<Comp>();
-        traverse<Comp>(std::move(func), return_type{});
+        traverse<Comp>(std::move(func));
     }
 
     /**
@@ -618,12 +611,12 @@ class basic_view<Entity, exclude_t<>, Component> final {
 
     public:
         using iterator = std::conditional_t<
-            is_empty_v<Component>,
+            std::tuple_size_v<decltype(std::declval<pool_type>().get_as_tuple({}))> == 0,
             iterable_view_iterator<typename basic_sparse_set<Entity>::iterator>,
             iterable_view_iterator<typename basic_sparse_set<Entity>::iterator, decltype(std::declval<pool_type>().begin())>
         >;
         using reverse_iterator = std::conditional_t<
-            is_empty_v<Component>,
+            std::tuple_size_v<decltype(std::declval<pool_type>().get_as_tuple({}))> == 0,
             iterable_view_iterator<typename basic_sparse_set<Entity>::reverse_iterator>,
             iterable_view_iterator<typename basic_sparse_set<Entity>::reverse_iterator, decltype(std::declval<pool_type>().rbegin())>
         >;
@@ -721,7 +714,7 @@ public:
      * @return An iterator to the first entity of the view.
      */
     [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
-        return pool->basic_sparse_set<Entity>::begin();
+        return pool->basic_sparse_set<entity_type>::begin();
     }
 
     /**
@@ -734,7 +727,7 @@ public:
      * @return An iterator to the entity following the last entity of the view.
      */
     [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
-        return pool->basic_sparse_set<Entity>::end();
+        return pool->basic_sparse_set<entity_type>::end();
     }
 
     /**
@@ -746,7 +739,7 @@ public:
      * @return An iterator to the first entity of the reversed view.
      */
     [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
-        return pool->basic_sparse_set<Entity>::rbegin();
+        return pool->basic_sparse_set<entity_type>::rbegin();
     }
 
     /**
@@ -761,7 +754,7 @@ public:
      * reversed view.
      */
     [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
-        return pool->basic_sparse_set<Entity>::rend();
+        return pool->basic_sparse_set<entity_type>::rend();
     }
 
     /**
@@ -831,11 +824,7 @@ public:
     template<typename... Comp>
     [[nodiscard]] decltype(auto) get(const entity_type entt) const {
         if constexpr(sizeof...(Comp) == 0) {
-            if constexpr(is_empty_v<Component>) {
-                return std::tuple{};
-            } else {
-                return std::forward_as_tuple(pool->get(entt));
-            }
+            return pool->get_as_tuple(entt);
         } else {
             static_assert(std::is_same_v<Comp..., Component>, "Invalid component type");
             return pool->get(entt);
@@ -866,28 +855,26 @@ public:
      */
     template<typename Func>
     void each(Func func) const {
-        if constexpr(is_empty_v<Component>) {
-            if constexpr(std::is_invocable_v<Func, entity_type>) {
-                for(const auto entt: *this) {
-                    func(entt);
-                }
-            } else {
+        if constexpr(std::tuple_size_v<decltype(pool->get_as_tuple({}))> == 0) {
+            if constexpr(std::is_invocable_v<Func>) {
                 for(auto pos = pool->size(); pos; --pos) {
                     func();
                 }
-            }
-        } else {
-            if constexpr(std::is_invocable_v<Func, entity_type, std::add_lvalue_reference_t<Component>>) {
-                auto raw = pool->begin();
-
-                for(const auto entt: *this) {
-                    func(entt, *(raw++));
-                }
             } else {
-                for(auto &&component: *pool) {
+                for(auto &&component: *this) {
                     func(component);
                 }
             }
+        } else if constexpr(std::is_invocable_v<Func, entity_type, std::add_lvalue_reference_t<Component>>) {
+            auto raw = pool->begin();
+
+            for(const auto entt: *this) {
+                func(entt, *(raw++));
+            }
+        } else {
+            for(auto &&component: *pool) {
+                func(component);
+            }
         }
     }