Răsfoiți Sursa

group: optimized ranges

Michele Caini 5 ani în urmă
părinte
comite
dd28882b27
1 a modificat fișierele cu 198 adăugiri și 323 ștergeri
  1. 198 323
      src/entt/entity/group.hpp

+ 198 - 323
src/entt/entity/group.hpp

@@ -17,325 +17,6 @@
 namespace entt {
 
 
-/**
- * @brief Group range.
- *
- * Primary template isn't defined on purpose. All the specializations give a
- * compile-time error, but for a few reasonable cases.
- */
-template<typename...>
-class group_range;
-
-
-/**
- * @brief Non-owning group range.
- *
- * Iterable object to use to _visit_ a group.
- *
- * @sa group
- *
- * @tparam Entity A valid entity type (see entt_traits for more details).
- * @tparam Exclude Types of components used to filter the group.
- * @tparam Get Type of components observed by the group.
- */
-template<typename Entity, typename... Exclude, typename... Get>
-class group_range<Entity, exclude_t<Exclude...>, get_t<Get...>> {
-    /*! @brief A group is allowed to create ranges. */
-    friend class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>>;
-
-    // I could have used std::conditional_t ...
-    template<typename Comp>
-    struct pool { using type = storage<Entity, Comp>; };
-
-    // ... if only MSVC didn't have a bug ...
-    template<typename Comp>
-    struct pool<const Comp> { using type = const storage<Entity, std::remove_const_t<Comp>>; };
-
-    // ... that forces me to do the same in a worse way! :(
-    template<typename Comp>
-    using pool_type = typename pool<Comp>::type;
-
-    class range_iterator {
-        friend class group_range<Entity, exclude_t<Exclude...>, entt::get_t<Get...>>;
-
-        using it_type = typename sparse_set<Entity>::iterator;
-        using pool_type = decltype(std::tuple_cat(std::declval<std::conditional_t<ENTT_IS_EMPTY(Get), std::tuple<>, std::tuple<pool_type<Get> *>>>()...));
-
-        range_iterator(it_type from, pool_type ref) ENTT_NOEXCEPT
-            : it{from},
-              pools{ref}
-        {}
-
-    public:
-        using difference_type = std::ptrdiff_t;
-        using value_type = decltype(std::tuple_cat(
-            std::declval<std::tuple<Entity>>(),
-            std::declval<std::conditional_t<ENTT_IS_EMPTY(Get), std::tuple<>, std::tuple<Get &>>>()...
-        ));
-        using pointer = void;
-        using reference = value_type;
-        using iterator_category = std::input_iterator_tag;
-
-        range_iterator() ENTT_NOEXCEPT = default;
-
-        range_iterator & operator++() ENTT_NOEXCEPT {
-            return ++it, *this;
-        }
-
-        range_iterator operator++(int) ENTT_NOEXCEPT {
-            range_iterator orig = *this;
-            return ++(*this), orig;
-        }
-
-        [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
-            return std::apply([entt = *it](auto *... cpool) { return reference{entt, cpool->get(entt)...}; }, pools);
-        }
-
-        [[nodiscard]] bool operator==(const range_iterator &other) const ENTT_NOEXCEPT {
-            return other.it == it;
-        }
-
-        [[nodiscard]] bool operator!=(const range_iterator &other) const ENTT_NOEXCEPT {
-            return !(*this == other);
-        }
-
-    private:
-        it_type it;
-        pool_type pools;
-    };
-
-    group_range(const sparse_set<Entity> &ref, std::tuple<pool_type<Get> *...> gpools)
-        : handler{&ref},
-          pools{gpools}
-    {}
-
-public:
-    /*! @brief Underlying entity identifier. */
-    using entity_type = Entity;
-    /*! @brief Input iterator type. */
-    using iterator = range_iterator;
-
-    /**
-     * @brief Returns an iterator to the first element.
-     *
-     * The returned iterator points to the first element. If the range is empty,
-     * the returned iterator will be equal to `end()`.
-     *
-     * @note
-     * Iterators stay true to the order imposed to the underlying data
-     * structures.
-     *
-     * @return An iterator to the first element.
-     */
-    [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
-        return iterator{handler->begin(), std::tuple_cat([](auto *cpool) {
-            if constexpr(ENTT_IS_EMPTY(typename std::decay_t<decltype(*cpool)>::object_type)) {
-                return std::make_tuple();
-            } else {
-                return std::make_tuple(cpool);
-            }
-        }(std::get<pool_type<Get> *>(pools))...)};
-    }
-
-    /**
-     * @brief Returns an iterator that is past the last element.
-     *
-     * The returned iterator points to the element following the last element.
-     * Attempting to dereference the returned iterator results in undefined
-     * behavior.
-     *
-     * @note
-     * Iterators stay true to the order imposed to the underlying data
-     * structures.
-     *
-     * @return An iterator to the element following the last element that has
-     * the given components.
-     */
-    [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
-        return iterator{handler->end(), std::tuple_cat([](auto *cpool) {
-            if constexpr(ENTT_IS_EMPTY(typename std::decay_t<decltype(*cpool)>::object_type)) {
-                return std::make_tuple();
-            } else {
-                return std::make_tuple(cpool);
-            }
-        }(std::get<pool_type<Get> *>(pools))...)};
-    }
-
-private:
-    const sparse_set<Entity> *handler;
-    std::tuple<pool_type<Get> *...> pools;
-};
-
-
-/**
- * @brief Owning group range specialization.
- *
- * Iterable object to use to _visit_ a group.
- *
- * @sa group
- *
- * @tparam Entity A valid entity type (see entt_traits for more details).
- * @tparam Exclude Types of components used to filter the group.
- * @tparam Get Types of components observed by the group.
- * @tparam Owned Types of components owned by the group.
- */
-template<typename Entity, typename... Exclude, typename... Get, typename... Owned>
-class group_range<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> {
-    /*! @brief A group is allowed to create ranges. */
-    friend class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...>;
-
-    // I could have used std::conditional_t ...
-    template<typename Comp>
-    struct pool { using type = storage<Entity, Comp>; };
-
-    // ... if only MSVC didn't have a bug ...
-    template<typename Comp>
-    struct pool<const Comp> { using type = const storage<Entity, std::remove_const_t<Comp>>; };
-
-    // ... that forces me to do the same in a worse way! :(
-    template<typename Comp>
-    using pool_type = typename pool<Comp>::type;
-
-    class range_iterator {
-        friend class group_range<Entity, exclude_t<Exclude...>, entt::get_t<Get...>, Owned...>;
-
-        using it_type = typename sparse_set<Entity>::iterator;
-        using owned_type = decltype(std::tuple_cat(std::declval<std::conditional_t<ENTT_IS_EMPTY(Owned), std::tuple<>, std::tuple<decltype(std::declval<pool_type<Owned>>().begin())>>>()...));
-        using get_type = decltype(std::tuple_cat(std::declval<std::conditional_t<ENTT_IS_EMPTY(Get), std::tuple<>, std::tuple<pool_type<Get> *>>>()...));
-
-        range_iterator(it_type from, owned_type oref, get_type gref) ENTT_NOEXCEPT
-            : it{from},
-              owned{oref},
-              get{gref}
-        {}
-
-    public:
-        using difference_type = std::ptrdiff_t;
-        using value_type = decltype(std::tuple_cat(
-            std::declval<std::tuple<Entity>>(),
-            std::declval<std::conditional_t<ENTT_IS_EMPTY(Owned), std::tuple<>, std::tuple<Owned &>>>()...,
-            std::declval<std::conditional_t<ENTT_IS_EMPTY(Get), std::tuple<>, std::tuple<Get &>>>()...
-        ));
-        using pointer = void;
-        using reference = value_type;
-        using iterator_category = std::input_iterator_tag;
-
-        range_iterator() ENTT_NOEXCEPT = default;
-
-        range_iterator & operator++() ENTT_NOEXCEPT {
-            return ++it, std::apply([](auto &&... curr) { (++curr, ...); }, owned), *this;
-        }
-
-        range_iterator operator++(int) ENTT_NOEXCEPT {
-            range_iterator orig = *this;
-            return ++(*this), orig;
-        }
-
-        [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
-            return std::tuple_cat(
-                std::make_tuple(*it),
-                std::apply([](auto &&... curr) { return std::forward_as_tuple(*curr...); }, owned),
-                std::apply([entt = *it](auto &&... curr) { return std::forward_as_tuple(curr->get(entt)...); }, get)
-            );
-        }
-
-        [[nodiscard]] bool operator==(const range_iterator &other) const ENTT_NOEXCEPT {
-            return other.it == it;
-        }
-
-        [[nodiscard]] bool operator!=(const range_iterator &other) const ENTT_NOEXCEPT {
-            return !(*this == other);
-        }
-
-    private:
-        it_type it;
-        owned_type owned;
-        get_type get;
-    };
-
-    group_range(std::tuple<pool_type<Owned> *..., pool_type<Get> *...> cpools, const std::size_t &extent)
-        : pools{cpools},
-          length{&extent}
-    {}
-
-public:
-    /*! @brief Underlying entity identifier. */
-    using entity_type = Entity;
-    /*! @brief Input iterator type. */
-    using iterator = range_iterator;
-
-    /**
-     * @brief Returns an iterator to the first element.
-     *
-     * The returned iterator points to the first element. If the range is empty,
-     * the returned iterator will be equal to `end()`.
-     *
-     * @note
-     * Iterators stay true to the order imposed to the underlying data
-     * structures.
-     *
-     * @return An iterator to the first element.
-     */
-    [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
-        return iterator{
-            std::get<0>(pools)->sparse_set<Entity>::end() - *length,
-            std::tuple_cat([this](auto *cpool) {
-                if constexpr(ENTT_IS_EMPTY(typename std::decay_t<decltype(*cpool)>::object_type)) {
-                    return std::make_tuple();
-                } else {
-                    return std::make_tuple(cpool->end() - *length);
-                }
-            }(std::get<pool_type<Owned> *>(pools))...),
-            std::tuple_cat([](auto *cpool) {
-                if constexpr(ENTT_IS_EMPTY(typename std::decay_t<decltype(*cpool)>::object_type)) {
-                    return std::make_tuple();
-                } else {
-                    return std::make_tuple(cpool);
-                }
-            }(std::get<pool_type<Get> *>(pools))...)
-        };
-    }
-
-    /**
-     * @brief Returns an iterator that is past the last element.
-     *
-     * The returned iterator points to the element following the last element.
-     * Attempting to dereference the returned iterator results in undefined
-     * behavior.
-     *
-     * @note
-     * Iterators stay true to the order imposed to the underlying data
-     * structures.
-     *
-     * @return An iterator to the element following the last element that has
-     * the given components.
-     */
-    [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
-        return iterator{
-            std::get<0>(pools)->sparse_set<Entity>::end(),
-            std::tuple_cat([](auto *cpool) {
-                if constexpr(ENTT_IS_EMPTY(typename std::decay_t<decltype(*cpool)>::object_type)) {
-                    return std::make_tuple();
-                } else {
-                    return std::make_tuple(cpool->end());
-                }
-            }(std::get<pool_type<Owned> *>(pools))...),
-            std::tuple_cat([](auto *cpool) {
-                if constexpr(ENTT_IS_EMPTY(typename std::decay_t<decltype(*cpool)>::object_type)) {
-                    return std::make_tuple();
-                } else {
-                    return std::make_tuple(cpool);
-                }
-            }(std::get<pool_type<Get> *>(pools))...)
-        };
-    }
-
-private:
-    const std::tuple<pool_type<Owned> *..., pool_type<Get> *...> pools;
-    const std::size_t *length;
-};
-
-
 /**
  * @brief Group.
  *
@@ -399,6 +80,89 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>> {
     template<typename Component>
     using pool_type = typename pool<Component>::type;
 
+    class group_range {
+        friend class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>>;
+
+        class range_iterator {
+            friend class group_range;
+
+            using it_type = typename sparse_set<Entity>::iterator;
+            using pool_type = decltype(std::tuple_cat(std::declval<std::conditional_t<ENTT_IS_EMPTY(Get), std::tuple<>, std::tuple<pool_type<Get> *>>>()...));
+
+            range_iterator(it_type from, pool_type ref) ENTT_NOEXCEPT
+                : it{from},
+                  pools{ref}
+            {}
+
+        public:
+            using difference_type = std::ptrdiff_t;
+            using value_type = decltype(std::tuple_cat(
+                std::declval<std::tuple<Entity>>(),
+                std::declval<std::conditional_t<ENTT_IS_EMPTY(Get), std::tuple<>, std::tuple<Get &>>>()...
+            ));
+            using pointer = void;
+            using reference = value_type;
+            using iterator_category = std::input_iterator_tag;
+
+            range_iterator() ENTT_NOEXCEPT = default;
+
+            range_iterator & operator++() ENTT_NOEXCEPT {
+                return ++it, *this;
+            }
+
+            range_iterator operator++(int) ENTT_NOEXCEPT {
+                range_iterator orig = *this;
+                return ++(*this), orig;
+            }
+
+            [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
+                return std::apply([entt = *it](auto *... cpool) { return reference{entt, cpool->get(entt)...}; }, pools);
+            }
+
+            [[nodiscard]] bool operator==(const range_iterator &other) const ENTT_NOEXCEPT {
+                return other.it == it;
+            }
+
+            [[nodiscard]] bool operator!=(const range_iterator &other) const ENTT_NOEXCEPT {
+                return !(*this == other);
+            }
+
+        private:
+            it_type it;
+            pool_type pools;
+        };
+
+        group_range(const sparse_set<Entity> &ref, std::tuple<pool_type<Get> *...> gpools)
+            : handler{&ref},
+              pools{gpools}
+        {}
+
+    public:
+        [[nodiscard]] auto begin() const ENTT_NOEXCEPT {
+            return range_iterator{handler->begin(), std::tuple_cat([](auto *cpool) {
+                if constexpr(ENTT_IS_EMPTY(typename std::decay_t<decltype(*cpool)>::object_type)) {
+                    return std::make_tuple();
+                } else {
+                    return std::make_tuple(cpool);
+                }
+            }(std::get<pool_type<Get> *>(pools))...)};
+        }
+
+        [[nodiscard]] auto end() const ENTT_NOEXCEPT {
+            return range_iterator{handler->end(), std::tuple_cat([](auto *cpool) {
+                if constexpr(ENTT_IS_EMPTY(typename std::decay_t<decltype(*cpool)>::object_type)) {
+                    return std::make_tuple();
+                } else {
+                    return std::make_tuple(cpool);
+                }
+            }(std::get<pool_type<Get> *>(pools))...)};
+        }
+
+    private:
+        const sparse_set<Entity> *handler;
+        std::tuple<pool_type<Get> *...> pools;
+    };
+
     basic_group(sparse_set<Entity> &ref, pool_type<Get> &... gpool) ENTT_NOEXCEPT
         : handler{&ref},
           pools{&gpool...}
@@ -678,8 +442,8 @@ public:
      *
      * @return An iterable object to use to _visit_ the group.
      */
-    group_range<entity_type, exclude_t<Exclude...>, get_t<Get...>> each() const {
-        return { *handler, pools };
+    [[nodiscard]] auto each() const ENTT_NOEXCEPT {
+        return group_range{*handler, pools};
     }
 
     /**
@@ -827,6 +591,117 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> {
     template<typename Component>
     using component_iterator = decltype(std::declval<pool_type<Component>>().begin());
 
+    class group_range {
+        friend class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...>;
+
+        class range_iterator {
+            friend class group_range;
+
+            using it_type = typename sparse_set<Entity>::iterator;
+            using owned_type = decltype(std::tuple_cat(std::declval<std::conditional_t<ENTT_IS_EMPTY(Owned), std::tuple<>, std::tuple<component_iterator<Owned>>>>()...));
+            using get_type = decltype(std::tuple_cat(std::declval<std::conditional_t<ENTT_IS_EMPTY(Get), std::tuple<>, std::tuple<pool_type<Get> *>>>()...));
+
+            range_iterator(it_type from, owned_type oref, get_type gref) ENTT_NOEXCEPT
+                : it{from},
+                  owned{oref},
+                  get{gref}
+            {}
+
+        public:
+            using difference_type = std::ptrdiff_t;
+            using value_type = decltype(std::tuple_cat(
+                std::declval<std::tuple<Entity>>(),
+                std::declval<std::conditional_t<ENTT_IS_EMPTY(Owned), std::tuple<>, std::tuple<Owned &>>>()...,
+                std::declval<std::conditional_t<ENTT_IS_EMPTY(Get), std::tuple<>, std::tuple<Get &>>>()...
+            ));
+            using pointer = void;
+            using reference = value_type;
+            using iterator_category = std::input_iterator_tag;
+
+            range_iterator() ENTT_NOEXCEPT = default;
+
+            range_iterator & operator++() ENTT_NOEXCEPT {
+                return ++it, std::apply([](auto &&... curr) { (++curr, ...); }, owned), *this;
+            }
+
+            range_iterator operator++(int) ENTT_NOEXCEPT {
+                range_iterator orig = *this;
+                return ++(*this), orig;
+            }
+
+            [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
+                return std::tuple_cat(
+                    std::make_tuple(*it),
+                    std::apply([](auto &&... curr) { return std::forward_as_tuple(*curr...); }, owned),
+                    std::apply([entt = *it](auto &&... curr) { return std::forward_as_tuple(curr->get(entt)...); }, get)
+                );
+            }
+
+            [[nodiscard]] bool operator==(const range_iterator &other) const ENTT_NOEXCEPT {
+                return other.it == it;
+            }
+
+            [[nodiscard]] bool operator!=(const range_iterator &other) const ENTT_NOEXCEPT {
+                return !(*this == other);
+            }
+
+        private:
+            it_type it;
+            owned_type owned;
+            get_type get;
+        };
+
+        group_range(std::tuple<pool_type<Owned> *..., pool_type<Get> *...> cpools, const std::size_t &extent)
+            : pools{cpools},
+              length{&extent}
+        {}
+
+    public:
+        [[nodiscard]] auto begin() const ENTT_NOEXCEPT {
+            return range_iterator{
+                std::get<0>(pools)->sparse_set<Entity>::end() - *length,
+                std::tuple_cat([this](auto *cpool) {
+                    if constexpr(ENTT_IS_EMPTY(typename std::decay_t<decltype(*cpool)>::object_type)) {
+                        return std::make_tuple();
+                    } else {
+                        return std::make_tuple(cpool->end() - *length);
+                    }
+                }(std::get<pool_type<Owned> *>(pools))...),
+                std::tuple_cat([](auto *cpool) {
+                    if constexpr(ENTT_IS_EMPTY(typename std::decay_t<decltype(*cpool)>::object_type)) {
+                        return std::make_tuple();
+                    } else {
+                        return std::make_tuple(cpool);
+                    }
+                }(std::get<pool_type<Get> *>(pools))...)
+            };
+        }
+
+        [[nodiscard]] auto end() const ENTT_NOEXCEPT {
+            return range_iterator{
+                std::get<0>(pools)->sparse_set<Entity>::end(),
+                std::tuple_cat([](auto *cpool) {
+                    if constexpr(ENTT_IS_EMPTY(typename std::decay_t<decltype(*cpool)>::object_type)) {
+                        return std::make_tuple();
+                    } else {
+                        return std::make_tuple(cpool->end());
+                    }
+                }(std::get<pool_type<Owned> *>(pools))...),
+                std::tuple_cat([](auto *cpool) {
+                    if constexpr(ENTT_IS_EMPTY(typename std::decay_t<decltype(*cpool)>::object_type)) {
+                        return std::make_tuple();
+                    } else {
+                        return std::make_tuple(cpool);
+                    }
+                }(std::get<pool_type<Get> *>(pools))...)
+            };
+        }
+
+    private:
+        const std::tuple<pool_type<Owned> *..., pool_type<Get> *...> pools;
+        const std::size_t *length;
+    };
+
     basic_group(const std::size_t &extent, pool_type<Owned> &... opool, pool_type<Get> &... gpool) ENTT_NOEXCEPT
         : pools{&opool..., &gpool...},
           length{&extent}
@@ -1108,8 +983,8 @@ public:
      *
      * @return An iterable object to use to _visit_ the group.
      */
-    group_range<entity_type, exclude_t<Exclude...>, get_t<Get...>, Owned...> each() const {
-        return { pools, *length };
+    [[nodiscard]] auto each() const ENTT_NOEXCEPT {
+        return group_range{pools, *length};
     }
 
     /**