1
0
Эх сурвалжийг харах

view: drop conceptually broken reverse iterators

Michele Caini 4 жил өмнө
parent
commit
b86ffc2370

+ 1 - 1
docs/md/entity.md

@@ -2240,7 +2240,7 @@ See the relevant documentation for more information.
 
 
 A special mention is needed for the iterators returned by views and groups. Most
 A special mention is needed for the iterators returned by views and groups. Most
 of the times they meet the requirements of random access iterators, in all cases
 of the times they meet the requirements of random access iterators, in all cases
-they meet at least the requirements of bidirectional iterators.<br/>
+they meet at least the requirements of forward iterators.<br/>
 In other terms, they are suitable for use with the parallel algorithms of the
 In other terms, they are suitable for use with the parallel algorithms of the
 standard library. If it's not clear, this is a great thing.
 standard library. If it's not clear, this is a great thing.
 
 

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

@@ -81,10 +81,6 @@ public:
         ignore_as_empty_v<typename Storage::value_type>,
         ignore_as_empty_v<typename Storage::value_type>,
         iterable_storage_iterator<typename basic_common_type::iterator>,
         iterable_storage_iterator<typename basic_common_type::iterator>,
         iterable_storage_iterator<typename basic_common_type::iterator, decltype(std::declval<Storage>().begin())>>;
         iterable_storage_iterator<typename basic_common_type::iterator, decltype(std::declval<Storage>().begin())>>;
-    using reverse_iterator = std::conditional_t<
-        ignore_as_empty_v<typename Storage::value_type>,
-        iterable_storage_iterator<typename basic_common_type::reverse_iterator>,
-        iterable_storage_iterator<typename basic_common_type::reverse_iterator, decltype(std::declval<Storage>().rbegin())>>;
 
 
     iterable_storage(Storage &ref)
     iterable_storage(Storage &ref)
         : pool{&ref} {}
         : pool{&ref} {}
@@ -97,14 +93,6 @@ public:
         return iterator{pool->basic_common_type::end(), pool->end()};
         return iterator{pool->basic_common_type::end(), pool->end()};
     }
     }
 
 
-    [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
-        return reverse_iterator{pool->basic_common_type::rbegin(), pool->rbegin()};
-    }
-
-    [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
-        return reverse_iterator{pool->basic_common_type::rend(), pool->rend()};
-    }
-
 private:
 private:
     Storage *const pool;
     Storage *const pool;
 };
 };
@@ -155,7 +143,6 @@ class iterable_view final {
 
 
 public:
 public:
     using iterator = iterable_view_iterator<typename View::iterator>;
     using iterator = iterable_view_iterator<typename View::iterator>;
-    using reverse_iterator = iterable_view_iterator<typename View::reverse_iterator>;
 
 
     iterable_view(const View &parent)
     iterable_view(const View &parent)
         : view{parent} {}
         : view{parent} {}
@@ -168,14 +155,6 @@ public:
         return {view.end(), &view};
         return {view.end(), &view};
     }
     }
 
 
-    [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
-        return {view.rbegin(), &view};
-    }
-
-    [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
-        return {view.rend(), &view};
-    }
-
 private:
 private:
     const View view;
     const View view;
 };
 };
@@ -194,19 +173,17 @@ public:
     using value_type = typename std::iterator_traits<It>::value_type;
     using value_type = typename std::iterator_traits<It>::value_type;
     using pointer = typename std::iterator_traits<It>::pointer;
     using pointer = typename std::iterator_traits<It>::pointer;
     using reference = typename std::iterator_traits<It>::reference;
     using reference = typename std::iterator_traits<It>::reference;
-    using iterator_category = std::bidirectional_iterator_tag;
+    using iterator_category = std::forward_iterator_tag;
 
 
     view_iterator() ENTT_NOEXCEPT
     view_iterator() ENTT_NOEXCEPT
-        : first{},
+        : it{},
           last{},
           last{},
