Explorar o código

minor changes

Michele Caini %!s(int64=7) %!d(string=hai) anos
pai
achega
e3c858278b

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

@@ -22,6 +22,7 @@
 #include "entity.hpp"
 #include "fwd.hpp"
 #include "group.hpp"
+#include "runtime_view.hpp"
 #include "snapshot.hpp"
 #include "sparse_set.hpp"
 #include "view.hpp"

+ 275 - 0
src/entt/entity/runtime_view.hpp

@@ -0,0 +1,275 @@
+#ifndef ENTT_ENTITY_RUNTIME_VIEW_HPP
+#define ENTT_ENTITY_RUNTIME_VIEW_HPP
+
+
+#include <iterator>
+#include <cassert>
+#include <vector>
+#include <utility>
+#include <algorithm>
+#include "../config/config.h"
+#include "entt_traits.hpp"
+#include "sparse_set.hpp"
+#include "fwd.hpp"
+
+
+namespace entt {
+
+
+/**
+ * @brief Runtime view.
+ *
+ * Runtime views iterate over those entities that have at least all the given
+ * components in their bags. During initialization, a runtime view looks at the
+ * number of entities available for each component and picks up a reference to
+ * the smallest set of candidate entities in order to get a performance boost
+ * when iterate.<br/>
+ * Order of elements during iterations are highly dependent on the order of the
+ * underlying data structures. See sparse_set and its specializations for more
+ * details.
+ *
+ * @b Important
+ *
+ * Iterators aren't invalidated if:
+ *
+ * * New instances of the given components are created and assigned to entities.
+ * * The entity currently pointed is modified (as an example, if one of the
+ *   given components is removed from the entity to which the iterator points).
+ *
+ * In all the other cases, modifying the pools of the given components in any
+ * way invalidates all the iterators and using them results in undefined
+ * behavior.
+ *
+ * @note
+ * Views share references to the underlying data structures of 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 the views, unless
+ * a pool was missing when the view was built (in this case, the view won't
+ * have a valid reference and won't be updated accordingly).
+ *
+ * @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.
+ *
+ * @tparam Entity A valid entity type (see entt_traits for more details).
+ */
+template<typename Entity>
+class basic_runtime_view {
+    /*! @brief A registry is allowed to create views. */
+    friend class basic_registry<Entity>;
+
+    using underlying_iterator_type = typename sparse_set<Entity>::iterator_type;
+    using extent_type = typename sparse_set<Entity>::size_type;
+    using traits_type = entt_traits<Entity>;
+
+    class iterator {
+        friend class basic_runtime_view<Entity>;
+
+        iterator(underlying_iterator_type first, underlying_iterator_type last, const sparse_set<Entity> * const *others, const sparse_set<Entity> * const *length, extent_type ext) ENTT_NOEXCEPT
+            : begin{first},
+              end{last},
+              from{others},
+              to{length},
+              extent{ext}
+        {
+            if(begin != end && !valid()) {
+                ++(*this);
+            }
+        }
+
+        bool valid() const ENTT_NOEXCEPT {
+            const auto entt = *begin;
+            const auto sz = size_type(entt & traits_type::entity_mask);
+
+            return sz < extent && std::all_of(from, to, [entt](const auto *view) {
+                return view->fast(entt);
+            });
+        }
+
+    public:
+        using difference_type = typename underlying_iterator_type::difference_type;
+        using value_type = typename underlying_iterator_type::value_type;
+        using pointer = typename underlying_iterator_type::pointer;
+        using reference = typename underlying_iterator_type::reference;
+        using iterator_category = std::forward_iterator_tag;
+
+        iterator() ENTT_NOEXCEPT = default;
+
+        iterator & operator++() ENTT_NOEXCEPT {
+            return (++begin != end && !valid()) ? ++(*this) : *this;
+        }
+
+        iterator operator++(int) ENTT_NOEXCEPT {
+            iterator orig = *this;
+            return ++(*this), orig;
+        }
+
+        bool operator==(const iterator &other) const ENTT_NOEXCEPT {
+            return other.begin == begin;
+        }
+
+        inline bool operator!=(const iterator &other) const ENTT_NOEXCEPT {
+            return !(*this == other);
+        }
+
+        pointer operator->() const ENTT_NOEXCEPT {
+            return begin.operator->();
+        }
+
+        inline reference operator*() const ENTT_NOEXCEPT {
+            return *operator->();
+        }
+
+    private:
+        underlying_iterator_type begin;
+        underlying_iterator_type end;
+        const sparse_set<Entity> * const *from;
+        const sparse_set<Entity> * const *to;
+        extent_type extent;
+    };
+
+    basic_runtime_view(std::vector<const sparse_set<Entity> *> others) ENTT_NOEXCEPT
+        : pools{std::move(others)}
+    {
+        const auto it = std::min_element(pools.begin(), pools.end(), [](const auto *lhs, const auto *rhs) {
+            return (!lhs && rhs) || (lhs && rhs && lhs->size() < rhs->size());
+        });
+
+        // brings the best candidate (if any) on front of the vector
+        std::rotate(pools.begin(), it, pools.end());
+    }
+
+    extent_type min() const ENTT_NOEXCEPT {
+        extent_type extent{};
+
+        if(valid()) {
+            const auto it = std::min_element(pools.cbegin(), pools.cend(), [](const auto *lhs, const auto *rhs) {
+                return lhs->extent() < rhs->extent();
+            });
+
+            extent = (*it)->extent();
+        }
+
+        return extent;
+    }
+
+    inline bool valid() const ENTT_NOEXCEPT {
+        return !pools.empty() && pools.front();
+    }
+
+public:
+    /*! @brief Underlying entity identifier. */
+    using entity_type = typename sparse_set<Entity>::entity_type;
+    /*! @brief Unsigned integer type. */
+    using size_type = typename sparse_set<Entity>::size_type;
+    /*! @brief Input iterator type. */
+    using iterator_type = iterator;
+
+    /**
+     * @brief Estimates the number of entities that have the given components.
+     * @return Estimated number of entities that have the given components.
+     */
+    size_type size() const ENTT_NOEXCEPT {
+        return valid() ? pools.front()->size() : size_type{};
+    }
+
+    /**
+     * @brief Checks if the view is definitely empty.
+     * @return True if the view is definitely empty, false otherwise.
+     */
+    bool empty() const ENTT_NOEXCEPT {
+        return !valid() || pools.front()->empty();
+    }
+
+    /**
+     * @brief Returns an iterator to the first entity that has the given
+     * components.
+     *
+     * The returned iterator points to the first entity that has the given
+     * components. 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 entity that has the given components.
+     */
+    iterator_type begin() const ENTT_NOEXCEPT {
+        iterator_type it{};
+
+        if(valid()) {
+            const auto &pool = *pools.front();
+            const auto * const *data = pools.data();
+            it = { pool.begin(), pool.end(), data + 1, data + pools.size(), min() };
+        }
+
+        return it;
+    }
+
+    /**
+     * @brief Returns an iterator that is past the last entity that has the
+     * given components.
+     *
+     * The returned iterator points to the entity following the last entity that
+     * has the given components. 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 entity following the last entity that has the
+     * given components.
+     */
+    iterator_type end() const ENTT_NOEXCEPT {
+        iterator_type it{};
+
+        if(valid()) {
+            const auto &pool = *pools.front();
+            it = { pool.end(), pool.end(), nullptr, nullptr, min() };
+        }
+
+        return it;
+    }
+
+    /**
+     * @brief Checks if a view contains an entity.
+     * @param entt A valid entity identifier.
+     * @return True if the view contains the given entity, false otherwise.
+     */
+    bool contains(const entity_type entt) const ENTT_NOEXCEPT {
+        return valid() && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *view) {
+            return view->has(entt) && view->data()[view->get(entt)] == entt;
+        });
+    }
+
+    /**
+     * @brief Iterates entities and applies the given function object to them.
+     *
+     * The function object is invoked for each entity. It is provided only with
+     * the entity itself. To get the components, users can use the registry with
+     * which the view was built.<br/>
+     * The signature of the function should be equivalent to the following:
+     *
+     * @code{.cpp}
+     * void(const entity_type);
+     * @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(begin(), end(), func);
+    }
+
+private:
+    std::vector<const sparse_set<Entity> *> pools;
+};
+
+
+}
+
+
+#endif // ENTT_ENTITY_RUNTIME_VIEW_HPP

+ 0 - 254
src/entt/entity/view.hpp

@@ -6,7 +6,6 @@
 #include <cassert>
 #include <array>
 #include <tuple>
-#include <vector>
 #include <utility>
 #include <algorithm>
 #include <type_traits>
@@ -670,259 +669,6 @@ private:
 };
 
 
-/**
- * @brief Runtime view.
- *
- * Runtime views iterate over those entities that have at least all the given
- * components in their bags. During initialization, a runtime view looks at the
- * number of entities available for each component and picks up a reference to
- * the smallest set of candidate entities in order to get a performance boost
- * when iterate.<br/>
- * Order of elements during iterations are highly dependent on the order of the
- * underlying data structures. See sparse_set and its specializations for more
- * details.
- *
- * @b Important
- *
- * Iterators aren't invalidated if:
- *
- * * New instances of the given components are created and assigned to entities.
- * * The entity currently pointed is modified (as an example, if one of the
- *   given components is removed from the entity to which the iterator points).
- *
- * In all the other cases, modifying the pools of the given components in any
- * way invalidates all the iterators and using them results in undefined
- * behavior.
- *
- * @note
- * Views share references to the underlying data structures of 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 the views, unless
- * a pool was missing when the view was built (in this case, the view won't
- * have a valid reference and won't be updated accordingly).
- *
- * @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.
- *
- * @tparam Entity A valid entity type (see entt_traits for more details).
- */
-template<typename Entity>
-class basic_runtime_view {
-    /*! @brief A registry is allowed to create views. */
-    friend class basic_registry<Entity>;
-
-    using underlying_iterator_type = typename sparse_set<Entity>::iterator_type;
-    using extent_type = typename sparse_set<Entity>::size_type;
-    using traits_type = entt_traits<Entity>;
-
-    class iterator {
-        friend class basic_runtime_view<Entity>;
-
-        iterator(underlying_iterator_type first, underlying_iterator_type last, const sparse_set<Entity> * const *others, const sparse_set<Entity> * const *length, extent_type ext) ENTT_NOEXCEPT
-            : begin{first},
-              end{last},
-              from{others},
-              to{length},
-              extent{ext}
-        {
-            if(begin != end && !valid()) {
-                ++(*this);
-            }
-        }
-
-        bool valid() const ENTT_NOEXCEPT {
-            const auto entt = *begin;
-            const auto sz = size_type(entt & traits_type::entity_mask);
-
-            return sz < extent && std::all_of(from, to, [entt](const auto *view) {
-                return view->fast(entt);
-            });
-        }
-
-    public:
-        using difference_type = typename underlying_iterator_type::difference_type;
-        using value_type = typename underlying_iterator_type::value_type;
-        using pointer = typename underlying_iterator_type::pointer;
-        using reference = typename underlying_iterator_type::reference;
-        using iterator_category = std::forward_iterator_tag;
-
-        iterator() ENTT_NOEXCEPT = default;
-
-        iterator & operator++() ENTT_NOEXCEPT {
-            return (++begin != end && !valid()) ? ++(*this) : *this;
-        }
-
-        iterator operator++(int) ENTT_NOEXCEPT {
-            iterator orig = *this;
-            return ++(*this), orig;
-        }
-
-        bool operator==(const iterator &other) const ENTT_NOEXCEPT {
-            return other.begin == begin;
-        }
-
-        inline bool operator!=(const iterator &other) const ENTT_NOEXCEPT {
-            return !(*this == other);
-        }
-
-        pointer operator->() const ENTT_NOEXCEPT {
-            return begin.operator->();
-        }
-
-        inline reference operator*() const ENTT_NOEXCEPT {
-            return *operator->();
-        }
-
-    private:
-        underlying_iterator_type begin;
-        underlying_iterator_type end;
-        const sparse_set<Entity> * const *from;
-        const sparse_set<Entity> * const *to;
-        extent_type extent;
-    };
-
-    basic_runtime_view(std::vector<const sparse_set<Entity> *> others) ENTT_NOEXCEPT
-        : pools{std::move(others)}
-    {
-        const auto it = std::min_element(pools.begin(), pools.end(), [](const auto *lhs, const auto *rhs) {
-            return (!lhs && rhs) || (lhs && rhs && lhs->size() < rhs->size());
-        });
-
-        // brings the best candidate (if any) on front of the vector
-        std::rotate(pools.begin(), it, pools.end());
-    }
-
-    extent_type min() const ENTT_NOEXCEPT {
-        extent_type extent{};
-
-        if(valid()) {
-            const auto it = std::min_element(pools.cbegin(), pools.cend(), [](const auto *lhs, const auto *rhs) {
-                return lhs->extent() < rhs->extent();
-            });
-
-            extent = (*it)->extent();
-        }
-
-        return extent;
-    }
-
-    inline bool valid() const ENTT_NOEXCEPT {
-        return !pools.empty() && pools.front();
-    }
-
-public:
-    /*! @brief Underlying entity identifier. */
-    using entity_type = typename sparse_set<Entity>::entity_type;
-    /*! @brief Unsigned integer type. */
-    using size_type = typename sparse_set<Entity>::size_type;
-    /*! @brief Input iterator type. */
-    using iterator_type = iterator;
-
-    /**
-     * @brief Estimates the number of entities that have the given components.
-     * @return Estimated number of entities that have the given components.
-     */
-    size_type size() const ENTT_NOEXCEPT {
-        return valid() ? pools.front()->size() : size_type{};
-    }
-
-    /**
-     * @brief Checks if the view is definitely empty.
-     * @return True if the view is definitely empty, false otherwise.
-     */
-    bool empty() const ENTT_NOEXCEPT {
-        return !valid() || pools.front()->empty();
-    }
-
-    /**
-     * @brief Returns an iterator to the first entity that has the given
-     * components.
-     *
-     * The returned iterator points to the first entity that has the given
-     * components. 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 entity that has the given components.
-     */
-    iterator_type begin() const ENTT_NOEXCEPT {
-        iterator_type it{};
-
-        if(valid()) {
-            const auto &pool = *pools.front();
-            const auto * const *data = pools.data();
-            it = { pool.begin(), pool.end(), data + 1, data + pools.size(), min() };
-        }
-
-        return it;
-    }
-
-    /**
-     * @brief Returns an iterator that is past the last entity that has the
-     * given components.
-     *
-     * The returned iterator points to the entity following the last entity that
-     * has the given components. 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 entity following the last entity that has the
-     * given components.
-     */
-    iterator_type end() const ENTT_NOEXCEPT {
-        iterator_type it{};
-
-        if(valid()) {
-            const auto &pool = *pools.front();
-            it = { pool.end(), pool.end(), nullptr, nullptr, min() };
-        }
-
-        return it;
-    }
-
-    /**
-     * @brief Checks if a view contains an entity.
-     * @param entt A valid entity identifier.
-     * @return True if the view contains the given entity, false otherwise.
-     */
-    bool contains(const entity_type entt) const ENTT_NOEXCEPT {
-        return valid() && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *view) {
-            return view->has(entt) && view->data()[view->get(entt)] == entt;
-        });
-    }
-
-    /**
-     * @brief Iterates entities and applies the given function object to them.
-     *
-     * The function object is invoked for each entity. It is provided only with
-     * the entity itself. To get the components, users can use the registry with
-     * which the view was built.<br/>
-     * The signature of the function should be equivalent to the following:
-     *
-     * @code{.cpp}
-     * void(const entity_type);
-     * @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(begin(), end(), func);
-    }
-
-private:
-    std::vector<const sparse_set<Entity> *> pools;
-};
-
-
 }
 
 

+ 1 - 0
src/entt/entt.hpp

@@ -12,6 +12,7 @@
 #include "entity/helper.hpp"
 #include "entity/prototype.hpp"
 #include "entity/registry.hpp"
+#include "entity/runtime_view.hpp"
 #include "entity/snapshot.hpp"
 #include "entity/sparse_set.hpp"
 #include "entity/view.hpp"

+ 1 - 0
test/CMakeLists.txt

@@ -98,6 +98,7 @@ SETUP_AND_ADD_TEST(group entt/entity/group.cpp)
 SETUP_AND_ADD_TEST(helper entt/entity/helper.cpp)
 SETUP_AND_ADD_TEST(prototype entt/entity/prototype.cpp)
 SETUP_AND_ADD_TEST(registry entt/entity/registry.cpp)
+SETUP_AND_ADD_TEST(runtime_view entt/entity/runtime_view.cpp)
 SETUP_AND_ADD_TEST(snapshot entt/entity/snapshot.cpp)
 SETUP_AND_ADD_TEST(sparse_set entt/entity/sparse_set.cpp)
 SETUP_AND_ADD_TEST(view entt/entity/view.cpp)

+ 208 - 0
test/entt/entity/runtime_view.cpp

@@ -0,0 +1,208 @@
+#include <iterator>
+#include <gtest/gtest.h>
+#include <entt/entity/registry.hpp>
+#include <entt/entity/runtime_view.hpp>
+
+TEST(RuntimeView, Functionalities) {
+    entt::registry registry;
+    using component_type = typename decltype(registry)::component_type;
+
+    // forces the creation of the pools
+    registry.reserve<int>(0);
+    registry.reserve<char>(0);
+
+    component_type types[] = { registry.type<int>(), registry.type<char>() };
+    auto view = registry.runtime_view(std::begin(types), std::end(types));
+
+    ASSERT_TRUE(view.empty());
+
+    const auto e0 = registry.create();
+    registry.assign<char>(e0);
+
+    const auto e1 = registry.create();
+    registry.assign<int>(e1);
+
+    ASSERT_FALSE(view.empty());
+
+    registry.assign<char>(e1);
+
+    auto it = registry.runtime_view(std::begin(types), std::end(types)).begin();
+
+    ASSERT_EQ(*it, e1);
+    ASSERT_EQ(++it, (registry.runtime_view(std::begin(types), std::end(types)).end()));
+
+    ASSERT_NO_THROW((registry.runtime_view(std::begin(types), std::end(types)).begin()++));
+    ASSERT_NO_THROW((++registry.runtime_view(std::begin(types), std::end(types)).begin()));
+
+    ASSERT_NE(view.begin(), view.end());
+    ASSERT_EQ(view.size(), decltype(view.size()){1});
+
+    registry.get<char>(e0) = '1';
+    registry.get<char>(e1) = '2';
+    registry.get<int>(e1) = 42;
+
+    for(auto entity: view) {
+        ASSERT_EQ(registry.get<int>(entity), 42);
+        ASSERT_EQ(registry.get<char>(entity), '2');
+    }
+}
+
+TEST(RuntimeView, Iterator) {
+    entt::registry registry;
+    using component_type = typename decltype(registry)::component_type;
+
+    const auto entity = registry.create();
+    registry.assign<int>(entity);
+    registry.assign<char>(entity);
+
+    component_type types[] = { registry.type<int>(), registry.type<char>() };
+    auto view = registry.runtime_view(std::begin(types), std::end(types));
+    using iterator_type = typename decltype(view)::iterator_type;
+
+    iterator_type end{view.begin()};
+    iterator_type begin{};
+    begin = view.end();
+    std::swap(begin, end);
+
+    ASSERT_EQ(begin, view.begin());
+    ASSERT_EQ(end, view.end());
+    ASSERT_NE(begin, end);
+
+    ASSERT_EQ(view.begin()++, view.begin());
+    ASSERT_EQ(++view.begin(), view.end());
+}
+
+TEST(RuntimeView, Contains) {
+    entt::registry registry;
+    using component_type = typename decltype(registry)::component_type;
+
+    const auto e0 = registry.create();
+    registry.assign<int>(e0);
+    registry.assign<char>(e0);
+
+    const auto e1 = registry.create();
+    registry.assign<int>(e1);
+    registry.assign<char>(e1);
+
+    registry.destroy(e0);
+
+    component_type types[] = { registry.type<int>(), registry.type<char>() };
+    auto view = registry.runtime_view(std::begin(types), std::end(types));
+
+    ASSERT_FALSE(view.contains(e0));
+    ASSERT_TRUE(view.contains(e1));
+}
+
+TEST(RuntimeView, Empty) {
+    entt::registry registry;
+    using component_type = typename decltype(registry)::component_type;
+
+    const auto e0 = registry.create();
+    registry.assign<double>(e0);
+    registry.assign<int>(e0);
+    registry.assign<float>(e0);
+
+    const auto e1 = registry.create();
+    registry.assign<char>(e1);
+    registry.assign<float>(e1);
+
+    component_type types[] = { registry.type<char>(), registry.type<int>(), registry.type<float>() };
+    auto view = registry.runtime_view(std::begin(types), std::end(types));
+
+    for(auto entity: view) {
+        (void)entity;
+        FAIL();
+    }
+}
+
+TEST(RuntimeView, Each) {
+    entt::registry registry;
+    using component_type = typename decltype(registry)::component_type;
+
+    const auto e0 = registry.create();
+    registry.assign<int>(e0);
+    registry.assign<char>(e0);
+
+    const auto e1 = registry.create();
+    registry.assign<int>(e1);
+    registry.assign<char>(e1);
+
+    component_type types[] = { registry.type<int>(), registry.type<char>() };
+    auto view = registry.runtime_view(std::begin(types), std::end(types));
+    std::size_t cnt = 0;
+
+    view.each([&cnt](auto) { ++cnt; });
+
+    ASSERT_EQ(cnt, std::size_t{2});
+}
+
+TEST(RuntimeView, EachWithHoles) {
+    entt::registry registry;
+    using component_type = typename decltype(registry)::component_type;
+
+    const auto e0 = registry.create();
+    const auto e1 = registry.create();
+    const auto e2 = registry.create();
+
+    registry.assign<char>(e0, '0');
+    registry.assign<char>(e1, '1');
+
+    registry.assign<int>(e0, 0);
+    registry.assign<int>(e2, 2);
+
+    component_type types[] = { registry.type<int>(), registry.type<char>() };
+    auto view = registry.runtime_view(std::begin(types), std::end(types));
+
+    view.each([e0](auto entity) {
+        ASSERT_EQ(e0, entity);
+    });
+}
+
+TEST(RuntimeView, MissingPool) {
+    entt::registry registry;
+    using component_type = typename decltype(registry)::component_type;
+
+    const auto e0 = registry.create();
+    registry.assign<int>(e0);
+
+    component_type types[] = { registry.type<int>(), registry.type<char>() };
+    auto view = registry.runtime_view(std::begin(types), std::end(types));
+
+    ASSERT_TRUE(view.empty());
+    ASSERT_EQ(view.size(), decltype(view.size()){0});
+
+    registry.assign<char>(e0);
+
+    ASSERT_TRUE(view.empty());
+    ASSERT_EQ(view.size(), decltype(view.size()){0});
+    ASSERT_FALSE(view.contains(e0));
+
+    view.each([](auto) { FAIL(); });
+
+    for(auto entity: view) {
+        (void)entity;
+        FAIL();
+    }
+}
+
+TEST(RuntimeView, EmptyRange) {
+    entt::registry registry;
+    using component_type = typename decltype(registry)::component_type;
+
+    const auto e0 = registry.create();
+    registry.assign<int>(e0);
+
+    const component_type *ptr = nullptr;
+    auto view = registry.runtime_view(ptr, ptr);
+
+    ASSERT_TRUE(view.empty());
+    ASSERT_EQ(view.size(), decltype(view.size()){0});
+    ASSERT_FALSE(view.contains(e0));
+
+    view.each([](auto) { FAIL(); });
+
+    for(auto entity: view) {
+        (void)entity;
+        FAIL();
+    }
+}

+ 1 - 206
test/entt/entity/view.cpp

@@ -1,6 +1,5 @@
 #include <utility>
-#include <iterator>
-#include <algorithm>
+#include <type_traits>
 #include <gtest/gtest.h>
 #include <entt/entity/registry.hpp>
 #include <entt/entity/view.hpp>
@@ -456,207 +455,3 @@ TEST(MultipleComponentView, Find) {
     ASSERT_NE(view.find(e5), view.end());
     ASSERT_EQ(view.find(e4), view.end());
 }
-
-TEST(RuntimeView, Functionalities) {
-    entt::registry registry;
-    using component_type = typename decltype(registry)::component_type;
-
-    // forces the creation of the pools
-    registry.reserve<int>(0);
-    registry.reserve<char>(0);
-
-    component_type types[] = { registry.type<int>(), registry.type<char>() };
-    auto view = registry.runtime_view(std::begin(types), std::end(types));
-
-    ASSERT_TRUE(view.empty());
-
-    const auto e0 = registry.create();
-    registry.assign<char>(e0);
-
-    const auto e1 = registry.create();
-    registry.assign<int>(e1);
-
-    ASSERT_FALSE(view.empty());
-
-    registry.assign<char>(e1);
-
-    auto it = registry.runtime_view(std::begin(types), std::end(types)).begin();
-
-    ASSERT_EQ(*it, e1);
-    ASSERT_EQ(++it, (registry.runtime_view(std::begin(types), std::end(types)).end()));
-
-    ASSERT_NO_THROW((registry.runtime_view(std::begin(types), std::end(types)).begin()++));
-    ASSERT_NO_THROW((++registry.runtime_view(std::begin(types), std::end(types)).begin()));
-
-    ASSERT_NE(view.begin(), view.end());
-    ASSERT_EQ(view.size(), decltype(view.size()){1});
-
-    registry.get<char>(e0) = '1';
-    registry.get<char>(e1) = '2';
-    registry.get<int>(e1) = 42;
-
-    for(auto entity: view) {
-        ASSERT_EQ(registry.get<int>(entity), 42);
-        ASSERT_EQ(registry.get<char>(entity), '2');
-    }
-}
-
-TEST(RuntimeView, Iterator) {
-    entt::registry registry;
-    using component_type = typename decltype(registry)::component_type;
-
-    const auto entity = registry.create();
-    registry.assign<int>(entity);
-    registry.assign<char>(entity);
-
-    component_type types[] = { registry.type<int>(), registry.type<char>() };
-    auto view = registry.runtime_view(std::begin(types), std::end(types));
-    using iterator_type = typename decltype(view)::iterator_type;
-
-    iterator_type end{view.begin()};
-    iterator_type begin{};
-    begin = view.end();
-    std::swap(begin, end);
-
-    ASSERT_EQ(begin, view.begin());
-    ASSERT_EQ(end, view.end());
-    ASSERT_NE(begin, end);
-
-    ASSERT_EQ(view.begin()++, view.begin());
-    ASSERT_EQ(++view.begin(), view.end());
-}
-
-TEST(RuntimeView, Contains) {
-    entt::registry registry;
-    using component_type = typename decltype(registry)::component_type;
-
-    const auto e0 = registry.create();
-    registry.assign<int>(e0);
-    registry.assign<char>(e0);
-
-    const auto e1 = registry.create();
-    registry.assign<int>(e1);
-    registry.assign<char>(e1);
-
-    registry.destroy(e0);
-
-    component_type types[] = { registry.type<int>(), registry.type<char>() };
-    auto view = registry.runtime_view(std::begin(types), std::end(types));
-
-    ASSERT_FALSE(view.contains(e0));
-    ASSERT_TRUE(view.contains(e1));
-}
-
-TEST(RuntimeView, Empty) {
-    entt::registry registry;
-    using component_type = typename decltype(registry)::component_type;
-
-    const auto e0 = registry.create();
-    registry.assign<double>(e0);
-    registry.assign<int>(e0);
-    registry.assign<float>(e0);
-
-    const auto e1 = registry.create();
-    registry.assign<char>(e1);
-    registry.assign<float>(e1);
-
-    component_type types[] = { registry.type<char>(), registry.type<int>(), registry.type<float>() };
-    auto view = registry.runtime_view(std::begin(types), std::end(types));
-
-    for(auto entity: view) {
-        (void)entity;
-        FAIL();
-    }
-}
-
-TEST(RuntimeView, Each) {
-    entt::registry registry;
-    using component_type = typename decltype(registry)::component_type;
-
-    const auto e0 = registry.create();
-    registry.assign<int>(e0);
-    registry.assign<char>(e0);
-
-    const auto e1 = registry.create();
-    registry.assign<int>(e1);
-    registry.assign<char>(e1);
-
-    component_type types[] = { registry.type<int>(), registry.type<char>() };
-    auto view = registry.runtime_view(std::begin(types), std::end(types));
-    std::size_t cnt = 0;
-
-    view.each([&cnt](auto) { ++cnt; });
-
-    ASSERT_EQ(cnt, std::size_t{2});
-}
-
-TEST(RuntimeView, EachWithHoles) {
-    entt::registry registry;
-    using component_type = typename decltype(registry)::component_type;
-
-    const auto e0 = registry.create();
-    const auto e1 = registry.create();
-    const auto e2 = registry.create();
-
-    registry.assign<char>(e0, '0');
-    registry.assign<char>(e1, '1');
-
-    registry.assign<int>(e0, 0);
-    registry.assign<int>(e2, 2);
-
-    component_type types[] = { registry.type<int>(), registry.type<char>() };
-    auto view = registry.runtime_view(std::begin(types), std::end(types));
-
-    view.each([e0](auto entity) {
-        ASSERT_EQ(e0, entity);
-    });
-}
-
-TEST(RuntimeView, MissingPool) {
-    entt::registry registry;
-    using component_type = typename decltype(registry)::component_type;
-
-    const auto e0 = registry.create();
-    registry.assign<int>(e0);
-
-    component_type types[] = { registry.type<int>(), registry.type<char>() };
-    auto view = registry.runtime_view(std::begin(types), std::end(types));
-
-    ASSERT_TRUE(view.empty());
-    ASSERT_EQ(view.size(), decltype(view.size()){0});
-
-    registry.assign<char>(e0);
-
-    ASSERT_TRUE(view.empty());
-    ASSERT_EQ(view.size(), decltype(view.size()){0});
-    ASSERT_FALSE(view.contains(e0));
-
-    view.each([](auto) { FAIL(); });
-
-    for(auto entity: view) {
-        (void)entity;
-        FAIL();
-    }
-}
-
-TEST(RuntimeView, EmptyRange) {
-    entt::registry registry;
-    using component_type = typename decltype(registry)::component_type;
-
-    const auto e0 = registry.create();
-    registry.assign<int>(e0);
-
-    const component_type *ptr = nullptr;
-    auto view = registry.runtime_view(ptr, ptr);
-
-    ASSERT_TRUE(view.empty());
-    ASSERT_EQ(view.size(), decltype(view.size()){0});
-    ASSERT_FALSE(view.contains(e0));
-
-    view.each([](auto) { FAIL(); });
-
-    for(auto entity: view) {
-        (void)entity;
-        FAIL();
-    }
-}