Przeglądaj źródła

view: improved view ranges

Michele Caini 5 lat temu
rodzic
commit
1b93a449b2
1 zmienionych plików z 166 dodań i 287 usunięć
  1. 166 287
      src/entt/entity/view.hpp

+ 166 - 287
src/entt/entity/view.hpp

@@ -20,287 +20,6 @@
 namespace entt {
 
 
-/**
- * @brief View 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 view_range;
-
-
-/**
- * @brief Multi component view range.
- *
- * Iterable object to use to _visit_ a view.
- *
- * @sa view
- *
- * @tparam Entity A valid entity type (see entt_traits for more details).
- * @tparam Exclude Types of components used to filter the view.
- * @tparam Component Types of components iterated by the view.
- */
-template<typename Entity, typename... Exclude, typename... Component>
-class view_range<Entity, exclude_t<Exclude...>, Component...> {
-    /*! @brief A view is allowed to create ranges. */
-    friend class basic_view<Entity, exclude_t<Exclude...>, Component...>;
-
-    // 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;
-
-    using entity_iterator = typename sparse_set<Entity>::iterator;
-    using filter_type = std::array<const sparse_set<Entity> *, sizeof...(Exclude)>;
-
-    class range_iterator {
-        friend class view_range<Entity, exclude_t<Exclude...>, Component...>;
-
-        range_iterator(entity_iterator from, entity_iterator to, std::tuple<pool_type<Component> *...> get, filter_type exclude) ENTT_NOEXCEPT
-            : first{from},
-              last{to},
-              pools{get},
-              filter{exclude}
-        {
-            if(first != last && !valid()) {
-                ++(*this);
-            }
-        }
-
-        [[nodiscard]] bool valid() const {
-            return (std::get<pool_type<Component> *>(pools)->contains(*first) && ...)
-                    && std::none_of(filter.cbegin(), filter.cend(), [entt = *first](const sparse_set<Entity> *curr) { return curr->contains(entt); });
-        }
-
-    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(Component), std::tuple<>, std::tuple<Component &>>>()...
-        ));
-        using pointer = void;
-        using reference = value_type;
-        using iterator_category = std::input_iterator_tag;
-
-        range_iterator() ENTT_NOEXCEPT = default;
-
-        range_iterator & operator++() ENTT_NOEXCEPT {
-            while(++first != last && !valid());
-            return *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(*first), [this](auto *cpool) -> decltype(auto) {
-                if constexpr(ENTT_IS_EMPTY(typename std::decay_t<decltype(*cpool)>::object_type)) {
-                    return std::make_tuple();
-                } else {
-                    return std::forward_as_tuple(cpool->get(*first));
-                }
-            }(std::get<pool_type<Component> *>(pools))...);
-        }
-
-        [[nodiscard]] bool operator==(const range_iterator &other) const ENTT_NOEXCEPT {
-            return other.first == first;
-        }
-
-        [[nodiscard]] bool operator!=(const range_iterator &other) const ENTT_NOEXCEPT {
-            return !(*this == other);
-        }
-
-    private:
-        entity_iterator first;
-        const entity_iterator last;
-        std::tuple<pool_type<Component> *...> pools;
-        filter_type filter;
-    };
-
-    view_range(const sparse_set<Entity> &ref, std::tuple<pool_type<Component> *...> component, filter_type epool)
-        : candidate{&ref},
-          pools{component},
-          filter{epool}
-    {}
-
-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{candidate->begin(), candidate->end(), pools, filter};
-    }
-
-    /**
-     * @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{candidate->end(), candidate->end(), pools, filter};
-    }
-
-private:
-    const sparse_set<Entity> *candidate;
-    std::tuple<pool_type<Component> *...> pools;
-    filter_type filter;
-};
-
-
-/**
- * @brief Single component view range specialization.
- *
- * Iterable object to use to _visit_ a view.
- *
- * @sa view
- *
- * @tparam Entity A valid entity type (see entt_traits for more details).
- * @tparam Component Type of component iterated by the view.
- */
-template<typename Entity, typename Component>
-class view_range<Entity, exclude_t<>, Component> {
-    /*! @brief A view is allowed to create ranges. */
-    friend class basic_view<Entity, exclude_t<>, Component>;
-
-    using pool_type = std::conditional_t<std::is_const_v<Component>, const storage<Entity, std::remove_const_t<Component>>, storage<Entity, Component>>;
-
-    class range_iterator {
-        friend class view_range<Entity, exclude_t<>, Component>;
-
-        using it_type = std::conditional_t<
-            ENTT_IS_EMPTY(Component),
-            std::tuple<typename sparse_set<Entity>::iterator>,
-            std::tuple<typename sparse_set<Entity>::iterator, decltype(std::declval<pool_type>().begin())>
-        >;
-
-        range_iterator(it_type from) ENTT_NOEXCEPT
-            : it{from}
-        {}
-
-    public:
-        using difference_type = std::ptrdiff_t;
-        using value_type = std::conditional_t<ENTT_IS_EMPTY(Component), std::tuple<Entity>, std::tuple<Entity, Component &>>;
-        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 std::apply([](auto &&... curr) { (++curr, ...); }, it), *this;
-        }
-
-        range_iterator operator++(int) ENTT_NOEXCEPT {
-            range_iterator orig = *this;
-            return ++(*this), orig;
-        }
-
-        [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
-            return std::apply([](auto &&... curr) { return reference{*curr...}; }, it);
-        }
-
-        [[nodiscard]] bool operator==(const range_iterator &other) const ENTT_NOEXCEPT {
-            return std::get<0>(other.it) == std::get<0>(it);
-        }
-
-        [[nodiscard]] bool operator!=(const range_iterator &other) const ENTT_NOEXCEPT {
-            return !(*this == other);
-        }
-
-    private:
-        it_type it;
-    };
-
-    view_range(pool_type &ref)
-        : pool{&ref}
-    {}
-
-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 {
-        if constexpr(ENTT_IS_EMPTY(Component)) {
-            return iterator{std::make_tuple(pool->sparse_set<entity_type>::begin())};
-        } else {
-            return iterator{std::make_tuple(pool->sparse_set<entity_type>::begin(), pool->begin())};
-        }
-    }
-
-    /**
-     * @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 {
-        if constexpr(ENTT_IS_EMPTY(Component)) {
-            return iterator{std::make_tuple(pool->sparse_set<entity_type>::end())};
-        } else {
-            return iterator{std::make_tuple(pool->sparse_set<entity_type>::end(), pool->end())};
-        }
-    }
-
-private:
-    pool_type *pool;
-};
-
-
 /**
  * @brief View.
  *
@@ -439,6 +158,90 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> {
         underlying_iterator it;
     };
 
+    class view_range {
+        friend class basic_view<Entity, exclude_t<Exclude...>, Component...>;
+
+        class range_iterator {
+            friend class view_range;
+
+            using ref_type = decltype(std::tuple_cat(std::declval<std::conditional_t<ENTT_IS_EMPTY(Component), std::tuple<>, std::tuple<pool_type<Component> *>>>()...));
+
+            range_iterator(view_iterator from, ref_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(Component), std::tuple<>, std::tuple<Component &>>>()...
+            ));
+            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 ++it, 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:
+            view_iterator it;
+            const ref_type pools;
+        };
+
+        view_range(view_iterator from, view_iterator to, std::tuple<pool_type<Component> *...> ref)
+            : first{from},
+              last{to},
+              pools{ref}
+        {}
+
+    public:
+        [[nodiscard]] auto begin() const ENTT_NOEXCEPT {
+            return range_iterator{first, 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<Component> *>(pools))...)};
+        }
+
+        [[nodiscard]] auto end() const ENTT_NOEXCEPT {
+            return range_iterator{last, 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<Component> *>(pools))...)};
+        }
+
+    private:
+        view_iterator first;
+        view_iterator last;
+        const std::tuple<pool_type<Component> *...> pools;
+    };
+
     basic_view(pool_type<Component> &... component, unpack_as_t<const sparse_set<Entity>, Exclude> &... epool) ENTT_NOEXCEPT
         : pools{&component...},
           filter{&epool...}
@@ -756,8 +559,8 @@ public:
      *
      * @return An iterable object to use to _visit_ the view.
      */