-          it{},
           pools{},
           pools{},
           filter{} {}
           filter{} {}
 
 
-    view_iterator(It from, It to, It curr, std::array<const Type *, Component> all_of, std::array<const Type *, Exclude> none_of) ENTT_NOEXCEPT
-        : first{from},
+    view_iterator(It curr, It to, std::array<const Type *, Component> all_of, std::array<const Type *, Exclude> none_of) ENTT_NOEXCEPT
+        : it{curr},
           last{to},
           last{to},
-          it{curr},
           pools{all_of},
           pools{all_of},
           filter{none_of} {
           filter{none_of} {
         if(it != last && !valid()) {
         if(it != last && !valid()) {
@@ -224,16 +201,6 @@ public:
         return ++(*this), orig;
         return ++(*this), orig;
     }
     }
 
 
-    view_iterator &operator--() ENTT_NOEXCEPT {
-        while(--it != first && !valid()) {}
-        return *this;
-    }
-
-    view_iterator operator--(int) ENTT_NOEXCEPT {
-        view_iterator orig = *this;
-        return operator--(), orig;
-    }
-
     [[nodiscard]] bool operator==(const view_iterator &other) const ENTT_NOEXCEPT {
     [[nodiscard]] bool operator==(const view_iterator &other) const ENTT_NOEXCEPT {
         return other.it == it;
         return other.it == it;
     }
     }
@@ -251,9 +218,8 @@ public:
     }
     }
 
 
 private:
 private:
-    It first;
-    It last;
     It it;
     It it;
+    It last;
     std::array<const Type *, Component> pools;
     std::array<const Type *, Component> pools;
     std::array<const Type *, Exclude> filter;
     std::array<const Type *, Exclude> filter;
 };
 };
@@ -354,8 +320,6 @@ public:
     using size_type = std::size_t;
     using size_type = std::size_t;
     /*! @brief Bidirectional iterator type. */
     /*! @brief Bidirectional iterator type. */
     using iterator = internal::view_iterator<basic_common_type, typename basic_common_type::iterator, sizeof...(Component) - 1u, sizeof...(Exclude)>;
     using iterator = internal::view_iterator<basic_common_type, typename basic_common_type::iterator, sizeof...(Component) - 1u, sizeof...(Exclude)>;
-    /*! @brief Reverse iterator type. */
-    using reverse_iterator = internal::view_iterator<basic_common_type, typename basic_common_type::reverse_iterator, sizeof...(Component) - 1u, sizeof...(Exclude)>;
     /*! @brief Iterable view type. */
     /*! @brief Iterable view type. */
     using iterable_view = internal::iterable_view<basic_view>;
     using iterable_view = internal::iterable_view<basic_view>;
     /*! @brief Common type among all storage types. */
     /*! @brief Common type among all storage types. */
