From 337bc6d97a1972cc2b6cc447a8e79cdb2f275c98 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Thu, 26 Nov 2020 10:23:35 +0100 Subject: [PATCH] view_pack: support for multiple views of the same type --- src/entt/entity/view_pack.hpp | 117 ++++++++++++++++----------------- test/entt/entity/view_pack.cpp | 16 +++++ 2 files changed, 73 insertions(+), 60 deletions(-) diff --git a/src/entt/entity/view_pack.hpp b/src/entt/entity/view_pack.hpp index 9771fdab7..d1b880cec 100644 --- a/src/entt/entity/view_pack.hpp +++ b/src/entt/entity/view_pack.hpp @@ -24,19 +24,19 @@ namespace entt { * intended primary use is for custom storage and views, but it can also be very * convenient in everyday use. * - * @tparam View Type of the leading view of the pack. - * @tparam Other Types of all other views of the pack. + * @tparam Head Type of the leading view of the pack. + * @tparam Tail Types of all other views of the pack. */ -template +template class view_pack { template class view_pack_iterator final { - friend class view_pack; + friend class view_pack; - view_pack_iterator(It from, It to, const std::tuple &ref) ENTT_NOEXCEPT + view_pack_iterator(It from, It to, const std::tuple &other) ENTT_NOEXCEPT : it{from}, last{to}, - pack{std::get(ref)...} + tail{other} { if(it != last && !valid()) { ++(*this); @@ -44,8 +44,7 @@ class view_pack { } [[nodiscard]] bool valid() const { - const auto entity = *it; - return (std::get(pack).contains(entity) && ...); + return std::apply([entity = *it](auto &&... curr) { return (curr.contains(entity) && ...); }, tail); } public: @@ -80,22 +79,22 @@ class view_pack { private: It it; const It last; - const std::tuple pack; + const std::tuple tail; }; class iterable_view_pack final { - friend class view_pack; + friend class view_pack; - using iterable_view = decltype(std::declval().each()); + using iterable_view = decltype(std::declval().each()); template class iterable_view_pack_iterator final { friend class iterable_view_pack; - iterable_view_pack_iterator(It from, It to, const std::tuple &ref) ENTT_NOEXCEPT + iterable_view_pack_iterator(It from, It to, const std::tuple &other) ENTT_NOEXCEPT : it{from}, last{to}, - pack{ref} + tail{other} { if(it != last && !valid()) { ++(*this); @@ -103,13 +102,12 @@ class view_pack { } [[nodiscard]] bool valid() const { - const auto entity = std::get<0>(*it); - return (std::get(pack).contains(entity) && ...); + return std::apply([entity = std::get<0>(*it)](auto &&... curr) { return (curr.contains(entity) && ...); }, tail); } public: using difference_type = typename std::iterator_traits::difference_type; - using value_type = decltype(std::tuple_cat(*std::declval(), std::declval().get({})...)); + using value_type = decltype(std::tuple_cat(*std::declval(), std::declval().get({})...)); using pointer = void; using reference = value_type; using iterator_category = std::input_iterator_tag; @@ -125,8 +123,7 @@ class view_pack { } [[nodiscard]] reference operator*() const { - const auto curr = *it; - return std::tuple_cat(curr, std::get(pack).get(std::get<0>(curr))...); + return std::apply([value = *it](auto &&... curr) { return std::tuple_cat(value, curr.get(std::get<0>(value))...); }, tail); } [[nodiscard]] bool operator==(const iterable_view_pack_iterator &other) const ENTT_NOEXCEPT { @@ -140,12 +137,12 @@ class view_pack { private: It it; const It last; - const std::tuple pack; + const std::tuple tail; }; - iterable_view_pack(const std::tuple &ref) - : iterable{std::get(ref).each()}, - pack{std::get(ref)...} + iterable_view_pack(const Head &first, const std::tuple &last) + : iterable{first.each()}, + tail{last} {} public: @@ -153,43 +150,44 @@ class view_pack { using reverse_iterator = iterable_view_pack_iterator; [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return { iterable.begin(), iterable.end(), pack }; + return { iterable.begin(), iterable.end(), tail }; } [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return { iterable.end(), iterable.end(), pack }; + return { iterable.end(), iterable.end(), tail }; } [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return { iterable.rbegin(), iterable.rend(), pack }; + return { iterable.rbegin(), iterable.rend(), tail }; } [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return { iterable.rend(), iterable.rend(), pack }; + return { iterable.rend(), iterable.rend(), tail }; } private: iterable_view iterable; - std::tuple pack; + std::tuple tail; }; public: /*! @brief Underlying entity identifier. */ - using entity_type = std::common_type_t; + using entity_type = std::common_type_t; /*! @brief Underlying entity identifier. */ - using size_type = std::common_type_t; + using size_type = std::common_type_t; /*! @brief Input iterator type. */ - using iterator = view_pack_iterator; + using iterator = view_pack_iterator; /*! @brief Reversed iterator type. */ - using reverse_iterator = view_pack_iterator; + using reverse_iterator = view_pack_iterator; /** * @brief Constructs a pack from a bunch of views. - * @param view A reference to the leading view for the pack. - * @param other References to the other views to use to construct the pack. + * @param first A reference to the leading view for the pack. + * @param last References to the other views to use to construct the pack. */ - view_pack(const View &view, const Other &... other) - : pack{view, other...} + view_pack(const Head &first, const Tail &... last) + : head{first}, + tail{last...} {} /** @@ -201,7 +199,7 @@ public: * @return An iterator to the first entity of the pack. */ [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return { std::get(pack).begin(), std::get(pack).end(), pack }; + return { head.begin(), head.end(), tail }; } /** @@ -214,7 +212,7 @@ public: * @return An iterator to the entity following the last entity of the pack. */ [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return { std::get(pack).end(), std::get(pack).end(), pack }; + return { head.end(), head.end(), tail }; } /** @@ -226,7 +224,7 @@ public: * @return An iterator to the first entity of the pack. */ [[nodiscard]] reverse_iterator rbegin() const { - return { std::get(pack).rbegin(), std::get(pack).rend(), pack }; + return { head.rbegin(), head.rend(), tail }; } /** @@ -241,7 +239,7 @@ public: * reversed pack. */ [[nodiscard]] reverse_iterator rend() const { - return { std::get(pack).rend(), std::get(pack).rend(), pack }; + return { head.rend(), head.rend(), tail }; } /** @@ -271,7 +269,7 @@ public: * iterator otherwise. */ [[nodiscard]] iterator find(const entity_type entt) const { - iterator it{std::get(pack).find(entt), std::get(pack).end(), pack}; + iterator it{head.find(entt), head.end(), tail}; return (it != end() && *it == entt) ? it : end(); } @@ -281,7 +279,7 @@ public: * @return True if the pack contains the given entity, false otherwise. */ [[nodiscard]] bool contains(const entity_type entt) const { - return std::get(pack).contains(entt) && (std::get(pack).contains(entt) && ...); + return head.contains(entt) && std::apply([entt](auto &&... curr) { return (curr.contains(entt) && ...); }, tail); } /** @@ -302,7 +300,7 @@ public: template [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) const { ENTT_ASSERT(contains(entt)); - auto component = std::tuple_cat(std::get(pack).get(entt), std::get(pack).get(entt)...); + auto component = std::apply([this, entt](auto &&... curr) { return std::tuple_cat(head.get(entt), curr.get(entt)...); }, tail); if constexpr(sizeof...(Comp) == 0) { return component; @@ -337,14 +335,14 @@ public: */ template void each(Func func) const { - for(const auto value: std::get(pack).each()) { - const auto entity = std::get<0>(value); + for(auto &&value: head.each()) { + if(std::apply([&value](auto &&... curr) { return (curr.contains(std::get<0>(value)) && ...); }, tail)) { + auto args = std::apply([&value](auto &&... curr) { return std::tuple_cat(value, curr.get(std::get<0>(value))...); }, tail); - if((std::get(pack).contains(entity) && ...)) { - if constexpr(is_applicable_v(pack).get(entity)...))>) { - std::apply(func, std::tuple_cat(value, std::get(pack).get(entity)...)); + if constexpr(is_applicable_v) { + std::apply(func, args); } else { - std::apply([&func](const auto, auto &&... component) { func(std::forward(component)...); }, std::tuple_cat(value, std::get(pack).get(entity)...)); + std::apply([&func](const auto, auto &&... component) { func(std::forward(component)...); }, args); } } } @@ -364,28 +362,26 @@ public: * @return An iterable object to use to _visit_ the pack. */ [[nodiscard]] iterable_view_pack each() const ENTT_NOEXCEPT { - return pack; + return { head, tail }; } /** - * @brief Returns a copy of the requested view from a pack. - * @tparam Type Type of the view to return. - * @return A copy of the requested view from the pack. + * @brief Returns a copy of the views stored by the pack. + * @return A copy of the views stored by the pack. */ - template - operator Type() const ENTT_NOEXCEPT { - return std::get(pack); + std::tuple pack() const ENTT_NOEXCEPT { + return std::apply([this](auto &&... curr) { return std::make_tuple(head, curr...); }, tail); } /** * @brief Appends a view to a pack. * @tparam Args View template arguments. - * @param view A reference to a view to append to the pack. + * @param other A reference to a view to append to the pack. * @return The extended pack. */ template - [[nodiscard]] auto operator|(const basic_view &view) const { - return std::make_from_tuple>>(std::tuple_cat(pack, std::make_tuple(view))); + [[nodiscard]] auto operator|(const basic_view &other) const { + return std::make_from_tuple>>(std::tuple_cat(std::make_tuple(head), tail, std::make_tuple(other))); } /** @@ -396,11 +392,12 @@ public: */ template [[nodiscard]] auto operator|(const view_pack &other) const { - return std::make_from_tuple>(std::tuple_cat(pack, std::make_tuple(static_cast(other)...))); + return std::make_from_tuple>(std::tuple_cat(std::make_tuple(head), tail, other.pack())); } private: - std::tuple pack; + Head head; + std::tuple tail; }; diff --git a/test/entt/entity/view_pack.cpp b/test/entt/entity/view_pack.cpp index b5db15c1b..7ce7094c6 100644 --- a/test/entt/entity/view_pack.cpp +++ b/test/entt/entity/view_pack.cpp @@ -402,3 +402,19 @@ TEST(ViewPack, LongestPool) { } } } + +TEST(ViewPack, RepeatedType) { + entt::registry registry; + const auto entity = registry.create(); + + registry.emplace(entity, 3); + + const auto view = registry.view(); + const auto pack = view | view; + + for(auto [entt, i1, i2]: pack.each()) { + ASSERT_EQ(entt, entity); + ASSERT_EQ(i1, 3); + ASSERT_EQ(i1, i2); + } +}