فهرست منبع

removed raw view + added extended each member function to all the other views

Michele Caini 7 سال پیش
والد
کامیت
c91f9beddb

+ 7 - 69
docs/entity.md

@@ -30,7 +30,6 @@
     * [Single component standard view](#single-component-standard-view)
     * [Multi component standard view](#multi-component-standard-view)
   * [Persistent View](#persistent-view)
-  * [Raw View](#raw-view)
   * [Runtime View](#runtime-view)
   * [Types: const, non-const and all in between](#types-const-non-const-and-all-in-between)
   * [Give me everything](#give-me-everything)
@@ -810,9 +809,9 @@ view can only iterate entities and their components, then read or update the
 data members of the latter.<br/>
 It is a subtle difference that can help designing a better software sometimes.
 
-There are mainly four kinds of views: standard (also known as `view`),
-persistent (also known as `persistent_view`), raw (also known as `raw_view`) and
-runtime (also known as `runtime_view`).<br/>
+There are mainly three kinds of views: standard (also known as `view`),
+persistent (also known as `persistent_view`), and runtime (also known as
+`runtime_view`).<br/>
 All of them have pros and cons to take in consideration. In particular:
 
 * Standard views:
@@ -854,22 +853,6 @@ All of them have pros and cons to take in consideration. In particular:
     persistent views there will be, the less performing will be creating and
     destroying entities and components or sorting a pool.
 
-* Raw views:
-
-  Pros:
-
-  * They work out-of-the-box and don't require any dedicated data structure.
-  * Creating and destroying them isn't expensive at all because they don't have
-    any type of initialization.
-  * They are the best tool for iterating components when it is not necessary to
-    know which entities they belong to.
-  * They don't affect any other operations of the registry.
-
-  Cons:
-
-  * They can be used to iterate only one type of component at a time.
-  * They don't return the entity to which a component belongs to the caller.
-
 * Runtime views:
 
   Pros:
@@ -887,7 +870,6 @@ All of them have pros and cons to take in consideration. In particular:
 
 To sum up and as a rule of thumb:
 
-* Use a raw view to iterate components only (no entities) for a given type.
 * Use a standard view to iterate entities and components for a single type.
 * Use a standard view to iterate entities and components for multiple types when
   a significantly low number of entities have one of the components, persistent
@@ -1096,48 +1078,6 @@ only entities, using `each` should be the preferred approach.
 function template of a registry during iterations, if possible. However, keep in
 mind that it works only with the components of the view itself.
 
-## Raw View
-
-Raw views return all the components of a given type. This kind of views can
-access components directly and avoid extra indirections like when components are
-accessed via an entity identifier.<br/>
-They offer a bunch of functionalities to get the number of instances they are
-going to return and a raw access to the entity list as well as to the component
-list.<br/>
-Refer to the inline documentation for all the details.
-
-Raw views can be used only to iterate components for a single type:
-
-```cpp
-auto view = registry.raw_view<renderable>();
-```
-
-There is no need to store views around for they are extremely cheap to
-construct, even though they can be copied without problems and reused freely. In
-fact, they return newly created and correctly initialized iterators whenever
-`begin` or `end` are invoked.<br/>
-To iterate a raw view, use it in a range-for loop:
-
-```cpp
-auto view = registry.raw_view<renderable>();
-
-for(auto &&component: raw) {
-    // ...
-}
-```
-
-Or rely on the `each` member function:
-
-```cpp
-registry.raw_view<renderable>().each([](auto &renderable) {
-    // ...
-});
-```
-
-Performance are exactly the same in both cases.
-
-**Note**: raw views don't have a `get` member function for obvious reasons.
-
 ## Runtime View
 
 Runtime views iterate entities that have at least all the given components in
@@ -1334,13 +1274,11 @@ assigned.
 
 The drawback is that the `raw` member function will no longer be able to return
 a valid pointer to the list of components in the pool. This is because there is
-no list of components at all. Therefore, `raw` will always return `nullptr` for
-this type of components.<br/>
+no list of components at all. Only one instance of the given type exists in this
+case. Therefore, `raw` will always return a pointer to that instance.<br/>
 Nonetheless, the iterators returned by the `begin` and `end` member functions
-are still valid and can be used safely. Similarly, raw views can still be built
-for this type of components if required.<br/>
-More in general, all the features offered by the library aren't affected, but
-for the `raw` member function that is no longer available instead.
+are still valid and can be used safely. More in general, all the features
+offered by the library aren't affected, but for the `raw` member function.
 
 # Multithreading
 

+ 0 - 10
src/entt/entity/helper.hpp

@@ -47,16 +47,6 @@ struct as_view final {
         return reg.template persistent_view<Component...>();
     }
 
-    /**
-     * @brief Conversion function from a registry to a raw view.
-     * @tparam Component Type of component used to construct the view.
-     * @return A newly created raw view.
-     */
-    template<typename Component>
-    inline operator entt::raw_view<Entity, Component>() const {
-        return reg.template raw_view<Component>();
-    }
-
 private:
     registry_type &reg;
 };

+ 0 - 39
src/entt/entity/registry.hpp

@@ -1124,7 +1124,6 @@ public:
      * @sa view
      * @sa view<Entity, Component>
      * @sa persistent_view
-     * @sa raw_view
      * @sa runtime_view
      *
      * @tparam Component Type of components used to construct the view.
@@ -1174,7 +1173,6 @@ public:
      * @sa view
      * @sa view<Entity, Component>
      * @sa persistent_view
-     * @sa raw_view
      * @sa runtime_view
      *
      * @tparam Component Types of components used to construct the view.
@@ -1222,42 +1220,6 @@ public:
         return const_cast<registry *>(this)->persistent_view<Component...>(type_list<Exclude...>{});
     }
 
-    /**
-     * @brief Returns a raw view for the given component.
-     *
-     * This kind of views are created on the fly and share with the registry its
-     * internal data structures.<br/>
-     * Feel free to discard a view after the use. Creating and destroying a view
-     * is an incredibly cheap operation because they do not require any type of
-     * initialization.<br/>
-     * As a rule of thumb, storing a view should never be an option.
-     *
-     * Raw views are incredibly fast and must be considered the best tool to
-     * iterate components whenever knowing the entities to which they belong
-     * isn't required.
-     *
-     * @sa view
-     * @sa view<Entity, Component>
-     * @sa persistent_view
-     * @sa raw_view
-     * @sa runtime_view
-     *
-     * @tparam Component Type of component used to construct the view.
-     * @return A newly created raw view.
-     */
-    template<typename Component>
-    entt::raw_view<Entity, Component> raw_view() {
-        assure<Component>();
-        return { &pool<Component>() };
-    }
-
-    /*! @copydoc raw_view */
-    template<typename Component>
-    inline entt::raw_view<Entity, Component> raw_view() const {
-        static_assert(std::is_const_v<Component>);
-        return const_cast<registry *>(this)->raw_view<Component>();
-    }
-
     /**
      * @brief Returns a runtime view for the given components.
      *
@@ -1276,7 +1238,6 @@ public:
      * @sa view
      * @sa view<Entity, Component>
      * @sa persistent_view
-     * @sa raw_view
      * @sa runtime_view
      *
      * @tparam It Type of forward iterator.

+ 4 - 3
src/entt/entity/sparse_set.hpp

@@ -774,14 +774,15 @@ public:
      * to iterate the sparse set in the expected order.
      *
      * @warning
-     * Empty components aren't explicitly instantiated. Therefore, this function
-     * always returns `nullptr` for them.
+     * Empty components aren't explicitly instantiated. Only one instance of the
+     * given type is created. Therefore, this function always returns a pointer
+     * to that instance.
      *
      * @return A pointer to the array of objects.
      */
     const object_type * raw() const ENTT_NOEXCEPT {
         if constexpr(std::is_empty_v<object_type>) {
-            return nullptr;
+            return &instances;
         } else {
             return instances.data();
         }

+ 48 - 215
src/entt/entity/view.hpp

@@ -62,7 +62,6 @@ class registry;
  *
  * @sa view
  * @sa view<Entity, Component>
- * @sa raw_view
  * @sa runtime_view
  *
  * @tparam Entity A valid entity type (see entt_traits for more details).
@@ -101,10 +100,9 @@ class persistent_view final {
     }
 
     template<typename Comp>
-    inline decltype(auto) get([[maybe_unused]] typename persistent_type::object_type::value_type index, [[maybe_unused]] const Entity entity) const {
+    inline decltype(auto) instance([[maybe_unused]] typename persistent_type::object_type::value_type index) const {
         if constexpr(std::is_empty_v<Comp>) {
-            // raw returns nullptr for empty components
-            return pool<Comp>()->get(entity);
+            return *pool<Comp>()->raw();
         } else {
             return pool<Comp>()->raw()[index];
         }
@@ -112,10 +110,17 @@ class persistent_view final {
 
     template<typename Func, std::size_t... Indexes>
     void each(Func func, std::index_sequence<Indexes...>) const {
-        std::for_each(handler->view_type::begin(), handler->view_type::end(), [func = std::move(func), raw = handler->cbegin(), this](const auto entity) mutable {
-            func(entity, get<Component>((*raw)[Indexes], entity)...);
-            ++raw;
-        });
+        if constexpr(std::is_invocable_v<Func, std::add_lvalue_reference_t<Component>...>) {
+            std::for_each(handler->cbegin(), handler->cend(), [func = std::move(func), this](const auto &indexes) mutable {
+                // we can safely use the first entity each and every time, b
+                func(instance<Component>(indexes[Indexes])...);
+            });
+        } else {
+            std::for_each(handler->view_type::begin(), handler->view_type::end(), [func = std::move(func), raw = handler->cbegin(), this](const auto entity) mutable {
+                func(entity, instance<Component>((*raw)[Indexes])...);
+                ++raw;
+            });
+        }
     }
 
 public:
@@ -268,12 +273,14 @@ public:
      * object to them.
      *
      * The function object is invoked for each entity. It is provided with the
-     * entity itself and a set of const references to all the components of the
-     * view.<br/>
-     * The signature of the function should be equivalent to the following:
+     * entity itself and a set of references to all its components. The
+     * _constness_ of the components is as requested.<br/>
+     * The signature of the function must be equivalent to one of the following
+     * forms:
      *
      * @code{.cpp}
      * void(const entity_type, Component &...);
+     * void(Component &...);
      * @endcode
      *
      * @tparam Func Type of the function object to invoke.
@@ -346,7 +353,6 @@ private:
  *
  * @sa view<Entity, Component>
  * @sa persistent_view
- * @sa raw_view
  * @sa runtime_view
  *
  * @tparam Entity A valid entity type (see entt_traits for more details).
@@ -488,8 +494,14 @@ class view final {
         auto begin = cpool->view_type::begin();
 
         // we can directly use the raw iterators if pools are ordered
-        while(((begin != end) && ... && (*begin == *(std::get<Indexes>(data)++)))) {
-            func(*(begin++), *(std::get<component_iterator_type<Component>>(raw)++)...);
+        if constexpr(std::is_invocable_v<Func, std::add_lvalue_reference_t<Component>...>) {
+            for(; ((begin != end) && ... && (*begin == *(std::get<Indexes>(data)++))); ++begin) {
+                func(*(std::get<component_iterator_type<Component>>(raw)++)...);
+            }
+        } else {
+            while(((begin != end) && ... && (*begin == *(std::get<Indexes>(data)++)))) {
+                func(*(begin++), *(std::get<component_iterator_type<Component>>(raw)++)...);
+            }
         }
 
         // fallback to visit what remains using indirections
@@ -500,7 +512,11 @@ class view final {
 
             if(((sz < extent) && ... && std::get<Indexes>(other)->fast(entity))) {
                 // avoided at least the indirection due to the sparse set for the pivot type (see get for more details)
-                func(entity, get<Comp, Component>(it, entity)...);
+                if constexpr(std::is_invocable_v<Func, std::add_lvalue_reference_t<Component>...>) {
+                    func(get<Comp, Component>(it, entity)...);
+                } else {
+                    func(entity, get<Comp, Component>(it, entity)...);
+                }
             }
         }
     }
@@ -636,12 +652,14 @@ public:
      * object to them.
      *
      * The function object is invoked for each entity. It is provided with the
-     * entity itself and a set of const references to all the components of the
-     * view.<br/>
-     * The signature of the function should be equivalent to the following:
+     * entity itself and a set of references to all its components. The
+     * _constness_ of the components is as requested.<br/>
+     * The signature of the function must be equivalent to one of the following
+     * forms:
      *
      * @code{.cpp}
      * void(const entity_type, Component &...);
+     * void(Component &...);
      * @endcode
      *
      * @tparam Func Type of the function object to invoke.
@@ -690,7 +708,6 @@ private:
  *
  * @sa view
  * @sa persistent_view
- * @sa raw_view
  * @sa runtime_view
  *
  * @tparam Entity A valid entity type (see entt_traits for more details).
@@ -870,202 +887,13 @@ public:
      * object to them.
      *
      * The function object is invoked for each entity. It is provided with the
-     * entity itself and a const reference to the component of the view.<br/>
-     * The signature of the function should be equivalent to the following:
-     *
-     * @code{.cpp}
-     * void(const entity_type, const Component &);
-     * @endcode
-     *
-     * @tparam Func Type of the function object to invoke.
-     * @param func A valid function object.
-     */
-    template<typename Func>
-    void each(Func func) const {
-        std::for_each(pool->view_type::begin(), pool->view_type::end(), [func = std::move(func), raw = pool->begin()](const auto entity) mutable {
-            func(entity, *(raw++));
-        });
-    }
-
-private:
-    pool_type *pool;
-};
-
-
-/**
- * @brief Raw view.
- *
- * Raw views are meant to easily iterate components without having to resort to
- * using any other member function, so as to further increase the performance.
- * Whenever knowing the entity to which a component belongs isn't required, this
- * should be the preferred tool.<br/>
- * Order of elements during iterations are highly dependent on the order of the
- * underlying data structure. See sparse_set and its specializations for more
- * details.
- *
- * @b Important
- *
- * Iterators aren't invalidated if:
- *
- * * New instances of the given component are created and assigned to entities.
- * * The entity to which the component belongs is modified (as an example, the
- *   given component is destroyed).
- *
- * In all the other cases, modifying the pool of the given component in any way
- * invalidates all the iterators and using them results in undefined behavior.
- *
- * @note
- * Views share a reference to the underlying data structure with the registry
- * that generated them. Therefore any change to the entities and to the
- * components made by means of the registry are immediately reflected by views.
- *
- * @warning
- * Lifetime of a view must overcome the one of the registry that generated it.
- * In any other case, attempting to use a view results in undefined behavior.
- *
- * @sa view
- * @sa view<Entity, Component>
- * @sa persistent_view
- * @sa runtime_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 raw_view final {
-    /*! @brief A registry is allowed to create views. */
-    friend class registry<Entity>;
-
-    using pool_type = std::conditional_t<std::is_const_v<Component>, const sparse_set<Entity, std::remove_const_t<Component>>, sparse_set<Entity, Component>>;
-
-    raw_view(pool_type *pool) ENTT_NOEXCEPT
-        : pool{pool}
-    {}
-
-public:
-    /*! @brief Type of component iterated by the view. */
-    using raw_type = std::remove_reference_t<decltype(std::declval<pool_type>().get(0))>;
-    /*! @brief Underlying entity identifier. */
-    using entity_type = typename pool_type::entity_type;
-    /*! @brief Unsigned integer type. */
-    using size_type = typename pool_type::size_type;
-    /*! @brief Input iterator type. */
-    using iterator_type = decltype(std::declval<pool_type>().begin());
-
-    /*! @brief Default copy constructor. */
-    raw_view(const raw_view &) = default;
-    /*! @brief Default move constructor. */
-    raw_view(raw_view &&) = default;
-
-    /*! @brief Default copy assignment operator. @return This view. */
-    raw_view & operator=(const raw_view &) = default;
-    /*! @brief Default move assignment operator. @return This view. */
-    raw_view & operator=(raw_view &&) = default;
-
-    /**
-     * @brief Returns the number of instances of the given type.
-     * @return Number of instances of the given component.
-     */
-    size_type size() const ENTT_NOEXCEPT {
-        return pool->size();
-    }
-
-    /**
-     * @brief Checks whether the view is empty.
-     * @return True if the view is empty, false otherwise.
-     */
-    bool empty() const ENTT_NOEXCEPT {
-        return pool->empty();
-    }
-
-    /**
-     * @brief Direct access to the list of components.
-     *
-     * The returned pointer is such that range `[raw(), raw() + size()]` is
-     * always a valid range, even if the container is empty.
-     *
-     * @note
-     * There are no guarantees on the order of the components. Use `begin` and
-     * `end` if you want to iterate the view in the expected order.
-     *
-     * @warning
-     * Empty components aren't explicitly instantiated. Therefore, this function
-     * always returns `nullptr` for them.
-     *
-     * @return A pointer to the array of components.
-     */
-    raw_type * raw() const ENTT_NOEXCEPT {
-        return pool->raw();
-    }
-
-    /**
-     * @brief Direct access to the list of entities.
-     *
-     * The returned pointer is such that range `[data(), data() + size()]` is
-     * always a valid range, even if the container is empty.
-     *
-     * @note
-     * There are no guarantees on the order of the entities. Use `begin` and
-     * `end` if you want to iterate the view in the expected order.
-     *
-     * @return A pointer to the array of entities.
-     */
-    const entity_type * data() const ENTT_NOEXCEPT {
-        return pool->data();
-    }
-
-    /**
-     * @brief Returns an iterator to the first instance of the given type.
-     *
-     * The returned iterator points to the first instance of the given type. If
-     * the view is empty, the returned iterator will be equal to `end()`.
-     *
-     * @note
-     * Input iterators stay true to the order imposed to the underlying data
-     * structures.
-     *
-     * @return An iterator to the first instance of the given type.
-     */
-    iterator_type begin() const ENTT_NOEXCEPT {
-        return pool->begin();
-    }
-
-    /**
-     * @brief Returns an iterator that is past the last instance of the given
-     * type.
-     *
-     * The returned iterator points to the element following the last instance
-     * of the given type. Attempting to dereference the returned iterator
-     * results in undefined behavior.
-     *
-     * @note
-     * Input iterators stay true to the order imposed to the underlying data
-     * structures.
-     *
-     * @return An iterator to the element following the last instance of the
-     * given type.
-     */
-    iterator_type end() const ENTT_NOEXCEPT {
-        return pool->end();
-    }
-
-    /**
-     * @brief Returns a reference to the element at the given position.
-     * @param pos Position of the element to return.
-     * @return A reference to the requested element.
-     */
-    raw_type & operator[](const size_type pos) const ENTT_NOEXCEPT {
-        return pool->begin()[pos];
-    }
-
-    /**
-     * @brief Iterates components and applies the given function object to them.
-     *
-     * The function object is provided with a reference to each component of the
-     * view.<br/>
-     * The signature of the function should be equivalent to the following:
+     * entity itself and a reference to its component. The _constness_ of the
+     * component is as requested.<br/>
+     * The signature of the function must be equivalent to one of the following
+     * forms:
      *
      * @code{.cpp}
+     * void(const entity_type, Component &);
      * void(Component &);
      * @endcode
      *
@@ -1074,7 +902,13 @@ public:
      */
     template<typename Func>
     void each(Func func) const {
-        std::for_each(pool->begin(), pool->end(), std::move(func));
+        if constexpr(std::is_invocable_v<Func, std::add_lvalue_reference_t<Component>>) {
+            std::for_each(pool->begin(), pool->end(), std::move(func));
+        } else {
+            std::for_each(pool->view_type::begin(), pool->view_type::end(), [func = std::move(func), raw = pool->begin()](const auto entity) mutable {
+                func(entity, *(raw++));
+            });
+        }
     }
 
 private:
@@ -1120,7 +954,6 @@ private:
  * @sa view
  * @sa view<Entity, Component>
  * @sa persistent_view
- * @sa raw_view
  *
  * @tparam Entity A valid entity type (see entt_traits for more details).
  */

+ 2 - 2
src/entt/signal/emitter.hpp

@@ -23,11 +23,11 @@ namespace entt {
  * The emitter class template follows the CRTP idiom. To create a custom emitter
  * type, derived classes must inherit directly from the base class as:
  *
- * ```cpp
+ * @code{.cpp}
  * struct my_emitter: emitter<my_emitter> {
  *     // ...
  * }
- * ```
+ * @endcode
  *
  * Handlers for the type of events are created internally on the fly. It's not
  * required to specify in advance the full list of accepted types.<br/>

+ 25 - 47
test/benchmark/benchmark.cpp

@@ -115,29 +115,7 @@ TEST(Benchmark, IterateSingleComponent1M) {
         timer.elapsed();
     };
 
-    test([](auto, const auto &) {});
-    test([](auto, auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateSingleComponentRaw1M) {
-    entt::registry<> registry;
-
-    std::cout << "Iterating over 1000000 entities, one component, raw view" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.assign<position>(entity);
-    }
-
-    auto test = [&registry](auto func) {
-        timer timer;
-        registry.raw_view<position>().each(func);
-        timer.elapsed();
-    };
-
-    test([](const auto &) {});
+    test([](const auto &...) {});
     test([](auto &... comp) {
         ((comp.x = {}), ...);
     });
@@ -185,8 +163,8 @@ TEST(Benchmark, IterateTwoComponents1M) {
         timer.elapsed();
     };
 
-    test([](auto, const auto &...) {});
-    test([](auto, auto &... comp) {
+    test([](const auto &...) {});
+    test([](auto &... comp) {
         ((comp.x = {}), ...);
     });
 }
@@ -211,8 +189,8 @@ TEST(Benchmark, IterateTwoComponents1MHalf) {
         timer.elapsed();
     };
 
-    test([](auto, const auto &...) {});
-    test([](auto, auto &... comp) {
+    test([](const auto &...) {});
+    test([](auto &... comp) {
         ((comp.x = {}), ...);
     });
 }
@@ -237,8 +215,8 @@ TEST(Benchmark, IterateTwoComponents1MOne) {
         timer.elapsed();
     };
 
-    test([](auto, const auto &...) {});
-    test([](auto, auto &... comp) {
+    test([](const auto &...) {});
+    test([](auto &... comp) {
         ((comp.x = {}), ...);
     });
 }
@@ -261,8 +239,8 @@ TEST(Benchmark, IterateTwoComponentsPersistent1M) {
         timer.elapsed();
     };
 
-    test([](auto, const auto &...) {});
-    test([](auto, auto &... comp) {
+    test([](const auto &...) {});
+    test([](auto &... comp) {
         ((comp.x = {}), ...);
     });
 }
@@ -374,8 +352,8 @@ TEST(Benchmark, IterateFiveComponents1M) {
         timer.elapsed();
     };
 
-    test([](auto, const auto &...) {});
-    test([](auto, auto &... comp) {
+    test([](const auto &...) {});
+    test([](auto &... comp) {
         ((comp.x = {}), ...);
     });
 }
@@ -403,8 +381,8 @@ TEST(Benchmark, IterateFiveComponents1MHalf) {
         timer.elapsed();
     };
 
-    test([](auto, const auto &...) {});
-    test([](auto, auto &... comp) {
+    test([](const auto &...) {});
+    test([](auto &... comp) {
         ((comp.x = {}), ...);
     });
 }
@@ -432,8 +410,8 @@ TEST(Benchmark, IterateFiveComponents1MOne) {
         timer.elapsed();
     };
 
-    test([](auto, const auto &...) {});
-    test([](auto, auto &... comp) {
+    test([](const auto &...) {});
+    test([](auto &... comp) {
         ((comp.x = {}), ...);
     });
 }
@@ -459,8 +437,8 @@ TEST(Benchmark, IterateFiveComponentsPersistent1M) {
         timer.elapsed();
     };
 
-    test([](auto, const auto &...) {});
-    test([](auto, auto &... comp) {
+    test([](const auto &...) {});
+    test([](auto &... comp) {
         ((comp.x = {}), ...);
     });
 }
@@ -613,8 +591,8 @@ TEST(Benchmark, IterateTenComponents1M) {
         timer.elapsed();
     };
 
-    test([](auto, const auto &...) {});
-    test([](auto, auto &... comp) {
+    test([](const auto &...) {});
+    test([](auto &... comp) {
         ((comp.x = {}), ...);
     });
 }
@@ -647,8 +625,8 @@ TEST(Benchmark, IterateTenComponents1MHalf) {
         timer.elapsed();
     };
 
-    test([](auto, auto &...) {});
-    test([](auto, auto &... comp) {
+    test([](auto &...) {});
+    test([](auto &... comp) {
         ((comp.x = {}), ...);
     });
 }
@@ -681,8 +659,8 @@ TEST(Benchmark, IterateTenComponents1MOne) {
         timer.elapsed();
     };
 
-    test([](auto, const auto &...) {});
-    test([](auto, auto &... comp) {
+    test([](const auto &...) {});
+    test([](auto &... comp) {
         ((comp.x = {}), ...);
     });
 }
@@ -713,8 +691,8 @@ TEST(Benchmark, IterateTenComponentsPersistent1M) {
         timer.elapsed();
     };
 
-    test([](auto, const auto &...) {});
-    test([](auto, auto &... comp) {
+    test([](const auto &...) {});
+    test([](auto &... comp) {
         ((comp.x = {}), ...);
     });
 }

+ 0 - 3
test/entt/entity/helper.cpp

@@ -14,9 +14,6 @@ TEST(Helper, AsView) {
 
     ([](entt::persistent_view<entity_type, int, char>) {})(entt::as_view{registry});
     ([](entt::persistent_view<entity_type, const double, const float>) {})(entt::as_view{cregistry});
-
-    ([](entt::raw_view<entity_type, int>) {})(entt::as_view{registry});
-    ([](entt::raw_view<entity_type, const double>) {})(entt::as_view{cregistry});
 }
 
 TEST(Helper, Dependency) {

+ 0 - 30
test/entt/entity/registry.cpp

@@ -417,24 +417,6 @@ TEST(Registry, PersistentView) {
     ASSERT_EQ(cnt, decltype(view)::size_type{2});
 }
 
-TEST(Registry, RawView) {
-    entt::registry<> registry;
-    auto view = registry.raw_view<int>();
-
-    const auto e0 = registry.create();
-    registry.assign<int>(e0, 0);
-    registry.assign<char>(e0, 'c');
-
-    const auto e1 = registry.create();
-    registry.assign<int>(e1, 0);
-    registry.assign<char>(e1, 'c');
-
-    decltype(view)::size_type cnt{0};
-    view.each([&cnt](auto &...) { ++cnt; });
-
-    ASSERT_EQ(cnt, decltype(view)::size_type{2});
-}
-
 TEST(Registry, CleanStandardViewAfterReset) {
     entt::registry<> registry;
     auto view = registry.view<int>();
@@ -462,18 +444,6 @@ TEST(Registry, CleanPersistentViewAfterReset) {
     ASSERT_EQ(view.size(), entt::registry<>::size_type{0});
 }
 
-TEST(Registry, CleanRawViewAfterReset) {
-    entt::registry<> registry;
-    auto view = registry.raw_view<int>();
-    registry.assign<int>(registry.create(), 0);
-
-    ASSERT_EQ(view.size(), entt::registry<>::size_type{1});
-
-    registry.reset();
-
-    ASSERT_EQ(view.size(), entt::registry<>::size_type{0});
-}
-
 TEST(Registry, SortSingle) {
     entt::registry<> registry;
 

+ 1 - 1
test/entt/entity/snapshot.cpp

@@ -231,7 +231,7 @@ TEST(Snapshot, Iterator) {
 
     ASSERT_EQ(registry.view<another_component>().size(), size);
 
-    registry.view<another_component>().each([](const auto entity, auto &&...) {
+    registry.view<another_component>().each([](const auto entity, const auto &) {
         ASSERT_TRUE(entity % 2);
     });
 }

+ 2 - 2
test/entt/entity/sparse_set.cpp

@@ -632,8 +632,8 @@ TEST(SparseSetWithType, RawEmptyType) {
 
     set.construct(3);
 
-    ASSERT_EQ(set.raw(), nullptr);
-    ASSERT_EQ(cset.raw(), nullptr);
+    ASSERT_EQ(set.raw(), cset.raw());
+    ASSERT_EQ(set.try_get(3), set.raw());
 }
 
 TEST(SparseSetWithType, SortOrdered) {

+ 13 - 143
test/entt/entity/view.cpp

@@ -131,10 +131,12 @@ TEST(PersistentView, Each) {
     std::size_t cnt = 0;
 
     view.each([&cnt](auto, int &, char &) { ++cnt; });
+    view.each([&cnt](int &, char &) { ++cnt; });
 
-    ASSERT_EQ(cnt, std::size_t{2});
+    ASSERT_EQ(cnt, std::size_t{4});
 
     cview.each([&cnt](auto, const int &, const char &) { --cnt; });
+    cview.each([&cnt](const int &, const char &) { --cnt; });
 
     ASSERT_EQ(cnt, std::size_t{0});
 }
@@ -336,6 +338,10 @@ TEST(PersistentView, EmptyAndNonEmptyTypes) {
         ASSERT_TRUE(entity == e0 || entity == e1);
     }
 
+    view.each([e0, e1](const auto entity, const int &, const empty_type &) {
+        ASSERT_TRUE(entity == e0 || entity == e1);
+    });
+
     ASSERT_EQ(view.size(), typename decltype(view)::size_type{2});
     ASSERT_EQ(&view.get<empty_type>(e0), &view.get<empty_type>(e1));
 }
@@ -450,10 +456,12 @@ TEST(SingleComponentView, Each) {
     std::size_t cnt = 0;
 
     view.each([&cnt](auto, int &) { ++cnt; });
+    view.each([&cnt](int &) { ++cnt; });
 
-    ASSERT_EQ(cnt, std::size_t{2});
+    ASSERT_EQ(cnt, std::size_t{4});
 
     cview.each([&cnt](auto, const int &) { --cnt; });
+    cview.each([&cnt](const int &) { --cnt; });
 
     ASSERT_EQ(cnt, std::size_t{0});
 }
@@ -629,10 +637,12 @@ TEST(MultipleComponentView, Each) {
     std::size_t cnt = 0;
 
     view.each([&cnt](auto, int &, char &) { ++cnt; });
+    view.each([&cnt](int &, char &) { ++cnt; });
 
-    ASSERT_EQ(cnt, std::size_t{2});
+    ASSERT_EQ(cnt, std::size_t{4});
 
     cview.each([&cnt](auto, const int &, const char &) { --cnt; });
+    cview.each([&cnt](const int &, const char &) { --cnt; });
 
     ASSERT_EQ(cnt, std::size_t{0});
 }
@@ -714,146 +724,6 @@ TEST(MultipleComponentView, Find) {
     ASSERT_EQ(++view.find(e0), view.end());
 }
 
-TEST(RawView, Functionalities) {
-    entt::registry<> registry;
-    auto view = registry.raw_view<char>();
-    auto cview = std::as_const(registry).raw_view<const char>();
-
-    ASSERT_TRUE(view.empty());
-
-    const auto e0 = registry.create();
-    const auto e1 = registry.create();
-
-    registry.assign<int>(e1);
-    registry.assign<char>(e1);
-
-    ASSERT_FALSE(view.empty());
-    ASSERT_NO_THROW(view.begin()++);
-    ASSERT_NO_THROW(++cview.begin());
-
-    ASSERT_NE(view.begin(), view.end());
-    ASSERT_NE(cview.begin(), cview.end());
-    ASSERT_EQ(view.size(), typename decltype(view)::size_type{1});
-
-    registry.assign<char>(e0);
-
-    ASSERT_EQ(view.size(), typename decltype(view)::size_type{2});
-
-    registry.get<char>(e0) = '1';
-    registry.get<char>(e1) = '2';
-
-    for(auto &&component: view) {
-        ASSERT_TRUE(component == '1' || component == '2');
-    }
-
-    ASSERT_EQ(*(view.data() + 0), e1);
-    ASSERT_EQ(*(view.data() + 1), e0);
-
-    ASSERT_EQ(*(view.raw() + 0), '2');
-    ASSERT_EQ(*(cview.raw() + 1), '1');
-
-    for(auto &&component: view) {
-        // verifies that iterators return references to components
-        component = '0';
-    }
-
-    for(auto &&component: cview) {
-        ASSERT_TRUE(component == '0');
-    }
-
-    registry.remove<char>(e0);
-    registry.remove<char>(e1);
-
-    ASSERT_EQ(view.begin(), view.end());
-    ASSERT_TRUE(view.empty());
-}
-
-TEST(RawView, ElementAccess) {
-    entt::registry<> registry;
-    auto view = registry.raw_view<int>();
-    auto cview = std::as_const(registry).raw_view<const int>();
-
-    const auto e0 = registry.create();
-    registry.assign<int>(e0, 42);
-
-    const auto e1 = registry.create();
-    registry.assign<int>(e1, 3);
-
-    for(typename decltype(view)::size_type i{}; i < view.size(); ++i) {
-        ASSERT_EQ(view[i], i ? 42 : 3);
-        ASSERT_EQ(cview[i], i ? 42 : 3);
-    }
-}
-
-TEST(RawView, Empty) {
-    entt::registry<> registry;
-
-    const auto e0 = registry.create();
-    registry.assign<char>(e0);
-    registry.assign<double>(e0);
-
-    const auto e1 = registry.create();
-    registry.assign<char>(e1);
-
-    auto view = registry.raw_view<int>();
-
-    ASSERT_EQ(view.size(), entt::registry<>::size_type{0});
-
-    for(auto &&component: view) {
-        (void)component;
-        FAIL();
-    }
-}
-
-TEST(RawView, Each) {
-    entt::registry<> registry;
-
-    registry.assign<int>(registry.create(), 1);
-    registry.assign<int>(registry.create(), 3);
-
-    auto view = registry.raw_view<int>();
-    auto cview = std::as_const(registry).raw_view<const int>();
-    std::size_t cnt = 0;
-
-    view.each([&cnt](int &v) { cnt += (v % 2); });
-
-    ASSERT_EQ(cnt, std::size_t{2});
-
-    cview.each([&cnt](const int &v) { cnt -= (v % 2); });
-
-    ASSERT_EQ(cnt, std::size_t{0});
-}
-
-TEST(RawView, ConstNonConstAndAllInBetween) {
-    entt::registry<> registry;
-    auto view = registry.raw_view<int>();
-    auto cview = registry.raw_view<const int>();
-
-    ASSERT_TRUE((std::is_same_v<typename decltype(view)::raw_type, int>));
-    ASSERT_TRUE((std::is_same_v<typename decltype(cview)::raw_type, const int>));
-
-    ASSERT_TRUE((std::is_same_v<decltype(view[0]), int &>));
-    ASSERT_TRUE((std::is_same_v<decltype(view.raw()), int *>));
-    ASSERT_TRUE((std::is_same_v<decltype(cview[0]), const int &>));
-    ASSERT_TRUE((std::is_same_v<decltype(cview.raw()), const int *>));
-
-    view.each([](auto &&i) {
-        ASSERT_TRUE((std::is_same_v<decltype(i), int &>));
-    });
-
-    cview.each([](auto &&i) {
-        ASSERT_TRUE((std::is_same_v<decltype(i), const int &>));
-    });
-
-    for(auto &&i: view) {
-        ASSERT_TRUE((std::is_same_v<decltype(i), int &>));
-    }
-
-    for(auto &&i: cview) {
-        ASSERT_TRUE((std::is_same_v<decltype(i), const int &>));
-    }
-}
-
 TEST(RuntimeView, Functionalities) {
     entt::registry<> registry;
     using component_type = typename decltype(registry)::component_type;