@@ -453,7 +417,7 @@ public:
      * @return An iterator to the first entity of the view.
      * @return An iterator to the first entity of the view.
      */
      */
     [[nodiscard]] iterator begin() const {
     [[nodiscard]] iterator begin() const {
-        return iterator{view->begin(), view->end(), view->begin(), pools_to_array(std::index_sequence_for<Component...>{}), filter};
+        return iterator{view->begin(), view->end(), pools_to_array(std::index_sequence_for<Component...>{}), filter};
     }
     }
 
 
     /**
     /**
@@ -466,34 +430,7 @@ public:
      * @return An iterator to the entity following the last entity of the view.
      * @return An iterator to the entity following the last entity of the view.
      */
      */
     [[nodiscard]] iterator end() const {
     [[nodiscard]] iterator end() const {
-        return iterator{view->begin(), view->end(), view->end(), pools_to_array(std::index_sequence_for<Component...>{}), filter};
-    }
-
-    /**
-     * @brief Returns an iterator to the first entity of the reversed view.
-     *
-     * The returned iterator points to the first entity of the reversed view. If
-     * the view is empty, the returned iterator will be equal to `rend()`.
-     *
-     * @return An iterator to the first entity of the reversed view.
-     */
-    [[nodiscard]] reverse_iterator rbegin() const {
-        return reverse_iterator{view->rbegin(), view->rend(), view->rbegin(), pools_to_array(std::index_sequence_for<Component...>{}), filter};
-    }
-
-    /**
-     * @brief Returns an iterator that is past the last entity of the reversed
-     * view.
-     *
-     * The returned iterator points to the entity following the last entity of
-     * the reversed view. Attempting to dereference the returned iterator
-     * results in undefined behavior.
-     *
-     * @return An iterator to the entity following the last entity of the
-     * reversed view.
-     */
-    [[nodiscard]] reverse_iterator rend() const {
-        return reverse_iterator{view->rbegin(), view->rend(), view->rend(), pools_to_array(std::index_sequence_for<Component...>{}), filter};
+        return iterator{view->end(), view->end(), pools_to_array(std::index_sequence_for<Component...>{}), filter};
     }
     }
 
 
     /**
     /**
@@ -512,8 +449,9 @@ public:
      * otherwise.
      * otherwise.
      */
      */
     [[nodiscard]] entity_type back() const {
     [[nodiscard]] entity_type back() const {
-        const auto it = rbegin();
-        return it != rend() ? *it : null;
+        auto it = view->rbegin();
+        for(const auto last = view->rend(); it != last && !contains(*it); ++it) {}
+        return it == view->rend() ? null : *it;
     }
     }
 
 
     /**
     /**
@@ -523,8 +461,7 @@ public:
      * iterator otherwise.
      * iterator otherwise.
      */
      */
     [[nodiscard]] iterator find(const entity_type entt) const {
     [[nodiscard]] iterator find(const entity_type entt) const {
-        const auto it = iterator{view->begin(), view->end(), view->find(entt), pools_to_array(std::index_sequence_for<Component...>{}), filter};
-        return (it != end() && *it == entt) ? it : end();
+        return contains(entt) ? iterator{view->find(entt), view->end(), pools_to_array(std::index_sequence_for<Component...>{}), filter} : end();
     }
     }
 
 
     /**
     /**
@@ -823,8 +760,7 @@ public:
      * otherwise.
      * otherwise.
      */
      */
     [[nodiscard]] entity_type front() const {
     [[nodiscard]] entity_type front() const {
-        const auto it = begin();
-        return it != end() ? *it : null;
+        return empty() ? null : *begin();
     }
     }
 
 
     /**
     /**
@@ -833,8 +769,7 @@ public:
      * otherwise.
      * otherwise.
      */
      */
     [[nodiscard]] entity_type back() const {
     [[nodiscard]] entity_type back() const {
-        const auto it = rbegin();
-        return it != rend() ? *it : null;
+        return empty() ? null : *rbegin();
     }
     }
 
 
     /**
     /**
@@ -844,8 +779,7 @@ public:
      * iterator otherwise.
      * iterator otherwise.
      */
      */
     [[nodiscard]] iterator find(const entity_type entt) const {
     [[nodiscard]] iterator find(const entity_type entt) const {
-        const auto it = view->find(entt);
-        return it != end() && *it == entt ? it : end();
+        return contains(entt) ? view->find(entt) : end();
     }
     }
 
 
     /**
     /**

+ 2 - 4
test/entt/entity/registry.cpp

@@ -567,7 +567,6 @@ TEST(Registry, RangeDestroy) {
     ASSERT_TRUE(registry.valid(entities[2u]));
     ASSERT_TRUE(registry.valid(entities[2u]));
 
 
     registry.destroy(icview.begin(), icview.end());
     registry.destroy(icview.begin(), icview.end());
-    registry.destroy(icview.rbegin(), icview.rend());
 
 
     ASSERT_FALSE(registry.valid(entities[0u]));
     ASSERT_FALSE(registry.valid(entities[0u]));
     ASSERT_FALSE(registry.valid(entities[1u]));
     ASSERT_FALSE(registry.valid(entities[1u]));
@@ -1431,7 +1430,6 @@ TEST(Registry, Erase) {
 
 
     registry.erase<int, char>(entities[0u]);
     registry.erase<int, char>(entities[0u]);
     registry.erase<int, char>(icview.begin(), icview.end());
     registry.erase<int, char>(icview.begin(), icview.end());
-    registry.erase<int, char>(icview.rbegin(), icview.rend());
 
 
     ASSERT_FALSE(registry.any_of<int>(entities[0u]));
     ASSERT_FALSE(registry.any_of<int>(entities[0u]));
     ASSERT_FALSE(registry.all_of<int>(entities[1u]));
     ASSERT_FALSE(registry.all_of<int>(entities[1u]));
@@ -1539,7 +1537,7 @@ TEST(Registry, Remove) {
     registry.remove<int, char>(entities[0u]);
     registry.remove<int, char>(entities[0u]);
 
 
     ASSERT_EQ((registry.remove<int, char>(icview.begin(), icview.end())), 2u);
     ASSERT_EQ((registry.remove<int, char>(icview.begin(), icview.end())), 2u);
-    ASSERT_EQ((registry.remove<int, char>(icview.rbegin(), icview.rend())), 0u);
+    ASSERT_EQ((registry.remove<int, char>(icview.begin(), icview.end())), 0u);
 
 
     ASSERT_FALSE(registry.any_of<int>(entities[0u]));
     ASSERT_FALSE(registry.any_of<int>(entities[0u]));
     ASSERT_FALSE(registry.all_of<int>(entities[1u]));
     ASSERT_FALSE(registry.all_of<int>(entities[1u]));
@@ -1602,7 +1600,7 @@ TEST(Registry, StableRemove) {
     registry.remove<int, stable_type>(entities[0u]);
     registry.remove<int, stable_type>(entities[0u]);
 
 
     ASSERT_EQ((registry.remove<int, stable_type>(icview.begin(), icview.end())), 2u);
     ASSERT_EQ((registry.remove<int, stable_type>(icview.begin(), icview.end())), 2u);
-    ASSERT_EQ((registry.remove<int, stable_type>(icview.rbegin(), icview.rend())), 0u);
+    ASSERT_EQ((registry.remove<int, stable_type>(icview.begin(), icview.end())), 0u);
 
 
     ASSERT_FALSE(registry.any_of<int>(entities[0u]));
     ASSERT_FALSE(registry.any_of<int>(entities[0u]));
     ASSERT_FALSE(registry.all_of<int>(entities[1u]));
     ASSERT_FALSE(registry.all_of<int>(entities[1u]));

+ 63 - 116
test/entt/entity/view.cpp

@@ -171,48 +171,45 @@ TEST(SingleComponentView, Empty) {
 
 
 TEST(SingleComponentView, Each) {
 TEST(SingleComponentView, Each) {
     entt::registry registry;
     entt::registry registry;
+    entt::entity entity[2]{registry.create(), registry.create()};
 
 
-    registry.emplace<int>(registry.create(), 0);
-    registry.emplace<int>(registry.create(), 1);
+    registry.emplace<int>(entity[0u], 0);
+    registry.emplace<int>(entity[1u], 1);
 
 
     auto view = registry.view<int>();
     auto view = registry.view<int>();
+    auto cview = std::as_const(registry).view<const int>();
+
     auto iterable = view.each();
     auto iterable = view.each();
+    auto citerable = cview.each();
 
 
-    ASSERT_NE(iterable.begin(), iterable.end());
+    ASSERT_NE(citerable.begin(), citerable.end());
     ASSERT_NO_THROW(iterable.begin()->operator=(*iterable.begin()));
     ASSERT_NO_THROW(iterable.begin()->operator=(*iterable.begin()));
 
 
-    auto cview = std::as_const(registry).view<const int>();
-    auto citerable = cview.each();
+    auto it = iterable.begin();
 
 
-    std::size_t cnt = 0;
+    ASSERT_EQ((it++, ++it), iterable.end());
 
 
-    for(auto first = citerable.rbegin(), last = citerable.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([expected = 1u](auto entt, int &value) mutable {
+        ASSERT_EQ(entt::to_integral(entt), expected);
+        ASSERT_EQ(value, expected);
+        --expected;
+    });
 
 
-    view.each([&cnt](auto, int &) { ++cnt; });
-    view.each([&cnt](int &) { ++cnt; });
+    cview.each([expected = 1u](const int &value) mutable {
+        ASSERT_EQ(value, expected);
+        --expected;
+    });
 
 
-    ASSERT_EQ(cnt, std::size_t{6});
+    ASSERT_EQ(std::get<0>(*iterable.begin()), entity[1u]);
+    ASSERT_EQ(std::get<0>(*++citerable.begin()), entity[0u]);
 
 
-    cview.each([&cnt](const int &) { --cnt; });
-    cview.each([&cnt](auto, const int &) { --cnt; });
+    static_assert(std::is_same_v<decltype(std::get<1>(*iterable.begin())), int &>);
+    static_assert(std::is_same_v<decltype(std::get<1>(*citerable.begin())), const int &>);
 
 
     // do not use iterable, make sure an iterable view works when created from a temporary
     // do not use iterable, make sure an iterable view works when created from a temporary
-    for(auto [entt, iv]: registry.view<int>().each()) {
-        static_assert(std::is_same_v<decltype(entt), entt::entity>);
-        static_assert(std::is_same_v<decltype(iv), int &>);
-        ASSERT_EQ(iv, --cnt);
+    for(auto [entt, value]: view.each()) {
+        ASSERT_EQ(entt::to_integral(entt), value);
     }
     }
-
-    ASSERT_EQ(cnt, std::size_t{0});
-
-    auto it = iterable.begin();
-    auto rit = iterable.rbegin();
-
-    ASSERT_EQ((it++, ++it), iterable.end());
-    ASSERT_EQ((rit++, ++rit), iterable.rend());
 }
 }
 
 
 TEST(SingleComponentView, ConstNonConstAndAllInBetween) {
 TEST(SingleComponentView, ConstNonConstAndAllInBetween) {
@@ -493,19 +490,15 @@ TEST(MultiComponentView, Functionalities) {
     registry.emplace<char>(e1, '2');
     registry.emplace<char>(e1, '2');
 
 
     ASSERT_EQ(*view.begin(), e1);
     ASSERT_EQ(*view.begin(), e1);
-    ASSERT_EQ(*view.rbegin(), e1);
+    ASSERT_EQ(*cview.begin(), e1);
     ASSERT_EQ(++view.begin(), (view.end()));
     ASSERT_EQ(++view.begin(), (view.end()));
-    ASSERT_EQ(++view.rbegin(), (view.rend()));
+    ASSERT_EQ(++cview.begin(), (cview.end()));
 
 
     ASSERT_NO_FATAL_FAILURE((view.begin()++));
     ASSERT_NO_FATAL_FAILURE((view.begin()++));
     ASSERT_NO_FATAL_FAILURE((++cview.begin()));
     ASSERT_NO_FATAL_FAILURE((++cview.begin()));
-    ASSERT_NO_FATAL_FAILURE(view.rbegin()++);
-    ASSERT_NO_FATAL_FAILURE(++cview.rbegin());
 
 
     ASSERT_NE(view.begin(), view.end());
     ASSERT_NE(view.begin(), view.end());
     ASSERT_NE(cview.begin(), cview.end());
     ASSERT_NE(cview.begin(), cview.end());
-    ASSERT_NE(view.rbegin(), view.rend());
-    ASSERT_NE(cview.rbegin(), cview.rend());
     ASSERT_EQ(view.size_hint(), 1u);
     ASSERT_EQ(view.size_hint(), 1u);
 
 
     for(auto entity: view) {
     for(auto entity: view) {
@@ -597,9 +590,10 @@ TEST(MultiComponentView, LazyExcludedTypeFromConstRegistry) {
 
 
 TEST(MultiComponentView, Iterator) {
 TEST(MultiComponentView, Iterator) {
     entt::registry registry;
     entt::registry registry;
-    const auto entity = registry.create();
-    registry.emplace<int>(entity);
-    registry.emplace<char>(entity);
+    const entt::entity entity[2]{registry.create(), registry.create()};
+
+    registry.insert<int>(std::begin(entity), std::end(entity));
+    registry.insert<char>(std::begin(entity), std::end(entity));
 
 
     const auto view = registry.view<int, char>();
     const auto view = registry.view<int, char>();
     using iterator = typename decltype(view)::iterator;
     using iterator = typename decltype(view)::iterator;
@@ -613,57 +607,13 @@ TEST(MultiComponentView, Iterator) {
     ASSERT_EQ(end, view.end());
     ASSERT_EQ(end, view.end());
     ASSERT_NE(begin, end);
     ASSERT_NE(begin, end);
 
 
+    ASSERT_EQ(*begin, entity[1u]);
+    ASSERT_EQ(*begin.operator->(), entity[1u]);
     ASSERT_EQ(begin++, view.begin());
     ASSERT_EQ(begin++, view.begin());
-    ASSERT_EQ(begin--, view.end());
 
 
+    ASSERT_EQ(*begin, entity[0u]);
+    ASSERT_EQ(*begin.operator->(), entity[0u]);
     ASSERT_EQ(++begin, view.end());
     ASSERT_EQ(++begin, view.end());
-    ASSERT_EQ(--begin, view.begin());
-
-    ASSERT_EQ(*begin, entity);
-    ASSERT_EQ(*begin.operator->(), entity);
-
-    registry.emplace<int>(registry.create());
-    registry.emplace<char>(registry.create());
-
-    const auto other = registry.create();
-    registry.emplace<int>(other);
-    registry.emplace<char>(other);
-
-    begin = view.begin();
-
-    ASSERT_EQ(*(begin++), other);
-    ASSERT_EQ(*(begin++), entity);
-    ASSERT_EQ(begin--, end);
-    ASSERT_EQ(*(begin--), entity);
-    ASSERT_EQ(*begin, other);
-}
-
-TEST(MultiComponentView, ReverseIterator) {
-    entt::registry registry;
-    const auto entity = registry.create();
-    registry.emplace<int>(entity);
-    registry.emplace<char>(entity);
-
-    const auto view = registry.view<int, char>();
-    using iterator = typename decltype(view)::reverse_iterator;
-
-    iterator end{view.rbegin()};
-    iterator begin{};
-    begin = view.rend();
-    std::swap(begin, end);
-
-    ASSERT_EQ(begin, view.rbegin());
-    ASSERT_EQ(end, view.rend());
-    ASSERT_NE(begin, end);
-
-    ASSERT_EQ(begin++, view.rbegin());
-    ASSERT_EQ(begin--, view.rend());
-
-    ASSERT_EQ(++begin, view.rend());
-    ASSERT_EQ(--begin, view.rbegin());
-
-    ASSERT_EQ(*begin, entity);
-    ASSERT_EQ(*begin.operator->(), entity);
 }
 }
 
 
 TEST(MultiComponentView, ElementAccess) {
 TEST(MultiComponentView, ElementAccess) {
@@ -718,59 +668,56 @@ TEST(MultiComponentView, SizeHint) {
 
 
     ASSERT_EQ(view.size_hint(), 1u);
     ASSERT_EQ(view.size_hint(), 1u);
     ASSERT_EQ(view.begin(), view.end());
     ASSERT_EQ(view.begin(), view.end());
-    ASSERT_EQ(view.rbegin(), view.rend());
 }
 }
 
 
 TEST(MultiComponentView, Each) {
 TEST(MultiComponentView, Each) {
     entt::registry registry;
     entt::registry registry;
+    entt::entity entity[2]{registry.create(), registry.create()};
 
 
-    const auto e0 = registry.create();
-    registry.emplace<int>(e0, 0);
-    registry.emplace<char>(e0);
+    registry.emplace<int>(entity[0u], 0);
+    registry.emplace<char>(entity[0u], 0);
 
 
     const auto e1 = registry.create();
     const auto e1 = registry.create();
-    registry.emplace<int>(e1, 1);
-    registry.emplace<char>(e1);
+    registry.emplace<int>(entity[1u], 1);
+    registry.emplace<char>(entity[1u], 1);
 
 
     auto view = registry.view<int, char>();
     auto view = registry.view<int, char>();
+    auto cview = std::as_const(registry).view<const int, const char>();
+
     auto iterable = view.each();
     auto iterable = view.each();
+    auto citerable = cview.each();
 
 
-    ASSERT_NE(iterable.begin(), iterable.end());
+    ASSERT_NE(citerable.begin(), citerable.end());
     ASSERT_NO_THROW(iterable.begin()->operator=(*iterable.begin()));
     ASSERT_NO_THROW(iterable.begin()->operator=(*iterable.begin()));
 
 
-    auto cview = std::as_const(registry).view<const int, const char>();
-    auto citerable = cview.each();
+    auto it = iterable.begin();
 
 
-    std::size_t cnt = 0;
+    ASSERT_EQ((it++, ++it), iterable.end());
 
 
-    for(auto first = citerable.rbegin(), last = citerable.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([expected = 1u](auto entt, int &ivalue, char &cvalue) mutable {
+        ASSERT_EQ(entt::to_integral(entt), expected);
+        ASSERT_EQ(ivalue, expected);
+        ASSERT_EQ(cvalue, expected);
+        --expected;
+    });
 
 
-    view.each([&cnt](auto, int &, char &) { ++cnt; });
-    view.each([&cnt](int &, char &) { ++cnt; });
+    cview.each([expected = 1u](const int &ivalue, const char &cvalue) mutable {
+        ASSERT_EQ(ivalue, expected);
+        ASSERT_EQ(cvalue, expected);
+        --expected;
+    });
 
 
-    ASSERT_EQ(cnt, std::size_t{6});
+    ASSERT_EQ(std::get<0>(*iterable.begin()), entity[1u]);
+    ASSERT_EQ(std::get<0>(*++citerable.begin()), entity[0u]);
 
 
-    cview.each([&cnt](const int &, const char &) { --cnt; });
-    cview.each([&cnt](auto, const int &, const char &) { --cnt; });
+    static_assert(std::is_same_v<decltype(std::get<1>(*iterable.begin())), int &>);
+    static_assert(std::is_same_v<decltype(std::get<2>(*citerable.begin())), const char &>);
 
 
     // do not use iterable, make sure an iterable view works when created from a temporary
     // do not use iterable, make sure an iterable view works when created from a temporary
-    for(auto [entt, iv, cv]: registry.view<int, char>().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 &>);
-        ASSERT_EQ(iv, --cnt);
+    for(auto [entt, ivalue, cvalue]: registry.view<int, char>().each()) {
+        ASSERT_EQ(entt::to_integral(entt), ivalue);
+        ASSERT_EQ(entt::to_integral(entt), cvalue);
     }
     }
-
-    ASSERT_EQ(cnt, std::size_t{0});
-
-    auto it = iterable.begin();
-    auto rit = iterable.rbegin();
-
-    ASSERT_EQ((it++, ++it), iterable.end());
-    ASSERT_EQ((rit++, ++rit), iterable.rend());
 }
 }
 
 
 TEST(MultiComponentView, EachWithSuggestedType) {
 TEST(MultiComponentView, EachWithSuggestedType) {