-    [[nodiscard]] view_range<entity_type, exclude_t<Exclude...>, Component...> each() const ENTT_NOEXCEPT {
-        return { candidate(), pools, filter };
+    [[nodiscard]] auto each() const ENTT_NOEXCEPT {
+        return view_range{begin(), end(), pools};
     }
 
     /**
@@ -775,8 +578,9 @@ public:
      * @return An iterable object to use to _visit_ the view.
      */
     template<typename Comp>
-    [[nodiscard]] view_range<entity_type, exclude_t<Exclude...>, Component...> each() const ENTT_NOEXCEPT {
-        return { *std::get<pool_type<Comp> *>(pools), pools, filter };
+    [[nodiscard]] auto each() const ENTT_NOEXCEPT {
+        const sparse_set<entity_type> &view = *std::get<pool_type<Comp> *>(pools);
+        return view_range{iterator{view, unchecked(view), filter, view.begin()}, iterator{view, unchecked(view), filter, view.begin()}, pools};
     }
 
 private:
@@ -823,6 +627,81 @@ class basic_view<Entity, exclude_t<>, Component> {
 
     using pool_type = std::conditional_t<std::is_const_v<Component>, const storage<Entity, std::remove_const_t<Component>>, storage<Entity, Component>>;
 
+    class view_range {
+        friend class basic_view<Entity, exclude_t<>, Component>;
+
+        class range_iterator {
+            friend class view_range;
+
+            using it_type = std::conditional_t<
+                ENTT_IS_EMPTY(Component),
+                std::tuple<typename sparse_set<Entity>::iterator>,
+                std::tuple<typename sparse_set<Entity>::iterator, decltype(std::declval<pool_type>().begin())>
+            >;
+
+            range_iterator(it_type from) ENTT_NOEXCEPT
+                : it{from}
+            {}
+
+        public:
+            using difference_type = std::ptrdiff_t;
+            using value_type = std::conditional_t<ENTT_IS_EMPTY(Component), std::tuple<Entity>, std::tuple<Entity, Component &>>;
+            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 std::apply([](auto &&... curr) { (++curr, ...); }, it), *this;
+            }
+
+            range_iterator operator++(int) ENTT_NOEXCEPT {
+                range_iterator orig = *this;
+                return ++(*this), orig;
+            }
+
+            [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
+                return std::apply([](auto &&... curr) { return reference{*curr...}; }, it);
+            }
+
+            [[nodiscard]] bool operator==(const range_iterator &other) const ENTT_NOEXCEPT {
+                return std::get<0>(other.it) == std::get<0>(it);
+            }
+
+            [[nodiscard]] bool operator!=(const range_iterator &other) const ENTT_NOEXCEPT {
+                return !(*this == other);
+            }
+
+        private:
+            it_type it;
+        };
+
+        view_range(pool_type &ref)
+            : pool{&ref}
+        {}
+
+    public:
+        [[nodiscard]] auto begin() const ENTT_NOEXCEPT {
+            if constexpr(ENTT_IS_EMPTY(Component)) {
+                return range_iterator{std::make_tuple(pool->sparse_set<entity_type>::begin())};
+            } else {
+                return range_iterator{std::make_tuple(pool->sparse_set<entity_type>::begin(), pool->begin())};
+            }
+        }
+
+        [[nodiscard]] auto end() const ENTT_NOEXCEPT {
+            if constexpr(ENTT_IS_EMPTY(Component)) {
+                return range_iterator{std::make_tuple(pool->sparse_set<entity_type>::end())};
+            } else {
+                return range_iterator{std::make_tuple(pool->sparse_set<entity_type>::end(), pool->end())};
+            }
+        }
+
+    private:
+        pool_type *pool;
+    };
+
     basic_view(pool_type &ref) ENTT_NOEXCEPT
         : pool{&ref}
     {}
@@ -1055,8 +934,8 @@ public:
      *
      * @return An iterable object to use to _visit_ the view.
      */
-    [[nodiscard]] view_range<entity_type, exclude_t<>, Component> each() const ENTT_NOEXCEPT {
-        return { *pool };
+    [[nodiscard]] auto each() const ENTT_NOEXCEPT {
+        return view_range{*pool};
     }
 
 private: