Преглед изворни кода

view: added reverse iterators, rbegin and rend to iterable views

Michele Caini пре 5 година
родитељ
комит
7662da22fc
4 измењених фајлова са 107 додато и 104 уклоњено
  1. 2 0
      TODO
  2. 5 5
      src/entt/entity/group.hpp
  3. 80 76
      src/entt/entity/view.hpp
  4. 20 23
      test/entt/entity/view.cpp

+ 2 - 0
TODO

@@ -9,6 +9,8 @@
 * update documentation for meta, it contains less than half of the actual feature
 * update documentation for meta, it contains less than half of the actual feature
 
 
 WIP:
 WIP:
+* split basic_view and view_t like sfinae-friendly class
+* add view-like functionalities to the view_pack
 * HP: write documentation for custom storages and views!!
 * HP: write documentation for custom storages and views!!
 * view pack: plain function as an alias for operator|, reverse iterators, rbegin and rend
 * view pack: plain function as an alias for operator|, reverse iterators, rbegin and rend
 * use extended get to remove is_eto_eligible checks from views and groups
 * use extended get to remove is_eto_eligible checks from views and groups

+ 5 - 5
src/entt/entity/group.hpp

@@ -120,8 +120,8 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>> final {
             }
             }
 
 
         private:
         private:
-            it_type it{};
-            ref_type pools{};
+            it_type it;
+            ref_type pools;
         };
         };
 
 
         iterable_group(const basic_sparse_set<Entity> &ref, std::tuple<pool_type<Get> *...> gpools)
         iterable_group(const basic_sparse_set<Entity> &ref, std::tuple<pool_type<Get> *...> gpools)
@@ -674,9 +674,9 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> final
             }
             }
 
 
         private:
         private:
-            it_type it{};
-            owned_type owned{};
-            get_type get{};
+            it_type it;
+            owned_type owned;
+            get_type get;
         };
         };
 
 
         iterable_group(std::tuple<pool_type<Owned> *..., pool_type<Get> *...> cpools, const std::size_t &extent)
         iterable_group(std::tuple<pool_type<Owned> *..., pool_type<Get> *...> cpools, const std::size_t &extent)

+ 80 - 76
src/entt/entity/view.hpp

@@ -71,18 +71,14 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> final {
     template<typename Comp>
     template<typename Comp>
     using pool_type = pool_t<Entity, Comp>;
     using pool_type = pool_t<Entity, Comp>;
 
 
-    template<typename Comp>
-    using component_iterator = decltype(std::declval<pool_type<Comp>>().begin());
-
     using return_type = type_list_cat_t<std::conditional_t<is_eto_eligible_v<Component>, type_list<>, type_list<Component>>...>;
     using return_type = type_list_cat_t<std::conditional_t<is_eto_eligible_v<Component>, type_list<>, type_list<Component>>...>;
     using unchecked_type = std::array<const basic_sparse_set<Entity> *, (sizeof...(Component) - 1)>;
     using unchecked_type = std::array<const basic_sparse_set<Entity> *, (sizeof...(Component) - 1)>;
-    using filter_type = std::array<const basic_sparse_set<Entity> *, sizeof...(Exclude)>;
 
 
     template<typename It>
     template<typename It>
     class view_iterator final {
     class view_iterator final {
         friend class basic_view<Entity, exclude_t<Exclude...>, Component...>;
         friend class basic_view<Entity, exclude_t<Exclude...>, Component...>;
 
 
-        view_iterator(It from, It to, It curr, unchecked_type other, filter_type ignore) ENTT_NOEXCEPT
+        view_iterator(It from, It to, It curr, unchecked_type other, const std::tuple<const pool_type<Exclude> *...> &ignore) ENTT_NOEXCEPT
             : first{from},
             : first{from},
               last{to},
               last{to},
               it{curr},
               it{curr},
@@ -95,8 +91,10 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> final {
         }
         }
 
 
         [[nodiscard]] bool valid() const {
         [[nodiscard]] bool valid() const {
-            return std::all_of(unchecked.cbegin(), unchecked.cend(), [entt = *it](const basic_sparse_set<Entity> *curr) { return curr->contains(entt); })
-                    && (sizeof...(Exclude) == 0 || std::none_of(filter.cbegin(), filter.cend(), [entt = *it](const basic_sparse_set<Entity> *cpool) { return cpool->contains(entt); }));
+            const auto entt = *it;
+
+            return std::all_of(unchecked.cbegin(), unchecked.cend(), [entt](const basic_sparse_set<Entity> *curr) { return curr->contains(entt); })
+                && !(std::get<const pool_type<Exclude> *>(filter)->contains(entt) || ...);
         }
         }
 
 
     public:
     public:
@@ -149,30 +147,24 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> final {
         It last;
         It last;
         It it;
         It it;
         unchecked_type unchecked;
         unchecked_type unchecked;
-        filter_type filter;
+        std::tuple<const pool_type<Exclude> *...> filter;
     };
     };
 
 
     class iterable_view {
     class iterable_view {
         friend class basic_view<Entity, exclude_t<Exclude...>, Component...>;
         friend class basic_view<Entity, exclude_t<Exclude...>, Component...>;
 
 
-        using underlying_iterator = view_iterator<typename basic_sparse_set<Entity>::iterator>;
-
+        template<typename It>
         class iterable_view_iterator {
         class iterable_view_iterator {
             friend class iterable_view;
             friend class iterable_view;
 
 
-            using ref_type = decltype(std::tuple_cat(std::declval<std::conditional_t<is_eto_eligible_v<Component>, std::tuple<>, std::tuple<pool_type<Component> *>>>()...));
-
-            iterable_view_iterator(underlying_iterator from, ref_type ref) ENTT_NOEXCEPT
+            iterable_view_iterator(It from, const basic_view &parent) ENTT_NOEXCEPT
                 : it{from},
                 : it{from},
-                  pools{ref}
+                  view{parent}
             {}
             {}
 
 
         public:
         public:
             using difference_type = std::ptrdiff_t;
             using difference_type = std::ptrdiff_t;
-            using value_type = decltype(std::tuple_cat(
-                std::declval<std::tuple<Entity>>(),
-                std::declval<std::conditional_t<is_eto_eligible_v<Component>, std::tuple<>, std::tuple<Component &>>>()...
-            ));
+            using value_type = decltype(std::tuple_cat(std::tuple<typename std::iterator_traits<It>::value_type>{}, std::declval<basic_view>().get({})));
             using pointer = void;
             using pointer = void;
             using reference = value_type;
             using reference = value_type;
             using iterator_category = std::input_iterator_tag;
             using iterator_category = std::input_iterator_tag;
@@ -187,7 +179,7 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> final {
             }
             }
 
 
             [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
             [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
-                return std::apply([entt = *it](auto *... cpool) { return reference{entt, cpool->get(entt)...}; }, pools);
+                return std::tuple_cat(std::make_tuple(*it), view.get(*it));
             }
             }
 
 
             [[nodiscard]] bool operator==(const iterable_view_iterator &other) const ENTT_NOEXCEPT {
             [[nodiscard]] bool operator==(const iterable_view_iterator &other) const ENTT_NOEXCEPT {
@@ -199,49 +191,42 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> final {
             }
             }
 
 
         private:
         private:
-            underlying_iterator it{};
-            const ref_type pools{};
+            It it;
+            const basic_view view;
         };
         };
 
 
-        iterable_view(underlying_iterator from, underlying_iterator to, std::tuple<pool_type<Component> *...> ref)
-            : first{from},
-              last{to},
-              pools{ref}
+        iterable_view(const basic_view &parent)
+            : view{parent}
         {}
         {}
 
 
     public:
     public:
-        using iterator = iterable_view_iterator;
+        using iterator = iterable_view_iterator<typename basic_view::iterator>;
+        using reverse_iterator = iterable_view_iterator<typename basic_view::reverse_iterator>;
 
 
         [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
         [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
-            return iterable_view_iterator{first, std::tuple_cat([](auto *cpool) {
-                if constexpr(is_eto_eligible_v<typename std::remove_reference_t<decltype(*cpool)>::value_type>) {
-                    return std::tuple{};
-                } else {
-                    return std::make_tuple(cpool);
-                }
-            }(std::get<pool_type<Component> *>(pools))...)};
+            return iterator{view.begin(), view};
         }
         }
 
 
         [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
         [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
-            return iterable_view_iterator{last, std::tuple_cat([](auto *cpool) {
-                if constexpr(is_eto_eligible_v<typename std::remove_reference_t<decltype(*cpool)>::value_type>) {
-                    return std::tuple{};
-                } else {
-                    return std::make_tuple(cpool);
-                }
-            }(std::get<pool_type<Component> *>(pools))...)};
+            return iterator{view.end(), view};
+        }
+
+        [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
+            return reverse_iterator{view.rbegin(), view};
+        }
+
+        [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
+            return reverse_iterator{view.rend(), view};
         }
         }
 
 
     private:
     private:
-        underlying_iterator first;
-        underlying_iterator last;
-        const std::tuple<pool_type<Component> *...> pools;
+        const basic_view view;
     };
     };
 
 
-    basic_view(pool_type<Component> &... component, unpack_as_t<const basic_sparse_set<Entity>, Exclude> &... epool) ENTT_NOEXCEPT
+    basic_view(pool_type<Component> &... component, const pool_type<Exclude> &... epool) ENTT_NOEXCEPT
         : pools{&component...},
         : pools{&component...},
-          view{candidate()},
-          filter{&epool...}
+          filter{&epool...},
+          view{candidate()}
     {}
     {}
 
 
     [[nodiscard]] const basic_sparse_set<Entity> * candidate() const ENTT_NOEXCEPT {
     [[nodiscard]] const basic_sparse_set<Entity> * candidate() const ENTT_NOEXCEPT {
@@ -257,9 +242,9 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> final {
         return other;
         return other;
     }
     }
 
 
-    template<typename Comp, typename Other>
-    [[nodiscard]] decltype(auto) get([[maybe_unused]] component_iterator<Comp> &it, [[maybe_unused]] pool_type<Other> *cpool, [[maybe_unused]] const Entity entt) const {
-        if constexpr(std::is_same_v<Comp, Other>) {
+    template<typename It, typename Pool>
+    [[nodiscard]] decltype(auto) get([[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 *it;
         } else {
         } else {
             return cpool->get(entt);
             return cpool->get(entt);
@@ -273,12 +258,12 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> final {
 
 
             for(const auto entt: static_cast<const basic_sparse_set<entity_type> &>(*std::get<pool_type<Comp> *>(pools))) {
             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)) && ...)
                 if(((std::is_same_v<Comp, Component> || std::get<pool_type<Component> *>(pools)->contains(entt)) && ...)
-                        && (sizeof...(Exclude) == 0 || std::none_of(filter.cbegin(), filter.cend(), [entt](const basic_sparse_set<Entity> *cpool) { return cpool->contains(entt); })))
+                    && !(std::get<const pool_type<Exclude> *>(filter)->contains(entt) || ...))
                 {
                 {
                     if constexpr(std::is_invocable_v<Func, entity_type, decltype(get<Type>({}))...>) {
                     if constexpr(std::is_invocable_v<Func, entity_type, decltype(get<Type>({}))...>) {
-                        func(entt, get<Comp, Type>(it, std::get<pool_type<Type> *>(pools), entt)...);
+                        func(entt, get(it, std::get<pool_type<Type> *>(pools), entt)...);
                     } else {
                     } else {
-                        func(get<Comp, Type>(it, std::get<pool_type<Type> *>(pools), entt)...);
+                        func(get(it, std::get<pool_type<Type> *>(pools), entt)...);
                     }
                     }
                 }
                 }
 
 
@@ -287,7 +272,7 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> final {
         } else {
         } else {
             for(const auto entt: static_cast<const basic_sparse_set<entity_type> &>(*std::get<pool_type<Comp> *>(pools))) {
             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)) && ...)
                 if(((std::is_same_v<Comp, Component> || std::get<pool_type<Component> *>(pools)->contains(entt)) && ...)
-                        && (sizeof...(Exclude) == 0 || std::none_of(filter.cbegin(), filter.cend(), [entt](const basic_sparse_set<Entity> *cpool) { return cpool->contains(entt); })))
+                    && !(std::get<const pool_type<Exclude> *>(filter)->contains(entt) || ...))
                 {
                 {
                     if constexpr(std::is_invocable_v<Func, entity_type, decltype(get<Type>({}))...>) {
                     if constexpr(std::is_invocable_v<Func, entity_type, decltype(get<Type>({}))...>) {
                         func(entt, std::get<pool_type<Type> *>(pools)->get(entt)...);
                         func(entt, std::get<pool_type<Type> *>(pools)->get(entt)...);
@@ -306,7 +291,7 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> final {
 
 
         while(first != last) {
         while(first != last) {
             if((std::get<pool_type<Component> *>(pools)->contains(*first) && ...)
             if((std::get<pool_type<Component> *>(pools)->contains(*first) && ...)
-                    && (sizeof...(Exclude) == 0 || std::none_of(filter.cbegin(), filter.cend(), [entt = *first](const basic_sparse_set<Entity> *cpool) { return cpool->contains(entt); })))
+                && !(std::get<const pool_type<Exclude> *>(filter)->contains(*first) || ...))
             {
             {
                 const auto base = *(first++);
                 const auto base = *(first++);
                 const auto chunk = (std::min)({ (std::get<pool_type<Component> *>(pools)->size() - std::get<pool_type<Component> *>(pools)->index(base))... });
                 const auto chunk = (std::min)({ (std::get<pool_type<Component> *>(pools)->size() - std::get<pool_type<Component> *>(pools)->index(base))... });
@@ -315,7 +300,7 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> final {
                 for(++length;
                 for(++length;
                     length < chunk
                     length < chunk
                         && ((*(std::get<pool_type<Component> *>(pools)->data() + std::get<pool_type<Component> *>(pools)->index(base) + length) == *first) && ...)
                         && ((*(std::get<pool_type<Component> *>(pools)->data() + std::get<pool_type<Component> *>(pools)->index(base) + length) == *first) && ...)
-                        && (sizeof...(Exclude) == 0 || std::none_of(filter.cbegin(), filter.cend(), [entt = *first](const basic_sparse_set<Entity> *cpool) { return cpool->contains(entt); }));
+                        && !(std::get<const pool_type<Exclude> *>(filter)->contains(*first) || ...);
                     ++length, ++first);
                     ++length, ++first);
 
 
                 func(view->data() + view->index(base), (std::get<pool_type<Type> *>(pools)->raw() + std::get<pool_type<Type> *>(pools)->index(base))..., length);
                 func(view->data() + view->index(base), (std::get<pool_type<Type> *>(pools)->raw() + std::get<pool_type<Type> *>(pools)->index(base))..., length);
@@ -432,8 +417,7 @@ public:
      * @return True if the view contains the given entity, false otherwise.
      * @return True if the view contains the given entity, false otherwise.
      */
      */
     [[nodiscard]] bool contains(const entity_type entt) const {
     [[nodiscard]] bool contains(const entity_type entt) const {
-        return (std::get<pool_type<Component> *>(pools)->contains(entt) && ...)
-                && (sizeof...(Exclude) == 0 || std::none_of(filter.begin(), filter.end(), [entt](const auto *cpool) { return cpool->contains(entt); }));
+        return (std::get<pool_type<Component> *>(pools)->contains(entt) && ...) && !(std::get<const pool_type<Exclude> *>(filter)->contains(entt) || ...);
     }
     }
 
 
     /**
     /**
@@ -535,7 +519,7 @@ public:
      * @return An iterable object to use to _visit_ the view.
      * @return An iterable object to use to _visit_ the view.
      */
      */
     [[nodiscard]] iterable_view each() const ENTT_NOEXCEPT {
     [[nodiscard]] iterable_view each() const ENTT_NOEXCEPT {
-        return iterable_view{begin(), end(), pools};
+        return iterable_view{*this};
     }
     }
 
 
     /**
     /**
@@ -555,7 +539,7 @@ public:
     template<typename Comp>
     template<typename Comp>
     [[nodiscard]] iterable_view each() const ENTT_NOEXCEPT {
     [[nodiscard]] iterable_view each() const ENTT_NOEXCEPT {
         view = std::get<pool_type<Comp> *>(pools);
         view = std::get<pool_type<Comp> *>(pools);
-        return each();
+        return iterable_view{*this};
     }
     }
 
 
     /**
     /**
@@ -597,8 +581,8 @@ public:
 
 
 private:
 private:
     const std::tuple<pool_type<Component> *...> pools;
     const std::tuple<pool_type<Component> *...> pools;
+    const std::tuple<const pool_type<Exclude> *...> filter;
     mutable const basic_sparse_set<entity_type>* view;
     mutable const basic_sparse_set<entity_type>* view;
-    filter_type filter;
 };
 };
 
 
 
 
@@ -643,22 +627,17 @@ class basic_view<Entity, exclude_t<>, Component> final {
     class iterable_view {
     class iterable_view {
         friend class basic_view<Entity, exclude_t<>, Component>;
         friend class basic_view<Entity, exclude_t<>, Component>;
 
 
+        template<typename It, typename... Other>
         class iterable_view_iterator {
         class iterable_view_iterator {
             friend class iterable_view;
             friend class iterable_view;
 
 
-            using it_type = std::conditional_t<
-                is_eto_eligible_v<Component>,
-                std::tuple<typename basic_sparse_set<Entity>::iterator>,
-                std::tuple<typename basic_sparse_set<Entity>::iterator, decltype(std::declval<pool_type>().begin())>
-            >;
-
-            iterable_view_iterator(it_type from) ENTT_NOEXCEPT
-                : it{from}
+            iterable_view_iterator(It from, Other... data) ENTT_NOEXCEPT
+                : it{from, data...}
             {}
             {}
 
 
         public:
         public:
             using difference_type = std::ptrdiff_t;
             using difference_type = std::ptrdiff_t;
-            using value_type = std::conditional_t<is_eto_eligible_v<Component>, std::tuple<Entity>, std::tuple<Entity, Component &>>;
+            using value_type = std::tuple<typename std::iterator_traits<It>::value_type, decltype(*std::declval<Other>())...>;
             using pointer = void;
             using pointer = void;
             using reference = value_type;
             using reference = value_type;
             using iterator_category = std::input_iterator_tag;
             using iterator_category = std::input_iterator_tag;
@@ -677,7 +656,7 @@ class basic_view<Entity, exclude_t<>, Component> final {
             }
             }
 
 
             [[nodiscard]] bool operator==(const iterable_view_iterator &other) const ENTT_NOEXCEPT {
             [[nodiscard]] bool operator==(const iterable_view_iterator &other) const ENTT_NOEXCEPT {
-                return std::get<0>(other.it) == std::get<0>(it);
+                return std::get<It>(other.it) == std::get<It>(it);
             }
             }
 
 
             [[nodiscard]] bool operator!=(const iterable_view_iterator &other) const ENTT_NOEXCEPT {
             [[nodiscard]] bool operator!=(const iterable_view_iterator &other) const ENTT_NOEXCEPT {
@@ -685,7 +664,7 @@ class basic_view<Entity, exclude_t<>, Component> final {
             }
             }
 
 
         private:
         private:
-            it_type it{};
+            std::tuple<It, Other...> it;
         };
         };
 
 
         iterable_view(pool_type &ref)
         iterable_view(pool_type &ref)
@@ -693,21 +672,46 @@ class basic_view<Entity, exclude_t<>, Component> final {
         {}
         {}
 
 
     public:
     public:
-        using iterator = iterable_view_iterator;
+        using iterator = std::conditional_t<
+            is_eto_eligible_v<Component>,
+            iterable_view_iterator<typename basic_view::iterator>,
+            iterable_view_iterator<typename basic_view::iterator, decltype(std::declval<pool_type>().begin())>
+        >;
+        using reverse_iterator = std::conditional_t<
+            is_eto_eligible_v<Component>,
+            iterable_view_iterator<typename basic_view::reverse_iterator>,
+            iterable_view_iterator<typename basic_view::reverse_iterator, decltype(std::declval<pool_type>().rbegin())>
+        >;
 
 
         [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
         [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
             if constexpr(is_eto_eligible_v<Component>) {
             if constexpr(is_eto_eligible_v<Component>) {
-                return iterable_view_iterator{std::make_tuple(pool->basic_sparse_set<entity_type>::begin())};
+                return iterator{pool->basic_sparse_set<entity_type>::begin()};
             } else {
             } else {
-                return iterable_view_iterator{std::make_tuple(pool->basic_sparse_set<entity_type>::begin(), pool->begin())};
+                return iterator{pool->basic_sparse_set<entity_type>::begin(), pool->begin()};
             }
             }
         }
         }
 
 
         [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
         [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
             if constexpr(is_eto_eligible_v<Component>) {
             if constexpr(is_eto_eligible_v<Component>) {
-                return iterable_view_iterator{std::make_tuple(pool->basic_sparse_set<entity_type>::end())};
+                return iterator{pool->basic_sparse_set<entity_type>::end()};
+            } else {
+                return iterator{pool->basic_sparse_set<entity_type>::end(), pool->end()};
+            }
+        }
+
+        [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
+            if constexpr(is_eto_eligible_v<Component>) {
+                return reverse_iterator{pool->basic_sparse_set<entity_type>::rbegin()};
+            } else {
+                return reverse_iterator{pool->basic_sparse_set<entity_type>::rbegin(), pool->rbegin()};
+            }
+        }
+
+        [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
+            if constexpr(is_eto_eligible_v<Component>) {
+                return reverse_iterator{pool->basic_sparse_set<entity_type>::rend()};
             } else {
             } else {
-                return iterable_view_iterator{std::make_tuple(pool->basic_sparse_set<entity_type>::end(), pool->end())};
+                return reverse_iterator{pool->basic_sparse_set<entity_type>::rend(), pool->rend()};
             }
             }
         }
         }
 
 

+ 20 - 23
test/entt/entity/view.cpp

@@ -111,31 +111,30 @@ TEST(SingleComponentView, Empty) {
 TEST(SingleComponentView, Each) {
 TEST(SingleComponentView, Each) {
     entt::registry registry;
     entt::registry registry;
 
 
-    registry.emplace<int>(registry.create());
-    registry.emplace<int>(registry.create());
+    registry.emplace<int>(registry.create(), 0);
+    registry.emplace<int>(registry.create(), 1);
 
 
     auto view = registry.view<int>();
     auto view = registry.view<int>();
     auto cview = std::as_const(registry).view<const int>();
     auto cview = std::as_const(registry).view<const int>();
     std::size_t cnt = 0;
     std::size_t cnt = 0;
 
 
+    for(auto first = cview.each().rbegin(), last = cview.each().rend(); first != last; ++first) {
+        static_assert(std::is_same_v<decltype(*first), std::tuple<entt::entity, const int &>>);
+        ASSERT_EQ(std::get<1>(*first), cnt++);
+    }
+
     view.each([&cnt](auto, int &) { ++cnt; });
     view.each([&cnt](auto, int &) { ++cnt; });
     view.each([&cnt](int &) { ++cnt; });
     view.each([&cnt](int &) { ++cnt; });
 
 
-    for(auto &&[entt, iv]: view.each()) {
-        static_assert(std::is_same_v<decltype(entt), entt::entity>);
-        static_assert(std::is_same_v<decltype(iv), int &>);
-        ++cnt;
-    }
-
     ASSERT_EQ(cnt, std::size_t{6});
     ASSERT_EQ(cnt, std::size_t{6});
 
 
-    cview.each([&cnt](auto, const int &) { --cnt; });
     cview.each([&cnt](const int &) { --cnt; });
     cview.each([&cnt](const int &) { --cnt; });
+    cview.each([&cnt](auto, const int &) { --cnt; });
 
 
-    for(auto &&[entt, iv]: cview.each()) {
+    for(auto &&[entt, iv]: view.each()) {
         static_assert(std::is_same_v<decltype(entt), entt::entity>);
         static_assert(std::is_same_v<decltype(entt), entt::entity>);
-        static_assert(std::is_same_v<decltype(iv), const int &>);
-        --cnt;
+        static_assert(std::is_same_v<decltype(iv), int &>);
+        ASSERT_EQ(iv, --cnt);
     }
     }
 
 
     ASSERT_EQ(cnt, std::size_t{0});
     ASSERT_EQ(cnt, std::size_t{0});
@@ -446,37 +445,35 @@ TEST(MultiComponentView, Each) {
     entt::registry registry;
     entt::registry registry;
 
 
     const auto e0 = registry.create();
     const auto e0 = registry.create();
-    registry.emplace<int>(e0);
+    registry.emplace<int>(e0, 0);
     registry.emplace<char>(e0);
     registry.emplace<char>(e0);
 
 
     const auto e1 = registry.create();
     const auto e1 = registry.create();
-    registry.emplace<int>(e1);
+    registry.emplace<int>(e1, 1);
     registry.emplace<char>(e1);
     registry.emplace<char>(e1);
 
 
     auto view = registry.view<int, char>();
     auto view = registry.view<int, char>();
     auto cview = std::as_const(registry).view<const int, const char>();
     auto cview = std::as_const(registry).view<const int, const char>();
     std::size_t cnt = 0;
     std::size_t cnt = 0;
 
 
+    for(auto first = cview.each().rbegin(), last = cview.each().rend(); first != last; ++first) {
+        static_assert(std::is_same_v<decltype(*first), std::tuple<entt::entity, const int &, const char &>>);
+        ASSERT_EQ(std::get<1>(*first), cnt++);
+    }
+
     view.each([&cnt](auto, int &, char &) { ++cnt; });
     view.each([&cnt](auto, int &, char &) { ++cnt; });
     view.each([&cnt](int &, char &) { ++cnt; });
     view.each([&cnt](int &, char &) { ++cnt; });
 
 
-    for(auto &&[entt, iv, cv]: view.each()) {
-        static_assert(std::is_same_v<decltype(entt), entt::entity>);
-        static_assert(std::is_same_v<decltype(iv), int &>);
-        static_assert(std::is_same_v<decltype(cv), char &>);
-        ++cnt;
-    }
-
     ASSERT_EQ(cnt, std::size_t{6});
     ASSERT_EQ(cnt, std::size_t{6});
 
 
-    cview.each([&cnt](auto, const int &, const char &) { --cnt; });
     cview.each([&cnt](const int &, const char &) { --cnt; });
     cview.each([&cnt](const int &, const char &) { --cnt; });
+    cview.each([&cnt](auto, const int &, const char &) { --cnt; });
 
 
     for(auto &&[entt, iv, cv]: cview.each()) {
     for(auto &&[entt, iv, cv]: cview.each()) {
         static_assert(std::is_same_v<decltype(entt), entt::entity>);
         static_assert(std::is_same_v<decltype(entt), entt::entity>);
         static_assert(std::is_same_v<decltype(iv), const int &>);
         static_assert(std::is_same_v<decltype(iv), const int &>);
         static_assert(std::is_same_v<decltype(cv), const char &>);
         static_assert(std::is_same_v<decltype(cv), const char &>);
-        --cnt;
+        ASSERT_EQ(iv, --cnt);
     }
     }
 
 
     ASSERT_EQ(cnt, std::size_t{0});
     ASSERT_EQ(cnt, std::size_t{0});