浏览代码

sparse_set/storage: virtual sort

Michele Caini 5 年之前
父节点
当前提交
7b501aa89b

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

@@ -503,13 +503,13 @@ public:
     void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
         if constexpr(sizeof...(Component) == 0) {
             static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
-            handler->sort(handler->begin(), handler->end(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
+            handler->sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
         }  else if constexpr(sizeof...(Component) == 1) {
-            handler->sort(handler->begin(), handler->end(), [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
+            handler->sort([this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
                 return compare((std::get<pool_type<Component> *>(pools)->get(lhs), ...), (std::get<pool_type<Component> *>(pools)->get(rhs), ...));
             }, std::move(algo), std::forward<Args>(args)...);
         } else {
-            handler->sort(handler->begin(), handler->end(), [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
+            handler->sort([this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
                 return compare(std::tuple<decltype(get<Component>({}))...>{std::get<pool_type<Component> *>(pools)->get(lhs)...}, std::tuple<decltype(get<Component>({}))...>{std::get<pool_type<Component> *>(pools)->get(rhs)...});
             }, std::move(algo), std::forward<Args>(args)...);
         }
@@ -1059,13 +1059,13 @@ public:
 
         if constexpr(sizeof...(Component) == 0) {
             static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
-            cpool->sort(cpool->end()-*length, cpool->end(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
+            cpool->sort_n(*length, std::move(compare), std::move(algo), std::forward<Args>(args)...);
         } else if constexpr(sizeof...(Component) == 1) {
-            cpool->sort(cpool->end()-*length, cpool->end(), [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
+            cpool->sort_n(*length, [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
                 return compare((std::get<pool_type<Component> *>(pools)->get(lhs), ...), (std::get<pool_type<Component> *>(pools)->get(rhs), ...));
             }, std::move(algo), std::forward<Args>(args)...);
         } else {
-            cpool->sort(cpool->end()-*length, cpool->end(), [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
+            cpool->sort_n(*length, [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
                 return compare(std::tuple<decltype(get<Component>({}))...>{std::get<pool_type<Component> *>(pools)->get(lhs)...}, std::tuple<decltype(get<Component>({}))...>{std::get<pool_type<Component> *>(pools)->get(rhs)...});
             }, std::move(algo), std::forward<Args>(args)...);
         }

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

@@ -1380,8 +1380,7 @@ public:
     template<typename Component, typename Compare, typename Sort = std_sort, typename... Args>
     void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
         ENTT_ASSERT(sortable<Component>());
-        auto &cpool = assure<Component>();
-        cpool.sort(cpool.begin(), cpool.end(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
+        assure<Component>().sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
     }
 
     /**

+ 25 - 60
src/entt/entity/sparse_set.hpp

@@ -149,6 +149,8 @@ class basic_sparse_set {
         index_type index;
     };
 
+    virtual void swap(const std::size_t, const std::size_t) {}
+
     [[nodiscard]] auto page(const Entity entt) const ENTT_NOEXCEPT {
         return size_type{(to_integral(entt) & traits_type::entity_mask) / entt_per_page};
     }
@@ -466,11 +468,8 @@ public:
     }
 
     /**
-     * @brief Sort elements according to the given comparison function.
-     *
-     * Sort the elements so that iterating the range with a couple of iterators
-     * returns them in the expected order. See `begin` and `end` for more
-     * details.
+     * @brief Sort the first count elements according to the given comparison
+     * function.
      *
      * The comparison function object must return `true` if the first element
      * is _less_ than the second one, `false` otherwise. The signature of the
@@ -483,7 +482,7 @@ public:
      * Moreover, the comparison function object shall induce a
      * _strict weak ordering_ on the values.
      *
-     * The sort function oject must offer a member function template
+     * The sort function object must offer a member function template
      * `operator()` that accepts three arguments:
      *
      * * An iterator to the first element of the range to sort.
@@ -493,80 +492,46 @@ public:
      * @tparam Compare Type of comparison function object.
      * @tparam Sort Type of sort function object.
      * @tparam Args Types of arguments to forward to the sort function object.
-     * @param first An iterator to the first element of the range to sort.
-     * @param last An iterator past the last element of the range to sort.
+     * @param count Number of elements to sort.
      * @param compare A valid comparison function object.
      * @param algo A valid sort function object.
      * @param args Arguments to forward to the sort function object, if any.
      */
     template<typename Compare, typename Sort = std_sort, typename... Args>
-    void sort(iterator first, iterator last, Compare compare, Sort algo = Sort{}, Args &&... args) {
-        ENTT_ASSERT(!(last < first));
-        ENTT_ASSERT(!(last > end()));
+    void sort_n(const size_type count, Compare compare, Sort algo = Sort{}, Args &&... args) {
+        ENTT_ASSERT(!(count > size()));
 
-        const auto length = std::distance(first, last);
-        const auto skip = std::distance(last, end());
-        const auto to = packed.rend() - skip;
-        const auto from = to - length;
+        algo(packed.rend() - count, packed.rend(), std::move(compare), std::forward<Args>(args)...);
+
+        for(size_type pos{}; pos < count; ++pos) {
+            auto curr = pos;
+            auto next = index(packed[curr]);
 
-        algo(from, to, std::move(compare), std::forward<Args>(args)...);
+            while(curr != next) {
+                swap(next, index(packed[next]));
+                sparse[page(packed[curr])][offset(packed[curr])] = entity_type{static_cast<typename traits_type::entity_type>(curr)};
 
-        for(size_type pos = skip, end = skip+length; pos < end; ++pos) {
-            sparse[page(packed[pos])][offset(packed[pos])] = entity_type{static_cast<typename traits_type::entity_type>(pos)};
+                curr = next;
+                next = index(packed[curr]);
+            }
         }
     }
 
     /**
-     * @brief Sort elements according to the given comparison function.
-     *
-     * @sa sort
-     *
-     * This function is a slightly slower version of `sort` that invokes the
-     * caller to indicate which entities are swapped.<br/>
-     * It's recommended when the caller wants to sort its own data structures to
-     * align them with the order induced in the sparse set.
+     * @brief Sort all elements according to the given comparison function.
+     * 
+     * @sa sort_n
      *
-     * The signature of the callback should be equivalent to the following:
-     *
-     * @code{.cpp}
-     * bool(const Entity, const Entity);
-     * @endcode
-     *
-     * @tparam Apply Type of function object to invoke to notify the caller.
      * @tparam Compare Type of comparison function object.
      * @tparam Sort Type of sort function object.
      * @tparam Args Types of arguments to forward to the sort function object.
-     * @param first An iterator to the first element of the range to sort.
-     * @param last An iterator past the last element of the range to sort.
-     * @param apply A valid function object to use as a callback.
      * @param compare A valid comparison function object.
      * @param algo A valid sort function object.
      * @param args Arguments to forward to the sort function object, if any.
      */
-    template<typename Apply, typename Compare, typename Sort = std_sort, typename... Args>
-    void arrange(iterator first, iterator last, Apply apply, Compare compare, Sort algo = Sort{}, Args &&... args) {
-        ENTT_ASSERT(!(last < first));
-        ENTT_ASSERT(!(last > end()));
-
-        const auto length = std::distance(first, last);
-        const auto skip = std::distance(last, end());
-        const auto to = packed.rend() - skip;
-        const auto from = to - length;
-
-        algo(from, to, std::move(compare), std::forward<Args>(args)...);
-
-        for(size_type pos = skip, end = skip+length; pos < end; ++pos) {
-            auto curr = pos;
-            auto next = index(packed[curr]);
-
-            while(curr != next) {
-                apply(packed[curr], packed[next]);
-                sparse[page(packed[curr])][offset(packed[curr])] = entity_type{static_cast<typename traits_type::entity_type>(curr)};
-
-                curr = next;
-                next = index(packed[curr]);
-            }
-        }
+    template<typename Compare, typename Sort = std_sort, typename... Args>
+    void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
+        sort_n(size(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
     }
 
     /**

+ 26 - 20
src/entt/entity/storage.hpp

@@ -156,6 +156,10 @@ class basic_storage: public basic_sparse_set<Entity> {
         index_type index;
     };
 
+    void swap(const std::size_t lhs, const std::size_t rhs) final {
+        std::swap(instances[lhs], instances[rhs]);
+    }
+
 public:
     /*! @brief Type of the objects associated with the entities. */
     using value_type = Type;
@@ -447,17 +451,13 @@ public:
      * @param rhs A valid entity identifier.
      */
     void swap(const entity_type lhs, const entity_type rhs) final {
-        std::swap(instances[underlying_type::index(lhs)], instances[underlying_type::index(rhs)]);
+        swap(underlying_type::index(lhs), underlying_type::index(rhs));
         underlying_type::swap(lhs, rhs);
     }
 
     /**
      * @brief Sort elements according to the given comparison function.
      *
-     * Sort the elements so that iterating the range with a couple of iterators
-     * returns them in the expected order. See `begin` and `end` for more
-     * details.
-     *
      * The comparison function object must return `true` if the first element
      * is _less_ than the second one, `false` otherwise. The signature of the
      * comparison function should be equivalent to one of the following:
@@ -485,33 +485,39 @@ public:
      * @tparam Compare Type of comparison function object.
      * @tparam Sort Type of sort function object.
      * @tparam Args Types of arguments to forward to the sort function object.
-     * @param first An iterator to the first element of the range to sort.
-     * @param last An iterator past the last element of the range to sort.
+     * @param count Number of elements to sort.
      * @param compare A valid comparison function object.
      * @param algo A valid sort function object.
      * @param args Arguments to forward to the sort function object, if any.
      */
     template<typename Compare, typename Sort = std_sort, typename... Args>
-    void sort(iterator first, iterator last, Compare compare, Sort algo = Sort{}, Args &&... args) {
-        ENTT_ASSERT(!(last < first));
-        ENTT_ASSERT(!(last > end()));
-
-        const auto from = underlying_type::begin() + std::distance(begin(), first);
-        const auto to = from + std::distance(first, last);
-
-        const auto apply = [this](const auto lhs, const auto rhs) {
-            std::swap(instances[underlying_type::index(lhs)], instances[underlying_type::index(rhs)]);
-        };
-
+    void sort_n(const size_type count, Compare compare, Sort algo = Sort{}, Args &&... args) {
         if constexpr(std::is_invocable_v<Compare, const value_type &, const value_type &>) {
-            underlying_type::arrange(from, to, std::move(apply), [this, compare = std::move(compare)](const auto lhs, const auto rhs) {
+            underlying_type::sort_n(count, [this, compare = std::move(compare)](const auto lhs, const auto rhs) {
                 return compare(std::as_const(instances[underlying_type::index(lhs)]), std::as_const(instances[underlying_type::index(rhs)]));
             }, std::move(algo), std::forward<Args>(args)...);
         } else {
-            underlying_type::arrange(from, to, std::move(apply), std::move(compare), std::move(algo), std::forward<Args>(args)...);
+            underlying_type::sort_n(count, std::move(compare), std::move(algo), std::forward<Args>(args)...);
         }
     }
 
+    /**
+     * @brief Sort all elements according to the given comparison function.
+     * 
+     * @sa sort_n
+     *
+     * @tparam Compare Type of comparison function object.
+     * @tparam Sort Type of sort function object.
+     * @tparam Args Types of arguments to forward to the sort function object.
+     * @param compare A valid comparison function object.
+     * @param algo A valid sort function object.
+     * @param args Arguments to forward to the sort function object, if any.
+     */
+    template<typename Compare, typename Sort = std_sort, typename... Args>
+    void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
+        sort_n(size(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
+    }
+
     /*! @brief Clears a storage. */
     void clear() ENTT_NOEXCEPT final {
         underlying_type::clear();

+ 1043 - 1043
test/benchmark/benchmark.cpp

@@ -64,1049 +64,1049 @@ void pathological(Func func) {
     });
 }
 
-TEST(Benchmark, Create) {
-    entt::registry registry;
-
-    std::cout << "Creating 1000000 entities" << std::endl;
-
-    timer timer;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        registry.create();
-    }
-
-    timer.elapsed();
-}
-
-TEST(Benchmark, CreateMany) {
-    entt::registry registry;
-    std::vector<entt::entity> entities(1000000);
-
-    std::cout << "Creating 1000000 entities at once" << std::endl;
-
-    timer timer;
-    registry.create(entities.begin(), entities.end());
-    timer.elapsed();
-}
-
-TEST(Benchmark, CreateManyAndEmplaceComponents) {
-    entt::registry registry;
-    std::vector<entt::entity> entities(1000000);
-
-    std::cout << "Creating 1000000 entities at once and emplace components" << std::endl;
-
-    timer timer;
-
-    registry.create(entities.begin(), entities.end());
-
-    for(const auto entity: entities) {
-        registry.emplace<position>(entity);
-        registry.emplace<velocity>(entity);
-    }
-
-    timer.elapsed();
-}
-
-TEST(Benchmark, CreateManyWithComponents) {
-    entt::registry registry;
-    std::vector<entt::entity> entities(1000000);
-
-    std::cout << "Creating 1000000 entities at once with components" << std::endl;
-
-    timer timer;
-    registry.create(entities.begin(), entities.end());
-    registry.insert<position>(entities.begin(), entities.end());
-    registry.insert<velocity>(entities.begin(), entities.end());
-    timer.elapsed();
-}
-
-TEST(Benchmark, Remove) {
-    entt::registry registry;
-    std::vector<entt::entity> entities(1000000);
-
-    std::cout << "Removing 1000000 components from their entities" << std::endl;
-
-    registry.create(entities.begin(), entities.end());
-    registry.insert<int>(entities.begin(), entities.end());
-
-    timer timer;
-
-    for(auto entity: registry.view<int>()) {
-        registry.remove<int>(entity);
-    }
-
-    timer.elapsed();
-}
-
-TEST(Benchmark, RemoveMany) {
-    entt::registry registry;
-    std::vector<entt::entity> entities(1000000);
-
-    std::cout << "Removing 999999 components from their entities at once" << std::endl;
-
-    registry.create(entities.begin(), entities.end());
-    registry.insert<int>(entities.begin(), entities.end());
-
-    timer timer;
-    auto view = registry.view<int>();
-    registry.remove<int>(++view.begin(), view.end());
-    timer.elapsed();
-}
-
-TEST(Benchmark, RemoveAll) {
-    entt::registry registry;
-    std::vector<entt::entity> entities(1000000);
-
-    std::cout << "Removing 1000000 components from their entities at once" << std::endl;
-
-    registry.create(entities.begin(), entities.end());
-    registry.insert<int>(entities.begin(), entities.end());
-
-    timer timer;
-    auto view = registry.view<int>();
-    registry.remove<int>(view.begin(), view.end());
-    timer.elapsed();
-}
-
-TEST(Benchmark, Recycle) {
-    entt::registry registry;
-    std::vector<entt::entity> entities(1000000);
-
-    std::cout << "Recycling 1000000 entities" << std::endl;
-
-    registry.create(entities.begin(), entities.end());
-
-    registry.each([&registry](auto entity) {
-        registry.destroy(entity);
-    });
-
-    timer timer;
-
-    for(auto next = entities.size(); next; --next) {
-        registry.create();
-    }
-
-    timer.elapsed();
-}
-
-TEST(Benchmark, RecycleMany) {
-    entt::registry registry;
-    std::vector<entt::entity> entities(1000000);
-
-    std::cout << "Recycling 1000000 entities" << std::endl;
-
-    registry.create(entities.begin(), entities.end());
-
-    registry.each([&registry](auto entity) {
-        registry.destroy(entity);
-    });
-
-    timer timer;
-    registry.create(entities.begin(), entities.end());
-    timer.elapsed();
-}
-
-TEST(Benchmark, Destroy) {
-    entt::registry registry;
-    std::vector<entt::entity> entities(1000000);
-
-    std::cout << "Destroying 1000000 entities" << std::endl;
-
-    registry.create(entities.begin(), entities.end());
-    registry.insert<int>(entities.begin(), entities.end());
-
-    timer timer;
-
-    for(auto entity: registry.view<int>()) {
-        registry.destroy(entity);
-    }
-
-    timer.elapsed();
-}
-
-TEST(Benchmark, DestroyMany) {
-    entt::registry registry;
-    std::vector<entt::entity> entities(1000000);
-
-    std::cout << "Destroying 1000000 entities" << std::endl;
-
-    registry.create(entities.begin(), entities.end());
-    registry.insert<int>(entities.begin(), entities.end());
-
-    timer timer;
-    auto view = registry.view<int>();
-    registry.destroy(view.begin(), view.end());
-    timer.elapsed();
-}
-
-TEST(Benchmark, IterateSingleComponent1M) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, one component" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<position>(entity);
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        registry.view<position>().each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateSingleComponentRuntime1M) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, one component, runtime view" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<position>(entity);
-    }
-
-    auto test = [&](auto func) {
-        entt::id_type types[] = { entt::type_hash<position>::value() };
-
-        timer timer;
-        registry.runtime_view(std::begin(types), std::end(types)).each(func);
-        timer.elapsed();
-    };
-
-    test([&registry](auto entity) {
-        registry.get<position>(entity).x = {};
-    });
-}
-
-TEST(Benchmark, IterateTwoComponents1M) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, two components" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<position>(entity);
-        registry.emplace<velocity>(entity);
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        registry.view<position, velocity>().each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateTwoComponents1MHalf) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, two components, half of the entities have all the components" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<velocity>(entity);
-
-        if(i % 2) {
-            registry.emplace<position>(entity);
-        }
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        registry.view<position, velocity>().each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateTwoComponents1MOne) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, two components, only one entity has all the components" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<velocity>(entity);
-
-        if(i == 500000L) {
-            registry.emplace<position>(entity);
-        }
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        registry.view<position, velocity>().each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateTwoComponentsNonOwningGroup1M) {
-    entt::registry registry;
-    const auto group = registry.group<>(entt::get<position, velocity>);
-
-    std::cout << "Iterating over 1000000 entities, two components, non owning group" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<position>(entity);
-        registry.emplace<velocity>(entity);
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        group.each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateTwoComponentsFullOwningGroup1M) {
-    entt::registry registry;
-    const auto group = registry.group<position, velocity>();
-
-    std::cout << "Iterating over 1000000 entities, two components, full owning group" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<position>(entity);
-        registry.emplace<velocity>(entity);
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        group.each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateTwoComponentsPartialOwningGroup1M) {
-    entt::registry registry;
-    const auto group = registry.group<position>(entt::get<velocity>);
-
-    std::cout << "Iterating over 1000000 entities, two components, partial owning group" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<position>(entity);
-        registry.emplace<velocity>(entity);
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        group.each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateTwoComponentsRuntime1M) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, two components, runtime view" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<position>(entity);
-        registry.emplace<velocity>(entity);
-    }
-
-    auto test = [&](auto func) {
-        entt::id_type types[] = {
-            entt::type_hash<position>::value(),
-            entt::type_hash<velocity>::value()
-        };
-
-        timer timer;
-        registry.runtime_view(std::begin(types), std::end(types)).each(func);
-        timer.elapsed();
-    };
-
-    test([&registry](auto entity) {
-        registry.get<position>(entity).x = {};
-        registry.get<velocity>(entity).x = {};
-    });
-}
-
-TEST(Benchmark, IterateTwoComponentsRuntime1MHalf) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, two components, half of the entities have all the components, runtime view" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<velocity>(entity);
-
-        if(i % 2) {
-            registry.emplace<position>(entity);
-        }
-    }
-
-    auto test = [&](auto func) {
-        entt::id_type types[] = {
-            entt::type_hash<position>::value(),
-            entt::type_hash<velocity>::value()
-        };
-
-        timer timer;
-        registry.runtime_view(std::begin(types), std::end(types)).each(func);
-        timer.elapsed();
-    };
-
-    test([&registry](auto entity) {
-        registry.get<position>(entity).x = {};
-        registry.get<velocity>(entity).x = {};
-    });
-}
-
-TEST(Benchmark, IterateTwoComponentsRuntime1MOne) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, two components, only one entity has all the components, runtime view" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<velocity>(entity);
-
-        if(i == 500000L) {
-            registry.emplace<position>(entity);
-        }
-    }
-
-    auto test = [&](auto func) {
-        entt::id_type types[] = {
-            entt::type_hash<position>::value(),
-            entt::type_hash<velocity>::value()
-        };
-
-        timer timer;
-        registry.runtime_view(std::begin(types), std::end(types)).each(func);
-        timer.elapsed();
-    };
-
-    test([&registry](auto entity) {
-        registry.get<position>(entity).x = {};
-        registry.get<velocity>(entity).x = {};
-    });
-}
-
-TEST(Benchmark, IterateThreeComponents1M) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, three components" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<position>(entity);
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        registry.view<position, velocity, comp<0>>().each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateThreeComponents1MHalf) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, three components, half of the entities have all the components" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-
-        if(i % 2) {
-            registry.emplace<position>(entity);
-        }
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        registry.view<position, velocity, comp<0>>().each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateThreeComponents1MOne) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, three components, only one entity has all the components" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-
-        if(i == 500000L) {
-            registry.emplace<position>(entity);
-        }
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        registry.view<position, velocity, comp<0>>().each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateThreeComponentsNonOwningGroup1M) {
-    entt::registry registry;
-    const auto group = registry.group<>(entt::get<position, velocity, comp<0>>);
-
-    std::cout << "Iterating over 1000000 entities, three components, non owning group" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<position>(entity);
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        group.each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateThreeComponentsFullOwningGroup1M) {
-    entt::registry registry;
-    const auto group = registry.group<position, velocity, comp<0>>();
-
-    std::cout << "Iterating over 1000000 entities, three components, full owning group" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<position>(entity);
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        group.each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateThreeComponentsPartialOwningGroup1M) {
-    entt::registry registry;
-    const auto group = registry.group<position, velocity>(entt::get<comp<0>>);
-
-    std::cout << "Iterating over 1000000 entities, three components, partial owning group" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<position>(entity);
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        group.each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateThreeComponentsRuntime1M) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, three components, runtime view" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<position>(entity);
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-    }
-
-    auto test = [&](auto func) {
-        entt::id_type types[] = {
-            entt::type_hash<position>::value(),
-            entt::type_hash<velocity>::value(),
-            entt::type_hash<comp<0>>::value()
-        };
-
-        timer timer;
-        registry.runtime_view(std::begin(types), std::end(types)).each(func);
-        timer.elapsed();
-    };
-
-    test([&registry](auto entity) {
-        registry.get<position>(entity).x = {};
-        registry.get<velocity>(entity).x = {};
-        registry.get<comp<0>>(entity).x = {};
-    });
-}
-
-TEST(Benchmark, IterateThreeComponentsRuntime1MHalf) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, three components, half of the entities have all the components, runtime view" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-
-        if(i % 2) {
-            registry.emplace<position>(entity);
-        }
-    }
-
-    auto test = [&](auto func) {
-        entt::id_type types[] = {
-            entt::type_hash<position>::value(),
-            entt::type_hash<velocity>::value(),
-            entt::type_hash<comp<0>>::value()
-        };
-
-        timer timer;
-        registry.runtime_view(std::begin(types), std::end(types)).each(func);
-        timer.elapsed();
-    };
-
-    test([&registry](auto entity) {
-        registry.get<position>(entity).x = {};
-        registry.get<velocity>(entity).x = {};
-        registry.get<comp<0>>(entity).x = {};
-    });
-}
-
-TEST(Benchmark, IterateThreeComponentsRuntime1MOne) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, three components, only one entity has all the components, runtime view" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-
-        if(i == 500000L) {
-            registry.emplace<position>(entity);
-        }
-    }
-
-    auto test = [&](auto func) {
-        entt::id_type types[] = {
-            entt::type_hash<position>::value(),
-            entt::type_hash<velocity>::value(),
-            entt::type_hash<comp<0>>::value()
-        };
-
-        timer timer;
-        registry.runtime_view(std::begin(types), std::end(types)).each(func);
-        timer.elapsed();
-    };
-
-    test([&registry](auto entity) {
-        registry.get<position>(entity).x = {};
-        registry.get<velocity>(entity).x = {};
-        registry.get<comp<0>>(entity).x = {};
-    });
-}
-
-TEST(Benchmark, IterateFiveComponents1M) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, five components" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<position>(entity);
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-        registry.emplace<comp<1>>(entity);
-        registry.emplace<comp<2>>(entity);
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        registry.view<position, velocity, comp<0>, comp<1>, comp<2>>().each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateFiveComponents1MHalf) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, five components, half of the entities have all the components" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-        registry.emplace<comp<1>>(entity);
-        registry.emplace<comp<2>>(entity);
-
-        if(i % 2) {
-            registry.emplace<position>(entity);
-        }
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        registry.view<position, velocity, comp<0>, comp<1>, comp<2>>().each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateFiveComponents1MOne) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, five components, only one entity has all the components" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-        registry.emplace<comp<1>>(entity);
-        registry.emplace<comp<2>>(entity);
-
-        if(i == 500000L) {
-            registry.emplace<position>(entity);
-        }
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        registry.view<position, velocity, comp<0>, comp<1>, comp<2>>().each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateFiveComponentsNonOwningGroup1M) {
-    entt::registry registry;
-    const auto group = registry.group<>(entt::get<position, velocity, comp<0>, comp<1>, comp<2>>);
-
-    std::cout << "Iterating over 1000000 entities, five components, non owning group" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<position>(entity);
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-        registry.emplace<comp<1>>(entity);
-        registry.emplace<comp<2>>(entity);
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        group.each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateFiveComponentsFullOwningGroup1M) {
-    entt::registry registry;
-    const auto group = registry.group<position, velocity, comp<0>, comp<1>, comp<2>>();
-
-    std::cout << "Iterating over 1000000 entities, five components, full owning group" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<position>(entity);
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-        registry.emplace<comp<1>>(entity);
-        registry.emplace<comp<2>>(entity);
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        group.each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateFiveComponentsPartialFourOfFiveOwningGroup1M) {
-    entt::registry registry;
-    const auto group = registry.group<position, velocity, comp<0>, comp<1>>(entt::get<comp<2>>);
-
-    std::cout << "Iterating over 1000000 entities, five components, partial (4 of 5) owning group" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<position>(entity);
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-        registry.emplace<comp<1>>(entity);
-        registry.emplace<comp<2>>(entity);
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        group.each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateFiveComponentsPartialThreeOfFiveOwningGroup1M) {
-    entt::registry registry;
-    const auto group = registry.group<position, velocity, comp<0>>(entt::get<comp<1>, comp<2>>);
-
-    std::cout << "Iterating over 1000000 entities, five components, partial (3 of 5) owning group" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<position>(entity);
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-        registry.emplace<comp<1>>(entity);
-        registry.emplace<comp<2>>(entity);
-    }
-
-    auto test = [&](auto func) {
-        timer timer;
-        group.each(func);
-        timer.elapsed();
-    };
-
-    test([](auto &... comp) {
-        ((comp.x = {}), ...);
-    });
-}
-
-TEST(Benchmark, IterateFiveComponentsRuntime1M) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, five components, runtime view" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<position>(entity);
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-        registry.emplace<comp<1>>(entity);
-        registry.emplace<comp<2>>(entity);
-    }
-
-    auto test = [&](auto func) {
-        entt::id_type types[] = {
-            entt::type_hash<position>::value(),
-            entt::type_hash<velocity>::value(),
-            entt::type_hash<comp<0>>::value(),
-            entt::type_hash<comp<1>>::value(),
-            entt::type_hash<comp<2>>::value()
-        };
-
-        timer timer;
-        registry.runtime_view(std::begin(types), std::end(types)).each(func);
-        timer.elapsed();
-    };
-
-    test([&registry](auto entity) {
-        registry.get<position>(entity).x = {};
-        registry.get<velocity>(entity).x = {};
-        registry.get<comp<0>>(entity).x = {};
-        registry.get<comp<1>>(entity).x = {};
-        registry.get<comp<2>>(entity).x = {};
-    });
-}
-
-TEST(Benchmark, IterateFiveComponentsRuntime1MHalf) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, five components, half of the entities have all the components, runtime view" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-        registry.emplace<comp<1>>(entity);
-        registry.emplace<comp<2>>(entity);
-
-        if(i % 2) {
-            registry.emplace<position>(entity);
-        }
-    }
-
-    auto test = [&](auto func) {
-        entt::id_type types[] = {
-            entt::type_hash<position>::value(),
-            entt::type_hash<velocity>::value(),
-            entt::type_hash<comp<0>>::value(),
-            entt::type_hash<comp<1>>::value(),
-            entt::type_hash<comp<2>>::value()
-        };
-
-        timer timer;
-        registry.runtime_view(std::begin(types), std::end(types)).each(func);
-        timer.elapsed();
-    };
-
-    test([&registry](auto entity) {
-        registry.get<position>(entity).x = {};
-        registry.get<velocity>(entity).x = {};
-        registry.get<comp<0>>(entity).x = {};
-        registry.get<comp<1>>(entity).x = {};
-        registry.get<comp<2>>(entity).x = {};
-    });
-}
-
-TEST(Benchmark, IterateFiveComponentsRuntime1MOne) {
-    entt::registry registry;
-
-    std::cout << "Iterating over 1000000 entities, five components, only one entity has all the components, runtime view" << std::endl;
-
-    for(std::uint64_t i = 0; i < 1000000L; i++) {
-        const auto entity = registry.create();
-        registry.emplace<velocity>(entity);
-        registry.emplace<comp<0>>(entity);
-        registry.emplace<comp<1>>(entity);
-        registry.emplace<comp<2>>(entity);
-
-        if(i == 500000L) {
-            registry.emplace<position>(entity);
-        }
-    }
-
-    auto test = [&](auto func) {
-        entt::id_type types[] = {
-            entt::type_hash<position>::value(),
-            entt::type_hash<velocity>::value(),
-            entt::type_hash<comp<0>>::value(),
-            entt::type_hash<comp<1>>::value(),
-            entt::type_hash<comp<2>>::value()
-        };
-
-        timer timer;
-        registry.runtime_view(std::begin(types), std::end(types)).each(func);
-        timer.elapsed();
-    };
-
-    test([&registry](auto entity) {
-        registry.get<position>(entity).x = {};
-        registry.get<velocity>(entity).x = {};
-        registry.get<comp<0>>(entity).x = {};
-        registry.get<comp<1>>(entity).x = {};
-        registry.get<comp<2>>(entity).x = {};
-    });
-}
-
-TEST(Benchmark, IteratePathological) {
-    std::cout << "Pathological case" << std::endl;
-
-    pathological([](auto &registry, auto func) {
-        timer timer;
-        registry.template view<position, velocity, comp<0>>().each(func);
-        timer.elapsed();
-    });
-}
-
-TEST(Benchmark, IteratePathologicalNonOwningGroup) {
-    std::cout << "Pathological case (non-owning group)" << std::endl;
-
-    pathological([](auto &registry, auto func) {
-        auto group = registry.template group<>(entt::get<position, velocity, comp<0>>);
-
-        timer timer;
-        group.each(func);
-        timer.elapsed();
-    });
-}
-
-TEST(Benchmark, IteratePathologicalFullOwningGroup) {
-    std::cout << "Pathological case (full-owning group)" << std::endl;
-
-    pathological([](auto &registry, auto func) {
-        auto group = registry.template group<position, velocity, comp<0>>();
-
-        timer timer;
-        group.each(func);
-        timer.elapsed();
-    });
-}
-
-TEST(Benchmark, IteratePathologicalPartialOwningGroup) {
-    std::cout << "Pathological case (partial-owning group)" << std::endl;
-
-    pathological([](auto &registry, auto func) {
-        auto group = registry.template group<position, velocity>(entt::get<comp<0>>);
-
-        timer timer;
-        group.each(func);
-        timer.elapsed();
-    });
-}
+// TEST(Benchmark, Create) {
+//     entt::registry registry;
+// 
+//     std::cout << "Creating 1000000 entities" << std::endl;
+// 
+//     timer timer;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         registry.create();
+//     }
+// 
+//     timer.elapsed();
+// }
+// 
+// TEST(Benchmark, CreateMany) {
+//     entt::registry registry;
+//     std::vector<entt::entity> entities(1000000);
+// 
+//     std::cout << "Creating 1000000 entities at once" << std::endl;
+// 
+//     timer timer;
+//     registry.create(entities.begin(), entities.end());
+//     timer.elapsed();
+// }
+// 
+// TEST(Benchmark, CreateManyAndEmplaceComponents) {
+//     entt::registry registry;
+//     std::vector<entt::entity> entities(1000000);
+// 
+//     std::cout << "Creating 1000000 entities at once and emplace components" << std::endl;
+// 
+//     timer timer;
+// 
+//     registry.create(entities.begin(), entities.end());
+// 
+//     for(const auto entity: entities) {
+//         registry.emplace<position>(entity);
+//         registry.emplace<velocity>(entity);
+//     }
+// 
+//     timer.elapsed();
+// }
+// 
+// TEST(Benchmark, CreateManyWithComponents) {
+//     entt::registry registry;
+//     std::vector<entt::entity> entities(1000000);
+// 
+//     std::cout << "Creating 1000000 entities at once with components" << std::endl;
+// 
+//     timer timer;
+//     registry.create(entities.begin(), entities.end());
+//     registry.insert<position>(entities.begin(), entities.end());
+//     registry.insert<velocity>(entities.begin(), entities.end());
+//     timer.elapsed();
+// }
+// 
+// TEST(Benchmark, Remove) {
+//     entt::registry registry;
+//     std::vector<entt::entity> entities(1000000);
+// 
+//     std::cout << "Removing 1000000 components from their entities" << std::endl;
+// 
+//     registry.create(entities.begin(), entities.end());
+//     registry.insert<int>(entities.begin(), entities.end());
+// 
+//     timer timer;
+// 
+//     for(auto entity: registry.view<int>()) {
+//         registry.remove<int>(entity);
+//     }
+// 
+//     timer.elapsed();
+// }
+// 
+// TEST(Benchmark, RemoveMany) {
+//     entt::registry registry;
+//     std::vector<entt::entity> entities(1000000);
+// 
+//     std::cout << "Removing 999999 components from their entities at once" << std::endl;
+// 
+//     registry.create(entities.begin(), entities.end());
+//     registry.insert<int>(entities.begin(), entities.end());
+// 
+//     timer timer;
+//     auto view = registry.view<int>();
+//     registry.remove<int>(++view.begin(), view.end());
+//     timer.elapsed();
+// }
+// 
+// TEST(Benchmark, RemoveAll) {
+//     entt::registry registry;
+//     std::vector<entt::entity> entities(1000000);
+// 
+//     std::cout << "Removing 1000000 components from their entities at once" << std::endl;
+// 
+//     registry.create(entities.begin(), entities.end());
+//     registry.insert<int>(entities.begin(), entities.end());
+// 
+//     timer timer;
+//     auto view = registry.view<int>();
+//     registry.remove<int>(view.begin(), view.end());
+//     timer.elapsed();
+// }
+// 
+// TEST(Benchmark, Recycle) {
+//     entt::registry registry;
+//     std::vector<entt::entity> entities(1000000);
+// 
+//     std::cout << "Recycling 1000000 entities" << std::endl;
+// 
+//     registry.create(entities.begin(), entities.end());
+// 
+//     registry.each([&registry](auto entity) {
+//         registry.destroy(entity);
+//     });
+// 
+//     timer timer;
+// 
+//     for(auto next = entities.size(); next; --next) {
+//         registry.create();
+//     }
+// 
+//     timer.elapsed();
+// }
+// 
+// TEST(Benchmark, RecycleMany) {
+//     entt::registry registry;
+//     std::vector<entt::entity> entities(1000000);
+// 
+//     std::cout << "Recycling 1000000 entities" << std::endl;
+// 
+//     registry.create(entities.begin(), entities.end());
+// 
+//     registry.each([&registry](auto entity) {
+//         registry.destroy(entity);
+//     });
+// 
+//     timer timer;
+//     registry.create(entities.begin(), entities.end());
+//     timer.elapsed();
+// }
+// 
+// TEST(Benchmark, Destroy) {
+//     entt::registry registry;
+//     std::vector<entt::entity> entities(1000000);
+// 
+//     std::cout << "Destroying 1000000 entities" << std::endl;
+// 
+//     registry.create(entities.begin(), entities.end());
+//     registry.insert<int>(entities.begin(), entities.end());
+// 
+//     timer timer;
+// 
+//     for(auto entity: registry.view<int>()) {
+//         registry.destroy(entity);
+//     }
+// 
+//     timer.elapsed();
+// }
+// 
+// TEST(Benchmark, DestroyMany) {
+//     entt::registry registry;
+//     std::vector<entt::entity> entities(1000000);
+// 
+//     std::cout << "Destroying 1000000 entities" << std::endl;
+// 
+//     registry.create(entities.begin(), entities.end());
+//     registry.insert<int>(entities.begin(), entities.end());
+// 
+//     timer timer;
+//     auto view = registry.view<int>();
+//     registry.destroy(view.begin(), view.end());
+//     timer.elapsed();
+// }
+// 
+// TEST(Benchmark, IterateSingleComponent1M) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, one component" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<position>(entity);
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         registry.view<position>().each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateSingleComponentRuntime1M) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, one component, runtime view" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<position>(entity);
+//     }
+// 
+//     auto test = [&](auto func) {
+//         entt::id_type types[] = { entt::type_hash<position>::value() };
+// 
+//         timer timer;
+//         registry.runtime_view(std::begin(types), std::end(types)).each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([&registry](auto entity) {
+//         registry.get<position>(entity).x = {};
+//     });
+// }
+// 
+// TEST(Benchmark, IterateTwoComponents1M) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, two components" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<position>(entity);
+//         registry.emplace<velocity>(entity);
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         registry.view<position, velocity>().each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateTwoComponents1MHalf) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, two components, half of the entities have all the components" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<velocity>(entity);
+// 
+//         if(i % 2) {
+//             registry.emplace<position>(entity);
+//         }
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         registry.view<position, velocity>().each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateTwoComponents1MOne) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, two components, only one entity has all the components" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<velocity>(entity);
+// 
+//         if(i == 500000L) {
+//             registry.emplace<position>(entity);
+//         }
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         registry.view<position, velocity>().each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateTwoComponentsNonOwningGroup1M) {
+//     entt::registry registry;
+//     const auto group = registry.group<>(entt::get<position, velocity>);
+// 
+//     std::cout << "Iterating over 1000000 entities, two components, non owning group" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<position>(entity);
+//         registry.emplace<velocity>(entity);
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         group.each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateTwoComponentsFullOwningGroup1M) {
+//     entt::registry registry;
+//     const auto group = registry.group<position, velocity>();
+// 
+//     std::cout << "Iterating over 1000000 entities, two components, full owning group" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<position>(entity);
+//         registry.emplace<velocity>(entity);
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         group.each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateTwoComponentsPartialOwningGroup1M) {
+//     entt::registry registry;
+//     const auto group = registry.group<position>(entt::get<velocity>);
+// 
+//     std::cout << "Iterating over 1000000 entities, two components, partial owning group" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<position>(entity);
+//         registry.emplace<velocity>(entity);
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         group.each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateTwoComponentsRuntime1M) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, two components, runtime view" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<position>(entity);
+//         registry.emplace<velocity>(entity);
+//     }
+// 
+//     auto test = [&](auto func) {
+//         entt::id_type types[] = {
+//             entt::type_hash<position>::value(),
+//             entt::type_hash<velocity>::value()
+//         };
+// 
+//         timer timer;
+//         registry.runtime_view(std::begin(types), std::end(types)).each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([&registry](auto entity) {
+//         registry.get<position>(entity).x = {};
+//         registry.get<velocity>(entity).x = {};
+//     });
+// }
+// 
+// TEST(Benchmark, IterateTwoComponentsRuntime1MHalf) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, two components, half of the entities have all the components, runtime view" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<velocity>(entity);
+// 
+//         if(i % 2) {
+//             registry.emplace<position>(entity);
+//         }
+//     }
+// 
+//     auto test = [&](auto func) {
+//         entt::id_type types[] = {
+//             entt::type_hash<position>::value(),
+//             entt::type_hash<velocity>::value()
+//         };
+// 
+//         timer timer;
+//         registry.runtime_view(std::begin(types), std::end(types)).each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([&registry](auto entity) {
+//         registry.get<position>(entity).x = {};
+//         registry.get<velocity>(entity).x = {};
+//     });
+// }
+// 
+// TEST(Benchmark, IterateTwoComponentsRuntime1MOne) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, two components, only one entity has all the components, runtime view" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<velocity>(entity);
+// 
+//         if(i == 500000L) {
+//             registry.emplace<position>(entity);
+//         }
+//     }
+// 
+//     auto test = [&](auto func) {
+//         entt::id_type types[] = {
+//             entt::type_hash<position>::value(),
+//             entt::type_hash<velocity>::value()
+//         };
+// 
+//         timer timer;
+//         registry.runtime_view(std::begin(types), std::end(types)).each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([&registry](auto entity) {
+//         registry.get<position>(entity).x = {};
+//         registry.get<velocity>(entity).x = {};
+//     });
+// }
+// 
+// TEST(Benchmark, IterateThreeComponents1M) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, three components" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<position>(entity);
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         registry.view<position, velocity, comp<0>>().each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateThreeComponents1MHalf) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, three components, half of the entities have all the components" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+// 
+//         if(i % 2) {
+//             registry.emplace<position>(entity);
+//         }
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         registry.view<position, velocity, comp<0>>().each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateThreeComponents1MOne) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, three components, only one entity has all the components" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+// 
+//         if(i == 500000L) {
+//             registry.emplace<position>(entity);
+//         }
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         registry.view<position, velocity, comp<0>>().each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateThreeComponentsNonOwningGroup1M) {
+//     entt::registry registry;
+//     const auto group = registry.group<>(entt::get<position, velocity, comp<0>>);
+// 
+//     std::cout << "Iterating over 1000000 entities, three components, non owning group" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<position>(entity);
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         group.each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateThreeComponentsFullOwningGroup1M) {
+//     entt::registry registry;
+//     const auto group = registry.group<position, velocity, comp<0>>();
+// 
+//     std::cout << "Iterating over 1000000 entities, three components, full owning group" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<position>(entity);
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         group.each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateThreeComponentsPartialOwningGroup1M) {
+//     entt::registry registry;
+//     const auto group = registry.group<position, velocity>(entt::get<comp<0>>);
+// 
+//     std::cout << "Iterating over 1000000 entities, three components, partial owning group" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<position>(entity);
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         group.each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateThreeComponentsRuntime1M) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, three components, runtime view" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<position>(entity);
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+//     }
+// 
+//     auto test = [&](auto func) {
+//         entt::id_type types[] = {
+//             entt::type_hash<position>::value(),
+//             entt::type_hash<velocity>::value(),
+//             entt::type_hash<comp<0>>::value()
+//         };
+// 
+//         timer timer;
+//         registry.runtime_view(std::begin(types), std::end(types)).each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([&registry](auto entity) {
+//         registry.get<position>(entity).x = {};
+//         registry.get<velocity>(entity).x = {};
+//         registry.get<comp<0>>(entity).x = {};
+//     });
+// }
+// 
+// TEST(Benchmark, IterateThreeComponentsRuntime1MHalf) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, three components, half of the entities have all the components, runtime view" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+// 
+//         if(i % 2) {
+//             registry.emplace<position>(entity);
+//         }
+//     }
+// 
+//     auto test = [&](auto func) {
+//         entt::id_type types[] = {
+//             entt::type_hash<position>::value(),
+//             entt::type_hash<velocity>::value(),
+//             entt::type_hash<comp<0>>::value()
+//         };
+// 
+//         timer timer;
+//         registry.runtime_view(std::begin(types), std::end(types)).each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([&registry](auto entity) {
+//         registry.get<position>(entity).x = {};
+//         registry.get<velocity>(entity).x = {};
+//         registry.get<comp<0>>(entity).x = {};
+//     });
+// }
+// 
+// TEST(Benchmark, IterateThreeComponentsRuntime1MOne) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, three components, only one entity has all the components, runtime view" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+// 
+//         if(i == 500000L) {
+//             registry.emplace<position>(entity);
+//         }
+//     }
+// 
+//     auto test = [&](auto func) {
+//         entt::id_type types[] = {
+//             entt::type_hash<position>::value(),
+//             entt::type_hash<velocity>::value(),
+//             entt::type_hash<comp<0>>::value()
+//         };
+// 
+//         timer timer;
+//         registry.runtime_view(std::begin(types), std::end(types)).each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([&registry](auto entity) {
+//         registry.get<position>(entity).x = {};
+//         registry.get<velocity>(entity).x = {};
+//         registry.get<comp<0>>(entity).x = {};
+//     });
+// }
+// 
+// TEST(Benchmark, IterateFiveComponents1M) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, five components" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<position>(entity);
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+//         registry.emplace<comp<1>>(entity);
+//         registry.emplace<comp<2>>(entity);
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         registry.view<position, velocity, comp<0>, comp<1>, comp<2>>().each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateFiveComponents1MHalf) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, five components, half of the entities have all the components" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+//         registry.emplace<comp<1>>(entity);
+//         registry.emplace<comp<2>>(entity);
+// 
+//         if(i % 2) {
+//             registry.emplace<position>(entity);
+//         }
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         registry.view<position, velocity, comp<0>, comp<1>, comp<2>>().each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateFiveComponents1MOne) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, five components, only one entity has all the components" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+//         registry.emplace<comp<1>>(entity);
+//         registry.emplace<comp<2>>(entity);
+// 
+//         if(i == 500000L) {
+//             registry.emplace<position>(entity);
+//         }
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         registry.view<position, velocity, comp<0>, comp<1>, comp<2>>().each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateFiveComponentsNonOwningGroup1M) {
+//     entt::registry registry;
+//     const auto group = registry.group<>(entt::get<position, velocity, comp<0>, comp<1>, comp<2>>);
+// 
+//     std::cout << "Iterating over 1000000 entities, five components, non owning group" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<position>(entity);
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+//         registry.emplace<comp<1>>(entity);
+//         registry.emplace<comp<2>>(entity);
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         group.each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateFiveComponentsFullOwningGroup1M) {
+//     entt::registry registry;
+//     const auto group = registry.group<position, velocity, comp<0>, comp<1>, comp<2>>();
+// 
+//     std::cout << "Iterating over 1000000 entities, five components, full owning group" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<position>(entity);
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+//         registry.emplace<comp<1>>(entity);
+//         registry.emplace<comp<2>>(entity);
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         group.each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateFiveComponentsPartialFourOfFiveOwningGroup1M) {
+//     entt::registry registry;
+//     const auto group = registry.group<position, velocity, comp<0>, comp<1>>(entt::get<comp<2>>);
+// 
+//     std::cout << "Iterating over 1000000 entities, five components, partial (4 of 5) owning group" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<position>(entity);
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+//         registry.emplace<comp<1>>(entity);
+//         registry.emplace<comp<2>>(entity);
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         group.each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateFiveComponentsPartialThreeOfFiveOwningGroup1M) {
+//     entt::registry registry;
+//     const auto group = registry.group<position, velocity, comp<0>>(entt::get<comp<1>, comp<2>>);
+// 
+//     std::cout << "Iterating over 1000000 entities, five components, partial (3 of 5) owning group" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<position>(entity);
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+//         registry.emplace<comp<1>>(entity);
+//         registry.emplace<comp<2>>(entity);
+//     }
+// 
+//     auto test = [&](auto func) {
+//         timer timer;
+//         group.each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([](auto &... comp) {
+//         ((comp.x = {}), ...);
+//     });
+// }
+// 
+// TEST(Benchmark, IterateFiveComponentsRuntime1M) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, five components, runtime view" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<position>(entity);
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+//         registry.emplace<comp<1>>(entity);
+//         registry.emplace<comp<2>>(entity);
+//     }
+// 
+//     auto test = [&](auto func) {
+//         entt::id_type types[] = {
+//             entt::type_hash<position>::value(),
+//             entt::type_hash<velocity>::value(),
+//             entt::type_hash<comp<0>>::value(),
+//             entt::type_hash<comp<1>>::value(),
+//             entt::type_hash<comp<2>>::value()
+//         };
+// 
+//         timer timer;
+//         registry.runtime_view(std::begin(types), std::end(types)).each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([&registry](auto entity) {
+//         registry.get<position>(entity).x = {};
+//         registry.get<velocity>(entity).x = {};
+//         registry.get<comp<0>>(entity).x = {};
+//         registry.get<comp<1>>(entity).x = {};
+//         registry.get<comp<2>>(entity).x = {};
+//     });
+// }
+// 
+// TEST(Benchmark, IterateFiveComponentsRuntime1MHalf) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, five components, half of the entities have all the components, runtime view" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+//         registry.emplace<comp<1>>(entity);
+//         registry.emplace<comp<2>>(entity);
+// 
+//         if(i % 2) {
+//             registry.emplace<position>(entity);
+//         }
+//     }
+// 
+//     auto test = [&](auto func) {
+//         entt::id_type types[] = {
+//             entt::type_hash<position>::value(),
+//             entt::type_hash<velocity>::value(),
+//             entt::type_hash<comp<0>>::value(),
+//             entt::type_hash<comp<1>>::value(),
+//             entt::type_hash<comp<2>>::value()
+//         };
+// 
+//         timer timer;
+//         registry.runtime_view(std::begin(types), std::end(types)).each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([&registry](auto entity) {
+//         registry.get<position>(entity).x = {};
+//         registry.get<velocity>(entity).x = {};
+//         registry.get<comp<0>>(entity).x = {};
+//         registry.get<comp<1>>(entity).x = {};
+//         registry.get<comp<2>>(entity).x = {};
+//     });
+// }
+// 
+// TEST(Benchmark, IterateFiveComponentsRuntime1MOne) {
+//     entt::registry registry;
+// 
+//     std::cout << "Iterating over 1000000 entities, five components, only one entity has all the components, runtime view" << std::endl;
+// 
+//     for(std::uint64_t i = 0; i < 1000000L; i++) {
+//         const auto entity = registry.create();
+//         registry.emplace<velocity>(entity);
+//         registry.emplace<comp<0>>(entity);
+//         registry.emplace<comp<1>>(entity);
+//         registry.emplace<comp<2>>(entity);
+// 
+//         if(i == 500000L) {
+//             registry.emplace<position>(entity);
+//         }
+//     }
+// 
+//     auto test = [&](auto func) {
+//         entt::id_type types[] = {
+//             entt::type_hash<position>::value(),
+//             entt::type_hash<velocity>::value(),
+//             entt::type_hash<comp<0>>::value(),
+//             entt::type_hash<comp<1>>::value(),
+//             entt::type_hash<comp<2>>::value()
+//         };
+// 
+//         timer timer;
+//         registry.runtime_view(std::begin(types), std::end(types)).each(func);
+//         timer.elapsed();
+//     };
+// 
+//     test([&registry](auto entity) {
+//         registry.get<position>(entity).x = {};
+//         registry.get<velocity>(entity).x = {};
+//         registry.get<comp<0>>(entity).x = {};
+//         registry.get<comp<1>>(entity).x = {};
+//         registry.get<comp<2>>(entity).x = {};
+//     });
+// }
+// 
+// TEST(Benchmark, IteratePathological) {
+//     std::cout << "Pathological case" << std::endl;
+// 
+//     pathological([](auto &registry, auto func) {
+//         timer timer;
+//         registry.template view<position, velocity, comp<0>>().each(func);
+//         timer.elapsed();
+//     });
+// }
+// 
+// TEST(Benchmark, IteratePathologicalNonOwningGroup) {
+//     std::cout << "Pathological case (non-owning group)" << std::endl;
+// 
+//     pathological([](auto &registry, auto func) {
+//         auto group = registry.template group<>(entt::get<position, velocity, comp<0>>);
+// 
+//         timer timer;
+//         group.each(func);
+//         timer.elapsed();
+//     });
+// }
+// 
+// TEST(Benchmark, IteratePathologicalFullOwningGroup) {
+//     std::cout << "Pathological case (full-owning group)" << std::endl;
+// 
+//     pathological([](auto &registry, auto func) {
+//         auto group = registry.template group<position, velocity, comp<0>>();
+// 
+//         timer timer;
+//         group.each(func);
+//         timer.elapsed();
+//     });
+// }
+// 
+// TEST(Benchmark, IteratePathologicalPartialOwningGroup) {
+//     std::cout << "Pathological case (partial-owning group)" << std::endl;
+// 
+//     pathological([](auto &registry, auto func) {
+//         auto group = registry.template group<position, velocity>(entt::get<comp<0>>);
+// 
+//         timer timer;
+//         group.each(func);
+//         timer.elapsed();
+//     });
+// }
 
 TEST(Benchmark, SortSingle) {
     entt::registry registry;

+ 87 - 393
test/entt/entity/sparse_set.cpp

@@ -291,119 +291,37 @@ TEST(SparseSet, Data) {
     ASSERT_EQ(set.index(entt::entity{12}), 1u);
     ASSERT_EQ(set.index(entt::entity{42}), 2u);
 
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{3});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{42});
+    ASSERT_EQ(set.data()[0u], entt::entity{3});
+    ASSERT_EQ(set.data()[1u], entt::entity{12});
+    ASSERT_EQ(set.data()[2u], entt::entity{42});
 }
 
 TEST(SparseSet, SortOrdered) {
     entt::sparse_set set;
+    entt::entity entities[5u]{entt::entity{42}, entt::entity{12}, entt::entity{9}, entt::entity{7}, entt::entity{3}};
 
-    set.emplace(entt::entity{42});
-    set.emplace(entt::entity{12});
-    set.emplace(entt::entity{9});
-    set.emplace(entt::entity{7});
-    set.emplace(entt::entity{3});
-
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{42});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{9});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{7});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{3});
-
-    set.sort(set.begin(), set.end(), std::less{});
-
-    ASSERT_EQ(set.index(entt::entity{42}), 0u);
-    ASSERT_EQ(set.index(entt::entity{12}), 1u);
-    ASSERT_EQ(set.index(entt::entity{9}), 2u);
-    ASSERT_EQ(set.index(entt::entity{7}), 3u);
-    ASSERT_EQ(set.index(entt::entity{3}), 4u);
-
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{42});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{9});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{7});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{3});
-
-    auto begin = set.begin();
-    auto end = set.end();
+    set.insert(std::begin(entities), std::end(entities));
+    set.sort(std::less{});
 
-    ASSERT_EQ(*(begin++), entt::entity{3});
-    ASSERT_EQ(*(begin++), entt::entity{7});
-    ASSERT_EQ(*(begin++), entt::entity{9});
-    ASSERT_EQ(*(begin++), entt::entity{12});
-    ASSERT_EQ(*(begin++), entt::entity{42});
-    ASSERT_EQ(begin, end);
+    ASSERT_TRUE(std::equal(std::rbegin(entities), std::rend(entities), set.begin(), set.end()));
 }
 
 TEST(SparseSet, SortReverse) {
     entt::sparse_set set;
+    entt::entity entities[5u]{entt::entity{3}, entt::entity{7}, entt::entity{9}, entt::entity{12}, entt::entity{42}};
 
-    set.emplace(entt::entity{3});
-    set.emplace(entt::entity{7});
-    set.emplace(entt::entity{9});
-    set.emplace(entt::entity{12});
-    set.emplace(entt::entity{42});
-
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{3});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{7});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{9});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{42});
-
-    set.sort(set.begin(), set.end(), std::less{});
-
-    ASSERT_EQ(set.index(entt::entity{42}), 0u);
-    ASSERT_EQ(set.index(entt::entity{12}), 1u);
-    ASSERT_EQ(set.index(entt::entity{9}), 2u);
-    ASSERT_EQ(set.index(entt::entity{7}), 3u);
-    ASSERT_EQ(set.index(entt::entity{3}), 4u);
-
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{42});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{9});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{7});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{3});
-
-    auto begin = set.begin();
-    auto end = set.end();
+    set.insert(std::begin(entities), std::end(entities));
+    set.sort(std::less{});
 
-    ASSERT_EQ(*(begin++), entt::entity{3});
-    ASSERT_EQ(*(begin++), entt::entity{7});
-    ASSERT_EQ(*(begin++), entt::entity{9});
-    ASSERT_EQ(*(begin++), entt::entity{12});
-    ASSERT_EQ(*(begin++), entt::entity{42});
-    ASSERT_EQ(begin, end);
+    ASSERT_TRUE(std::equal(std::begin(entities), std::end(entities), set.begin(), set.end()));
 }
 
 TEST(SparseSet, SortUnordered) {
     entt::sparse_set set;
+    entt::entity entities[5u]{entt::entity{9}, entt::entity{7}, entt::entity{3}, entt::entity{12}, entt::entity{42}};
 
-    set.emplace(entt::entity{9});
-    set.emplace(entt::entity{7});
-    set.emplace(entt::entity{3});
-    set.emplace(entt::entity{12});
-    set.emplace(entt::entity{42});
-
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{9});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{7});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{3});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{42});
-
-    set.sort(set.begin(), set.end(), std::less{});
-
-    ASSERT_EQ(set.index(entt::entity{42}), 0u);
-    ASSERT_EQ(set.index(entt::entity{12}), 1u);
-    ASSERT_EQ(set.index(entt::entity{9}), 2u);
-    ASSERT_EQ(set.index(entt::entity{7}), 3u);
-    ASSERT_EQ(set.index(entt::entity{3}), 4u);
-
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{42});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{9});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{7});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{3});
+    set.insert(std::begin(entities), std::end(entities));
+    set.sort(std::less{});
 
     auto begin = set.begin();
     auto end = set.end();
@@ -418,364 +336,140 @@ TEST(SparseSet, SortUnordered) {
 
 TEST(SparseSet, SortRange) {
     entt::sparse_set set;
+    entt::entity entities[5u]{entt::entity{7}, entt::entity{9}, entt::entity{3}, entt::entity{12}, entt::entity{42}};
 
-    set.emplace(entt::entity{9});
-    set.emplace(entt::entity{7});
-    set.emplace(entt::entity{3});
-    set.emplace(entt::entity{12});
-    set.emplace(entt::entity{42});
-
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{9});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{7});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{3});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{42});
-
-    set.sort(set.end(), set.end(), std::less{});
-
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{9});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{7});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{3});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{42});
-
-    set.sort(set.begin(), set.begin(), std::less{});
-
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{9});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{7});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{3});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{42});
-
-    set.sort(set.begin()+2, set.begin()+3, std::less{});
+    set.insert(std::begin(entities), std::end(entities));
+    set.sort_n(0u, std::less{});
 
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{9});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{7});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{3});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{42});
+    ASSERT_TRUE(std::equal(std::rbegin(entities), std::rend(entities), set.begin(), set.end()));
 
-    set.sort(++set.begin(), --set.end(), std::less{});
+    set.sort_n(2u, std::less{});
 
-    ASSERT_EQ(set.index(entt::entity{9}), 0u);
-    ASSERT_EQ(set.index(entt::entity{12}), 1u);
-    ASSERT_EQ(set.index(entt::entity{7}), 2u);
-    ASSERT_EQ(set.index(entt::entity{3}), 3u);
-    ASSERT_EQ(set.index(entt::entity{42}), 4u);
+    ASSERT_EQ(set.data()[0u], entt::entity{9});
+    ASSERT_EQ(set.data()[1u], entt::entity{7});
+    ASSERT_EQ(set.data()[2u], entt::entity{3});
 
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{9});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{7});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{3});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{42});
+    set.sort_n(5u, std::less{});
 
     auto begin = set.begin();
     auto end = set.end();
 
-    ASSERT_EQ(*(begin++), entt::entity{42});
     ASSERT_EQ(*(begin++), entt::entity{3});
     ASSERT_EQ(*(begin++), entt::entity{7});
-    ASSERT_EQ(*(begin++), entt::entity{12});
     ASSERT_EQ(*(begin++), entt::entity{9});
+    ASSERT_EQ(*(begin++), entt::entity{12});
+    ASSERT_EQ(*(begin++), entt::entity{42});
     ASSERT_EQ(begin, end);
 }
 
-TEST(SparseSet, ArrangOrdered) {
-    entt::sparse_set set;
-    entt::entity entities[5]{entt::entity{42}, entt::entity{12}, entt::entity{9}, entt::entity{7}, entt::entity{3}};
-    set.insert(std::begin(entities), std::end(entities));
-
-    set.arrange(set.begin(), set.end(), [](auto...) { FAIL(); }, std::less{});
-
-    ASSERT_EQ(set.index(entt::entity{42}), 0u);
-    ASSERT_EQ(set.index(entt::entity{12}), 1u);
-    ASSERT_EQ(set.index(entt::entity{9}), 2u);
-    ASSERT_EQ(set.index(entt::entity{7}), 3u);
-    ASSERT_EQ(set.index(entt::entity{3}), 4u);
-
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{42});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{9});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{7});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{3});
-
-    ASSERT_TRUE(std::equal(std::begin(entities), std::end(entities), set.data()));
-}
-
-TEST(SparseSet, ArrangeReverse) {
-    entt::sparse_set set;
-    entt::entity entities[5]{entt::entity{3}, entt::entity{7}, entt::entity{9}, entt::entity{12}, entt::entity{42}};
-    set.insert(std::begin(entities), std::end(entities));
-
-    set.arrange(set.begin(), set.end(), [&set, &entities](const auto lhs, const auto rhs) {
-        std::swap(entities[set.index(lhs)], entities[set.index(rhs)]);
-    }, std::less{});
-
-    ASSERT_EQ(set.index(entt::entity{42}), 0u);
-    ASSERT_EQ(set.index(entt::entity{12}), 1u);
-    ASSERT_EQ(set.index(entt::entity{9}), 2u);
-    ASSERT_EQ(set.index(entt::entity{7}), 3u);
-    ASSERT_EQ(set.index(entt::entity{3}), 4u);
-
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{42});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{9});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{7});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{3});
-
-    ASSERT_TRUE(std::equal(std::begin(entities), std::end(entities), set.data()));
-}
-
-TEST(SparseSet, ArrangeUnordered) {
-    entt::sparse_set set;
-    entt::entity entities[5]{entt::entity{9}, entt::entity{7}, entt::entity{3}, entt::entity{12}, entt::entity{42}};
-    set.insert(std::begin(entities), std::end(entities));
-
-    set.arrange(set.begin(), set.end(), [&set, &entities](const auto lhs, const auto rhs) {
-        std::swap(entities[set.index(lhs)], entities[set.index(rhs)]);
-    }, std::less{});
-
-    ASSERT_EQ(set.index(entt::entity{42}), 0u);
-    ASSERT_EQ(set.index(entt::entity{12}), 1u);
-    ASSERT_EQ(set.index(entt::entity{9}), 2u);
-    ASSERT_EQ(set.index(entt::entity{7}), 3u);
-    ASSERT_EQ(set.index(entt::entity{3}), 4u);
-
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{42});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{9});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{7});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{3});
-
-    ASSERT_TRUE(std::equal(std::begin(entities), std::end(entities), set.data()));
-}
-
-TEST(SparseSet, ArrangeRange) {
-    entt::sparse_set set;
-    entt::entity entities[5]{entt::entity{9}, entt::entity{7}, entt::entity{3}, entt::entity{12}, entt::entity{42}};
-    set.insert(std::begin(entities), std::end(entities));
-
-    set.arrange(set.end(), set.end(), [](const auto, const auto) { FAIL(); }, std::less{});
-
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{9});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{7});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{3});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{42});
-
-    set.arrange(set.begin(), set.begin(), [](const auto, const auto) { FAIL(); }, std::less{});
-
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{9});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{7});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{3});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{42});
-
-    set.arrange(set.begin()+2, set.begin()+3, [](const auto, const auto) { FAIL(); }, std::less{});
-
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{9});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{7});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{3});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{42});
-
-    set.arrange(++set.begin(), --set.end(), [&set, &entities](const auto lhs, const auto rhs) {
-        std::swap(entities[set.index(lhs)], entities[set.index(rhs)]);
-    }, std::less{});
-
-    ASSERT_EQ(set.index(entt::entity{9}), 0u);
-    ASSERT_EQ(set.index(entt::entity{12}), 1u);
-    ASSERT_EQ(set.index(entt::entity{7}), 2u);
-    ASSERT_EQ(set.index(entt::entity{3}), 3u);
-    ASSERT_EQ(set.index(entt::entity{42}), 4u);
-
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{9});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{12});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{7});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{3});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{42});
-}
-
-TEST(SparseSet, ArrangeCornerCase) {
-    entt::sparse_set set;
-    entt::entity entities[5]{entt::entity{0}, entt::entity{1}, entt::entity{4}, entt::entity{3}, entt::entity{2}};
-    set.insert(std::begin(entities), std::end(entities));
-
-    set.arrange(++set.begin(), set.end(), [&set, &entities](const auto lhs, const auto rhs) {
-        std::swap(entities[set.index(lhs)], entities[set.index(rhs)]);
-    }, std::less{});
-
-    ASSERT_EQ(set.index(entt::entity{4}), 0u);
-    ASSERT_EQ(set.index(entt::entity{3}), 1u);
-    ASSERT_EQ(set.index(entt::entity{1}), 2u);
-    ASSERT_EQ(set.index(entt::entity{0}), 3u);
-    ASSERT_EQ(set.index(entt::entity{2}), 4u);
-
-    ASSERT_EQ(*(set.data() + 0u), entt::entity{4});
-    ASSERT_EQ(*(set.data() + 1u), entt::entity{3});
-    ASSERT_EQ(*(set.data() + 2u), entt::entity{1});
-    ASSERT_EQ(*(set.data() + 3u), entt::entity{0});
-    ASSERT_EQ(*(set.data() + 4u), entt::entity{2});
-}
-
 TEST(SparseSet, RespectDisjoint) {
     entt::sparse_set lhs;
     entt::sparse_set rhs;
 
-    lhs.emplace(entt::entity{3});
-    lhs.emplace(entt::entity{12});
-    lhs.emplace(entt::entity{42});
+    entt::entity lhs_entities[3u]{entt::entity{3}, entt::entity{12}, entt::entity{42}};
+    lhs.insert(std::begin(lhs_entities), std::end(lhs_entities));
 
-    ASSERT_EQ(lhs.index(entt::entity{3}), 0u);
-    ASSERT_EQ(lhs.index(entt::entity{12}), 1u);
-    ASSERT_EQ(lhs.index(entt::entity{42}), 2u);
+    ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.begin(), lhs.end()));
 
     lhs.respect(rhs);
 
-    ASSERT_EQ(std::as_const(lhs).index(entt::entity{3}), 0u);
-    ASSERT_EQ(std::as_const(lhs).index(entt::entity{12}), 1u);
-    ASSERT_EQ(std::as_const(lhs).index(entt::entity{42}), 2u);
+    ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.begin(), lhs.end()));
 }
 
 TEST(SparseSet, RespectOverlap) {
     entt::sparse_set lhs;
     entt::sparse_set rhs;
 
-    lhs.emplace(entt::entity{3});
-    lhs.emplace(entt::entity{12});
-    lhs.emplace(entt::entity{42});
+    entt::entity lhs_entities[3u]{entt::entity{3}, entt::entity{12}, entt::entity{42}};
+    lhs.insert(std::begin(lhs_entities), std::end(lhs_entities));
 
-    rhs.emplace(entt::entity{12});
+    entt::entity rhs_entities[1u]{entt::entity{12}};
+    rhs.insert(std::begin(rhs_entities), std::end(rhs_entities));
 
-    ASSERT_EQ(lhs.index(entt::entity{3}), 0u);
-    ASSERT_EQ(lhs.index(entt::entity{12}), 1u);
-    ASSERT_EQ(lhs.index(entt::entity{42}), 2u);
+    ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.begin(), lhs.end()));
+    ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.begin(), rhs.end()));
 
     lhs.respect(rhs);
 
-    ASSERT_EQ(std::as_const(lhs).index(entt::entity{3}), 0u);
-    ASSERT_EQ(std::as_const(lhs).index(entt::entity{12}), 2u);
-    ASSERT_EQ(std::as_const(lhs).index(entt::entity{42}), 1u);
+    auto begin = lhs.begin();
+    auto end = lhs.end();
+
+    ASSERT_EQ(*(begin++), entt::entity{12});
+    ASSERT_EQ(*(begin++), entt::entity{42});
+    ASSERT_EQ(*(begin++), entt::entity{3});
+    ASSERT_EQ(begin, end);
 }
 
 TEST(SparseSet, RespectOrdered) {
     entt::sparse_set lhs;
     entt::sparse_set rhs;
 
-    lhs.emplace(entt::entity{1});
-    lhs.emplace(entt::entity{2});
-    lhs.emplace(entt::entity{3});
-    lhs.emplace(entt::entity{4});
-    lhs.emplace(entt::entity{5});
-
-    ASSERT_EQ(lhs.index(entt::entity{1}), 0u);
-    ASSERT_EQ(lhs.index(entt::entity{2}), 1u);
-    ASSERT_EQ(lhs.index(entt::entity{3}), 2u);
-    ASSERT_EQ(lhs.index(entt::entity{4}), 3u);
-    ASSERT_EQ(lhs.index(entt::entity{5}), 4u);
-
-    rhs.emplace(entt::entity{6});
-    rhs.emplace(entt::entity{1});
-    rhs.emplace(entt::entity{2});
-    rhs.emplace(entt::entity{3});
-    rhs.emplace(entt::entity{4});
-    rhs.emplace(entt::entity{5});
-
-    ASSERT_EQ(rhs.index(entt::entity{6}), 0u);
-    ASSERT_EQ(rhs.index(entt::entity{1}), 1u);
-    ASSERT_EQ(rhs.index(entt::entity{2}), 2u);
-    ASSERT_EQ(rhs.index(entt::entity{3}), 3u);
-    ASSERT_EQ(rhs.index(entt::entity{4}), 4u);
-    ASSERT_EQ(rhs.index(entt::entity{5}), 5u);
+    entt::entity lhs_entities[5u]{entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
+    lhs.insert(std::begin(lhs_entities), std::end(lhs_entities));
+
+    entt::entity rhs_entities[6u]{entt::entity{6}, entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
+    rhs.insert(std::begin(rhs_entities), std::end(rhs_entities));
+
+    ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.begin(), lhs.end()));
+    ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.begin(), rhs.end()));
 
     rhs.respect(lhs);
 
-    ASSERT_EQ(rhs.index(entt::entity{6}), 0u);
-    ASSERT_EQ(rhs.index(entt::entity{1}), 1u);
-    ASSERT_EQ(rhs.index(entt::entity{2}), 2u);
-    ASSERT_EQ(rhs.index(entt::entity{3}), 3u);
-    ASSERT_EQ(rhs.index(entt::entity{4}), 4u);
-    ASSERT_EQ(rhs.index(entt::entity{5}), 5u);
+    ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.begin(), rhs.end()));
 }
 
 TEST(SparseSet, RespectReverse) {
     entt::sparse_set lhs;
     entt::sparse_set rhs;
 
-    lhs.emplace(entt::entity{1});
-    lhs.emplace(entt::entity{2});
-    lhs.emplace(entt::entity{3});
-    lhs.emplace(entt::entity{4});
-    lhs.emplace(entt::entity{5});
-
-    ASSERT_EQ(lhs.index(entt::entity{1}), 0u);
-    ASSERT_EQ(lhs.index(entt::entity{2}), 1u);
-    ASSERT_EQ(lhs.index(entt::entity{3}), 2u);
-    ASSERT_EQ(lhs.index(entt::entity{4}), 3u);
-    ASSERT_EQ(lhs.index(entt::entity{5}), 4u);
-
-    rhs.emplace(entt::entity{5});
-    rhs.emplace(entt::entity{4});
-    rhs.emplace(entt::entity{3});
-    rhs.emplace(entt::entity{2});
-    rhs.emplace(entt::entity{1});
-    rhs.emplace(entt::entity{6});
-
-    ASSERT_EQ(rhs.index(entt::entity{5}), 0u);
-    ASSERT_EQ(rhs.index(entt::entity{4}), 1u);
-    ASSERT_EQ(rhs.index(entt::entity{3}), 2u);
-    ASSERT_EQ(rhs.index(entt::entity{2}), 3u);
-    ASSERT_EQ(rhs.index(entt::entity{1}), 4u);
-    ASSERT_EQ(rhs.index(entt::entity{6}), 5u);
+    entt::entity lhs_entities[5u]{entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
+    lhs.insert(std::begin(lhs_entities), std::end(lhs_entities));
+
+    entt::entity rhs_entities[6u]{entt::entity{5}, entt::entity{4}, entt::entity{3}, entt::entity{2}, entt::entity{1}, entt::entity{6}};
+    rhs.insert(std::begin(rhs_entities), std::end(rhs_entities));
+
+    ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.begin(), lhs.end()));
+    ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.begin(), rhs.end()));
 
     rhs.respect(lhs);
 
-    ASSERT_EQ(rhs.index(entt::entity{6}), 0u);
-    ASSERT_EQ(rhs.index(entt::entity{1}), 1u);
-    ASSERT_EQ(rhs.index(entt::entity{2}), 2u);
-    ASSERT_EQ(rhs.index(entt::entity{3}), 3u);
-    ASSERT_EQ(rhs.index(entt::entity{4}), 4u);
-    ASSERT_EQ(rhs.index(entt::entity{5}), 5u);
+    auto begin = rhs.begin();
+    auto end = rhs.end();
+
+    ASSERT_EQ(*(begin++), entt::entity{5});
+    ASSERT_EQ(*(begin++), entt::entity{4});
+    ASSERT_EQ(*(begin++), entt::entity{3});
+    ASSERT_EQ(*(begin++), entt::entity{2});
+    ASSERT_EQ(*(begin++), entt::entity{1});
+    ASSERT_EQ(*(begin++), entt::entity{6});
+    ASSERT_EQ(begin, end);
 }
 
 TEST(SparseSet, RespectUnordered) {
     entt::sparse_set lhs;
     entt::sparse_set rhs;
 
-    lhs.emplace(entt::entity{1});
-    lhs.emplace(entt::entity{2});
-    lhs.emplace(entt::entity{3});
-    lhs.emplace(entt::entity{4});
-    lhs.emplace(entt::entity{5});
-
-    ASSERT_EQ(lhs.index(entt::entity{1}), 0u);
-    ASSERT_EQ(lhs.index(entt::entity{2}), 1u);
-    ASSERT_EQ(lhs.index(entt::entity{3}), 2u);
-    ASSERT_EQ(lhs.index(entt::entity{4}), 3u);
-    ASSERT_EQ(lhs.index(entt::entity{5}), 4u);
-
-    rhs.emplace(entt::entity{3});
-    rhs.emplace(entt::entity{2});
-    rhs.emplace(entt::entity{6});
-    rhs.emplace(entt::entity{1});
-    rhs.emplace(entt::entity{4});
-    rhs.emplace(entt::entity{5});
-
-    ASSERT_EQ(rhs.index(entt::entity{3}), 0u);
-    ASSERT_EQ(rhs.index(entt::entity{2}), 1u);
-    ASSERT_EQ(rhs.index(entt::entity{6}), 2u);
-    ASSERT_EQ(rhs.index(entt::entity{1}), 3u);
-    ASSERT_EQ(rhs.index(entt::entity{4}), 4u);
-    ASSERT_EQ(rhs.index(entt::entity{5}), 5u);
+    entt::entity lhs_entities[5u]{entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
+    lhs.insert(std::begin(lhs_entities), std::end(lhs_entities));
+
+    entt::entity rhs_entities[6u]{entt::entity{3}, entt::entity{2}, entt::entity{6}, entt::entity{1}, entt::entity{4}, entt::entity{5}};
+    rhs.insert(std::begin(rhs_entities), std::end(rhs_entities));
+
+    ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.begin(), lhs.end()));
+    ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.begin(), rhs.end()));
 
     rhs.respect(lhs);
 
-    ASSERT_EQ(rhs.index(entt::entity{6}), 0u);
-    ASSERT_EQ(rhs.index(entt::entity{1}), 1u);
-    ASSERT_EQ(rhs.index(entt::entity{2}), 2u);
-    ASSERT_EQ(rhs.index(entt::entity{3}), 3u);
-    ASSERT_EQ(rhs.index(entt::entity{4}), 4u);
-    ASSERT_EQ(rhs.index(entt::entity{5}), 5u);
+    auto begin = rhs.begin();
+    auto end = rhs.end();
+
+    ASSERT_EQ(*(begin++), entt::entity{5});
+    ASSERT_EQ(*(begin++), entt::entity{4});
+    ASSERT_EQ(*(begin++), entt::entity{3});
+    ASSERT_EQ(*(begin++), entt::entity{2});
+    ASSERT_EQ(*(begin++), entt::entity{1});
+    ASSERT_EQ(*(begin++), entt::entity{6});
+    ASSERT_EQ(begin, end);
 }
 
 TEST(SparseSet, CanModifyDuringIteration) {

+ 162 - 303
test/entt/entity/storage.cpp

@@ -11,6 +11,10 @@
 struct empty_type {};
 struct boxed_int { int value; };
 
+bool operator==(const boxed_int &lhs, const boxed_int &rhs) {
+    return lhs.value == rhs.value;
+}
+
 struct throwing_component {
     struct constructor_exception: std::exception {};
 
@@ -342,249 +346,136 @@ TEST(Storage, Raw) {
     ASSERT_EQ(std::as_const(pool).get(entt::entity{12}), 6);
     ASSERT_EQ(pool.get(entt::entity{42}), 9);
 
-    ASSERT_EQ(*(pool.raw() + 0u), 3);
-    ASSERT_EQ(*(std::as_const(pool).raw() + 1u), 6);
-    ASSERT_EQ(*(pool.raw() + 2u), 9);
+    ASSERT_EQ(pool.raw()[0u], 3);
+    ASSERT_EQ(std::as_const(pool).raw()[1u], 6);
+    ASSERT_EQ(pool.raw()[2u], 9);
 }
 
 TEST(Storage, SortOrdered) {
     entt::storage<boxed_int> pool;
+    entt::entity entities[5u]{entt::entity{12}, entt::entity{42}, entt::entity{7}, entt::entity{3}, entt::entity{9}};
+    boxed_int values[5u]{12, 9, 6, 3, 1};
 
-    pool.emplace(entt::entity{12}, boxed_int{12});
-    pool.emplace(entt::entity{42}, boxed_int{9});
-    pool.emplace(entt::entity{7}, boxed_int{6});
-    pool.emplace(entt::entity{3}, boxed_int{3});
-    pool.emplace(entt::entity{9}, boxed_int{1});
-
-    ASSERT_EQ(pool.get(entt::entity{12}).value, 12);
-    ASSERT_EQ(pool.get(entt::entity{42}).value, 9);
-    ASSERT_EQ(pool.get(entt::entity{7}).value, 6);
-    ASSERT_EQ(pool.get(entt::entity{3}).value, 3);
-    ASSERT_EQ(pool.get(entt::entity{9}).value, 1);
-
-    pool.sort(pool.begin(), pool.end(), [](auto lhs, auto rhs) {
-        return lhs.value < rhs.value;
-    });
-
-    ASSERT_EQ(pool.index(entt::entity{12}), 0u);
-    ASSERT_EQ(pool.index(entt::entity{42}), 1u);
-    ASSERT_EQ(pool.index(entt::entity{7}), 2u);
-    ASSERT_EQ(pool.index(entt::entity{3}), 3u);
-    ASSERT_EQ(pool.index(entt::entity{9}), 4u);
-
-    ASSERT_EQ((pool.raw() + 0u)->value, 12);
-    ASSERT_EQ((pool.raw() + 1u)->value, 9);
-    ASSERT_EQ((pool.raw() + 2u)->value, 6);
-    ASSERT_EQ((pool.raw() + 3u)->value, 3);
-    ASSERT_EQ((pool.raw() + 4u)->value, 1);
-
-    auto begin = pool.begin();
-    auto end = pool.end();
+    pool.insert(std::begin(entities), std::end(entities), std::begin(values), std::end(values));
+    pool.sort([](auto lhs, auto rhs) { return lhs.value < rhs.value; });
 
-    ASSERT_EQ((begin++)->value, 1);
-    ASSERT_EQ((begin++)->value, 3);
-    ASSERT_EQ((begin++)->value, 6);
-    ASSERT_EQ((begin++)->value, 9);
-    ASSERT_EQ((begin++)->value, 12);
-    ASSERT_EQ(begin, end);
+    ASSERT_TRUE(std::equal(std::rbegin(entities), std::rend(entities), pool.entt::sparse_set::begin(), pool.entt::sparse_set::end()));
+    ASSERT_TRUE(std::equal(std::rbegin(values), std::rend(values), pool.begin(), pool.end()));
 }
 
 TEST(Storage, SortReverse) {
     entt::storage<boxed_int> pool;
+    entt::entity entities[5u]{entt::entity{12}, entt::entity{42}, entt::entity{7}, entt::entity{3}, entt::entity{9}};
+    boxed_int values[5u]{1, 3, 6, 9, 12};
 
-    pool.emplace(entt::entity{12}, boxed_int{1});
-    pool.emplace(entt::entity{42}, boxed_int{3});
-    pool.emplace(entt::entity{7}, boxed_int{6});
-    pool.emplace(entt::entity{3}, boxed_int{9});
-    pool.emplace(entt::entity{9}, boxed_int{12});
-
-    ASSERT_EQ(pool.get(entt::entity{12}).value, 1);
-    ASSERT_EQ(pool.get(entt::entity{42}).value, 3);
-    ASSERT_EQ(pool.get(entt::entity{7}).value, 6);
-    ASSERT_EQ(pool.get(entt::entity{3}).value, 9);
-    ASSERT_EQ(pool.get(entt::entity{9}).value, 12);
-
-    pool.sort(pool.begin(), pool.end(), [&pool](entt::entity lhs, entt::entity rhs) {
-        return pool.get(lhs).value < pool.get(rhs).value;
-    });
-
-    ASSERT_EQ(pool.index(entt::entity{9}), 0u);
-    ASSERT_EQ(pool.index(entt::entity{3}), 1u);
-    ASSERT_EQ(pool.index(entt::entity{7}), 2u);
-    ASSERT_EQ(pool.index(entt::entity{42}), 3u);
-    ASSERT_EQ(pool.index(entt::entity{12}), 4u);
-
-    ASSERT_EQ((pool.raw() + 0u)->value, 12);
-    ASSERT_EQ((pool.raw() + 1u)->value, 9);
-    ASSERT_EQ((pool.raw() + 2u)->value, 6);
-    ASSERT_EQ((pool.raw() + 3u)->value, 3);
-    ASSERT_EQ((pool.raw() + 4u)->value, 1);
+    pool.insert(std::begin(entities), std::end(entities), std::begin(values), std::end(values));
+    pool.sort([](auto lhs, auto rhs) { return lhs.value < rhs.value; });
 
-    auto begin = pool.begin();
-    auto end = pool.end();
-
-    ASSERT_EQ((begin++)->value, 1);
-    ASSERT_EQ((begin++)->value, 3);
-    ASSERT_EQ((begin++)->value, 6);
-    ASSERT_EQ((begin++)->value, 9);
-    ASSERT_EQ((begin++)->value, 12);
-    ASSERT_EQ(begin, end);
+    ASSERT_TRUE(std::equal(std::begin(entities), std::end(entities), pool.entt::sparse_set::begin(), pool.entt::sparse_set::end()));
+    ASSERT_TRUE(std::equal(std::begin(values), std::end(values), pool.begin(), pool.end()));
 }
 
 TEST(Storage, SortUnordered) {
     entt::storage<boxed_int> pool;
+    entt::entity entities[5u]{entt::entity{12}, entt::entity{42}, entt::entity{7}, entt::entity{3}, entt::entity{9}};
+    boxed_int values[5u]{6, 3, 1, 9, 12};
 
-    pool.emplace(entt::entity{12}, boxed_int{6});
-    pool.emplace(entt::entity{42}, boxed_int{3});
-    pool.emplace(entt::entity{7}, boxed_int{1});
-    pool.emplace(entt::entity{3}, boxed_int{9});
-    pool.emplace(entt::entity{9}, boxed_int{12});
-
-    ASSERT_EQ(pool.get(entt::entity{12}).value, 6);
-    ASSERT_EQ(pool.get(entt::entity{42}).value, 3);
-    ASSERT_EQ(pool.get(entt::entity{7}).value, 1);
-    ASSERT_EQ(pool.get(entt::entity{3}).value, 9);
-    ASSERT_EQ(pool.get(entt::entity{9}).value, 12);
-
-    pool.sort(pool.begin(), pool.end(), [](auto lhs, auto rhs) {
-        return lhs.value < rhs.value;
-    });
-
-    ASSERT_EQ(pool.index(entt::entity{9}), 0u);
-    ASSERT_EQ(pool.index(entt::entity{3}), 1u);
-    ASSERT_EQ(pool.index(entt::entity{12}), 2u);
-    ASSERT_EQ(pool.index(entt::entity{42}), 3u);
-    ASSERT_EQ(pool.index(entt::entity{7}), 4u);
-
-    ASSERT_EQ((pool.raw() + 0u)->value, 12);
-    ASSERT_EQ((pool.raw() + 1u)->value, 9);
-    ASSERT_EQ((pool.raw() + 2u)->value, 6);
-    ASSERT_EQ((pool.raw() + 3u)->value, 3);
-    ASSERT_EQ((pool.raw() + 4u)->value, 1);
+    pool.insert(std::begin(entities), std::end(entities), std::begin(values), std::end(values));
+    pool.sort([](auto lhs, auto rhs) { return lhs.value < rhs.value; });
 
     auto begin = pool.begin();
     auto end = pool.end();
 
-    ASSERT_EQ((begin++)->value, 1);
-    ASSERT_EQ((begin++)->value, 3);
-    ASSERT_EQ((begin++)->value, 6);
-    ASSERT_EQ((begin++)->value, 9);
-    ASSERT_EQ((begin++)->value, 12);
+    ASSERT_EQ(*(begin++), boxed_int{1});
+    ASSERT_EQ(*(begin++), boxed_int{3});
+    ASSERT_EQ(*(begin++), boxed_int{6});
+    ASSERT_EQ(*(begin++), boxed_int{9});
+    ASSERT_EQ(*(begin++), boxed_int{12});
     ASSERT_EQ(begin, end);
+
+    ASSERT_EQ(pool.data()[0u], entt::entity{9});
+    ASSERT_EQ(pool.data()[1u], entt::entity{3});
+    ASSERT_EQ(pool.data()[2u], entt::entity{12});
+    ASSERT_EQ(pool.data()[3u], entt::entity{42});
+    ASSERT_EQ(pool.data()[4u], entt::entity{7});
 }
 
 TEST(Storage, SortRange) {
     entt::storage<boxed_int> pool;
+    entt::entity entities[5u]{entt::entity{12}, entt::entity{42}, entt::entity{7}, entt::entity{3}, entt::entity{9}};
+    boxed_int values[5u]{3, 6, 1, 9, 12};
+
+    pool.insert(std::begin(entities), std::end(entities), std::begin(values), std::end(values));
+    pool.sort_n(0u, [](auto lhs, auto rhs) { return lhs.value < rhs.value; });
 
-    pool.emplace(entt::entity{12}, boxed_int{6});
-    pool.emplace(entt::entity{42}, boxed_int{3});
-    pool.emplace(entt::entity{7}, boxed_int{1});
-    pool.emplace(entt::entity{3}, boxed_int{9});
-    pool.emplace(entt::entity{9}, boxed_int{12});
-
-    ASSERT_EQ(pool.get(entt::entity{12}).value, 6);
-    ASSERT_EQ(pool.get(entt::entity{42}).value, 3);
-    ASSERT_EQ(pool.get(entt::entity{7}).value, 1);
-    ASSERT_EQ(pool.get(entt::entity{3}).value, 9);
-    ASSERT_EQ(pool.get(entt::entity{9}).value, 12);
-
-    pool.sort(pool.end(), pool.end(), std::less{});
-
-    ASSERT_EQ(pool.get(entt::entity{12}).value, 6);
-    ASSERT_EQ(pool.get(entt::entity{42}).value, 3);
-    ASSERT_EQ(pool.get(entt::entity{7}).value, 1);
-    ASSERT_EQ(pool.get(entt::entity{3}).value, 9);
-    ASSERT_EQ(pool.get(entt::entity{9}).value, 12);
-
-    pool.sort(pool.begin(), pool.begin(), std::less{});
-
-    ASSERT_EQ(pool.get(entt::entity{12}).value, 6);
-    ASSERT_EQ(pool.get(entt::entity{42}).value, 3);
-    ASSERT_EQ(pool.get(entt::entity{7}).value, 1);
-    ASSERT_EQ(pool.get(entt::entity{3}).value, 9);
-    ASSERT_EQ(pool.get(entt::entity{9}).value, 12);
-
-    pool.sort(pool.begin()+2, pool.begin()+3, std::less{});
-
-    ASSERT_EQ(pool.get(entt::entity{12}).value, 6);
-    ASSERT_EQ(pool.get(entt::entity{42}).value, 3);
-    ASSERT_EQ(pool.get(entt::entity{7}).value, 1);
-    ASSERT_EQ(pool.get(entt::entity{3}).value, 9);
-    ASSERT_EQ(pool.get(entt::entity{9}).value, 12);
-
-    pool.sort(++pool.begin(), --pool.end(), [](auto lhs, auto rhs) {
-        return lhs.value < rhs.value;
-    });
-
-    ASSERT_EQ(pool.index(entt::entity{12}), 0u);
-    ASSERT_EQ(pool.index(entt::entity{3}), 1u);
-    ASSERT_EQ(pool.index(entt::entity{42}), 2u);
-    ASSERT_EQ(pool.index(entt::entity{7}), 3u);
-    ASSERT_EQ(pool.index(entt::entity{9}), 4u);
-
-    ASSERT_EQ((pool.raw() + 0u)->value, 6);
-    ASSERT_EQ((pool.raw() + 1u)->value, 9);
-    ASSERT_EQ((pool.raw() + 2u)->value, 3);
-    ASSERT_EQ((pool.raw() + 3u)->value, 1);
-    ASSERT_EQ((pool.raw() + 4u)->value, 12);
+    ASSERT_TRUE(std::equal(std::rbegin(entities), std::rend(entities), pool.entt::sparse_set::begin(), pool.entt::sparse_set::end()));
+    ASSERT_TRUE(std::equal(std::rbegin(values), std::rend(values), pool.begin(), pool.end()));
+
+    pool.sort_n(2u, [](auto lhs, auto rhs) { return lhs.value < rhs.value; });
+
+    ASSERT_EQ(pool.raw()[0u], boxed_int{6});
+    ASSERT_EQ(pool.raw()[1u], boxed_int{3});
+    ASSERT_EQ(pool.raw()[2u], boxed_int{1});
+
+    ASSERT_EQ(pool.data()[0u], entt::entity{42});
+    ASSERT_EQ(pool.data()[1u], entt::entity{12});
+    ASSERT_EQ(pool.data()[2u], entt::entity{7});
+
+    pool.sort_n(5u, [](auto lhs, auto rhs) { return lhs.value < rhs.value; });
 
     auto begin = pool.begin();
     auto end = pool.end();
 
-    ASSERT_EQ((begin++)->value, 12);
-    ASSERT_EQ((begin++)->value, 1);
-    ASSERT_EQ((begin++)->value, 3);
-    ASSERT_EQ((begin++)->value, 9);
-    ASSERT_EQ((begin++)->value, 6);
+    ASSERT_EQ(*(begin++), boxed_int{1});
+    ASSERT_EQ(*(begin++), boxed_int{3});
+    ASSERT_EQ(*(begin++), boxed_int{6});
+    ASSERT_EQ(*(begin++), boxed_int{9});
+    ASSERT_EQ(*(begin++), boxed_int{12});
     ASSERT_EQ(begin, end);
+
+    ASSERT_EQ(pool.data()[0u], entt::entity{9});
+    ASSERT_EQ(pool.data()[1u], entt::entity{3});
+    ASSERT_EQ(pool.data()[2u], entt::entity{42});
+    ASSERT_EQ(pool.data()[3u], entt::entity{12});
+    ASSERT_EQ(pool.data()[4u], entt::entity{7});
 }
 
 TEST(Storage, RespectDisjoint) {
     entt::storage<int> lhs;
     entt::storage<int> rhs;
 
-    lhs.emplace(entt::entity{3}, 3);
-    lhs.emplace(entt::entity{12}, 6);
-    lhs.emplace(entt::entity{42}, 9);
+    entt::entity lhs_entities[3u]{entt::entity{3}, entt::entity{12}, entt::entity{42}};
+    int lhs_values[3u]{3, 6, 9};
+    lhs.insert(std::begin(lhs_entities), std::end(lhs_entities), std::begin(lhs_values), std::end(lhs_values));
 
-    ASSERT_EQ(std::as_const(lhs).get(entt::entity{3}), 3);
-    ASSERT_EQ(std::as_const(lhs).get(entt::entity{12}), 6);
-    ASSERT_EQ(std::as_const(lhs).get(entt::entity{42}), 9);
+    ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
+    ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
 
     lhs.respect(rhs);
 
-    ASSERT_EQ(*(std::as_const(lhs).raw() + 0u), 3);
-    ASSERT_EQ(*(std::as_const(lhs).raw() + 1u), 6);
-    ASSERT_EQ(*(std::as_const(lhs).raw() + 2u), 9);
-
-    auto begin = lhs.begin();
-    auto end = lhs.end();
-
-    ASSERT_EQ(*(begin++), 9);
-    ASSERT_EQ(*(begin++), 6);
-    ASSERT_EQ(*(begin++), 3);
-    ASSERT_EQ(begin, end);
+    ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
+    ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
 }
 
 TEST(Storage, RespectOverlap) {
     entt::storage<int> lhs;
     entt::storage<int> rhs;
 
-    lhs.emplace(entt::entity{3}, 3);
-    lhs.emplace(entt::entity{12}, 6);
-    lhs.emplace(entt::entity{42}, 9);
-    rhs.emplace(entt::entity{12}, 6);
+    entt::entity lhs_entities[3u]{entt::entity{3}, entt::entity{12}, entt::entity{42}};
+    int lhs_values[3u]{3, 6, 9};
+    lhs.insert(std::begin(lhs_entities), std::end(lhs_entities), std::begin(lhs_values), std::end(lhs_values));
 
-    ASSERT_EQ(std::as_const(lhs).get(entt::entity{3}), 3);
-    ASSERT_EQ(std::as_const(lhs).get(entt::entity{12}), 6);
-    ASSERT_EQ(std::as_const(lhs).get(entt::entity{42}), 9);
-    ASSERT_EQ(rhs.get(entt::entity{12}), 6);
+    entt::entity rhs_entities[1u]{entt::entity{12}};
+    int rhs_values[1u]{6};
+    rhs.insert(std::begin(rhs_entities), std::end(rhs_entities), std::begin(rhs_values), std::end(rhs_values));
 
-    lhs.respect(rhs);
+    ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
+    ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
+
+    ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
+    ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
 
-    ASSERT_EQ(*(std::as_const(lhs).raw() + 0u), 3);
-    ASSERT_EQ(*(std::as_const(lhs).raw() + 1u), 9);
-    ASSERT_EQ(*(std::as_const(lhs).raw() + 2u), 6);
+    lhs.respect(rhs);
 
     auto begin = lhs.begin();
     auto end = lhs.end();
@@ -593,144 +484,112 @@ TEST(Storage, RespectOverlap) {
     ASSERT_EQ(*(begin++), 9);
     ASSERT_EQ(*(begin++), 3);
     ASSERT_EQ(begin, end);
+
+    ASSERT_EQ(lhs.data()[0u], entt::entity{3});
+    ASSERT_EQ(lhs.data()[1u], entt::entity{42});
+    ASSERT_EQ(lhs.data()[2u], entt::entity{12});
 }
 
 TEST(Storage, RespectOrdered) {
     entt::storage<int> lhs;
     entt::storage<int> rhs;
 
-    lhs.emplace(entt::entity{1}, 0);
-    lhs.emplace(entt::entity{2}, 0);
-    lhs.emplace(entt::entity{3}, 0);
-    lhs.emplace(entt::entity{4}, 0);
-    lhs.emplace(entt::entity{5}, 0);
-
-    ASSERT_EQ(lhs.get(entt::entity{1}), 0);
-    ASSERT_EQ(lhs.get(entt::entity{2}), 0);
-    ASSERT_EQ(lhs.get(entt::entity{3}), 0);
-    ASSERT_EQ(lhs.get(entt::entity{4}), 0);
-    ASSERT_EQ(lhs.get(entt::entity{5}), 0);
-
-    rhs.emplace(entt::entity{6}, 0);
-    rhs.emplace(entt::entity{1}, 0);
-    rhs.emplace(entt::entity{2}, 0);
-    rhs.emplace(entt::entity{3}, 0);
-    rhs.emplace(entt::entity{4}, 0);
-    rhs.emplace(entt::entity{5}, 0);
-
-    ASSERT_EQ(rhs.get(entt::entity{6}), 0);
-    ASSERT_EQ(rhs.get(entt::entity{1}), 0);
-    ASSERT_EQ(rhs.get(entt::entity{2}), 0);
-    ASSERT_EQ(rhs.get(entt::entity{3}), 0);
-    ASSERT_EQ(rhs.get(entt::entity{4}), 0);
-    ASSERT_EQ(rhs.get(entt::entity{5}), 0);
+    entt::entity lhs_entities[5u]{entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
+    int lhs_values[5u]{1, 2, 3, 4, 5};
+    lhs.insert(std::begin(lhs_entities), std::end(lhs_entities), std::begin(lhs_values), std::end(lhs_values));
+
+    entt::entity rhs_entities[6u]{entt::entity{6}, entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
+    int rhs_values[6u]{6, 1, 2, 3, 4, 5};
+    rhs.insert(std::begin(rhs_entities), std::end(rhs_entities), std::begin(rhs_values), std::end(rhs_values));
+
+    ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
+    ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
+
+    ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
+    ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
 
     rhs.respect(lhs);
 
-    ASSERT_EQ(*(lhs.data() + 0u), entt::entity{1});
-    ASSERT_EQ(*(lhs.data() + 1u), entt::entity{2});
-    ASSERT_EQ(*(lhs.data() + 2u), entt::entity{3});
-    ASSERT_EQ(*(lhs.data() + 3u), entt::entity{4});
-    ASSERT_EQ(*(lhs.data() + 4u), entt::entity{5});
-
-    ASSERT_EQ(*(rhs.data() + 0u), entt::entity{6});
-    ASSERT_EQ(*(rhs.data() + 1u), entt::entity{1});
-    ASSERT_EQ(*(rhs.data() + 2u), entt::entity{2});
-    ASSERT_EQ(*(rhs.data() + 3u), entt::entity{3});
-    ASSERT_EQ(*(rhs.data() + 4u), entt::entity{4});
-    ASSERT_EQ(*(rhs.data() + 5u), entt::entity{5});
+    ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
+    ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
 }
 
 TEST(Storage, RespectReverse) {
     entt::storage<int> lhs;
     entt::storage<int> rhs;
 
-    lhs.emplace(entt::entity{1}, 0);
-    lhs.emplace(entt::entity{2}, 0);
-    lhs.emplace(entt::entity{3}, 0);
-    lhs.emplace(entt::entity{4}, 0);
-    lhs.emplace(entt::entity{5}, 0);
-
-    ASSERT_EQ(lhs.get(entt::entity{1}), 0);
-    ASSERT_EQ(lhs.get(entt::entity{2}), 0);
-    ASSERT_EQ(lhs.get(entt::entity{3}), 0);
-    ASSERT_EQ(lhs.get(entt::entity{4}), 0);
-    ASSERT_EQ(lhs.get(entt::entity{5}), 0);
-
-    rhs.emplace(entt::entity{5}, 0);
-    rhs.emplace(entt::entity{4}, 0);
-    rhs.emplace(entt::entity{3}, 0);
-    rhs.emplace(entt::entity{2}, 0);
-    rhs.emplace(entt::entity{1}, 0);
-    rhs.emplace(entt::entity{6}, 0);
-
-    ASSERT_EQ(rhs.get(entt::entity{5}), 0);
-    ASSERT_EQ(rhs.get(entt::entity{4}), 0);
-    ASSERT_EQ(rhs.get(entt::entity{3}), 0);
-    ASSERT_EQ(rhs.get(entt::entity{2}), 0);
-    ASSERT_EQ(rhs.get(entt::entity{1}), 0);
-    ASSERT_EQ(rhs.get(entt::entity{6}), 0);
+    entt::entity lhs_entities[5u]{entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
+    int lhs_values[5u]{1, 2, 3, 4, 5};
+    lhs.insert(std::begin(lhs_entities), std::end(lhs_entities), std::begin(lhs_values), std::end(lhs_values));
+
+    entt::entity rhs_entities[6u]{entt::entity{5}, entt::entity{4}, entt::entity{3}, entt::entity{2}, entt::entity{1}, entt::entity{6}};
+    int rhs_values[6u]{5, 4, 3, 2, 1, 6};
+    rhs.insert(std::begin(rhs_entities), std::end(rhs_entities), std::begin(rhs_values), std::end(rhs_values));
+
+    ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
+    ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
+
+    ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
+    ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
 
     rhs.respect(lhs);
 
-    ASSERT_EQ(*(lhs.data() + 0u), entt::entity{1});
-    ASSERT_EQ(*(lhs.data() + 1u), entt::entity{2});
-    ASSERT_EQ(*(lhs.data() + 2u), entt::entity{3});
-    ASSERT_EQ(*(lhs.data() + 3u), entt::entity{4});
-    ASSERT_EQ(*(lhs.data() + 4u), entt::entity{5});
-
-    ASSERT_EQ(*(rhs.data() + 0u), entt::entity{6});
-    ASSERT_EQ(*(rhs.data() + 1u), entt::entity{1});
-    ASSERT_EQ(*(rhs.data() + 2u), entt::entity{2});
-    ASSERT_EQ(*(rhs.data() + 3u), entt::entity{3});
-    ASSERT_EQ(*(rhs.data() + 4u), entt::entity{4});
-    ASSERT_EQ(*(rhs.data() + 5u), entt::entity{5});
+    auto begin = rhs.begin();
+    auto end = rhs.end();
+
+    ASSERT_EQ(*(begin++), 5);
+    ASSERT_EQ(*(begin++), 4);
+    ASSERT_EQ(*(begin++), 3);
+    ASSERT_EQ(*(begin++), 2);
+    ASSERT_EQ(*(begin++), 1);
+    ASSERT_EQ(*(begin++), 6);
+    ASSERT_EQ(begin, end);
+
+    ASSERT_EQ(rhs.data()[0u], entt::entity{6});
+    ASSERT_EQ(rhs.data()[1u], entt::entity{1});
+    ASSERT_EQ(rhs.data()[2u], entt::entity{2});
+    ASSERT_EQ(rhs.data()[3u], entt::entity{3});
+    ASSERT_EQ(rhs.data()[4u], entt::entity{4});
+    ASSERT_EQ(rhs.data()[5u], entt::entity{5});
 }
 
 TEST(Storage, RespectUnordered) {
     entt::storage<int> lhs;
     entt::storage<int> rhs;
 
-    lhs.emplace(entt::entity{1}, 0);
-    lhs.emplace(entt::entity{2}, 0);
-    lhs.emplace(entt::entity{3}, 0);
-    lhs.emplace(entt::entity{4}, 0);
-    lhs.emplace(entt::entity{5}, 0);
-
-    ASSERT_EQ(lhs.get(entt::entity{1}), 0);
-    ASSERT_EQ(lhs.get(entt::entity{2}), 0);
-    ASSERT_EQ(lhs.get(entt::entity{3}), 0);
-    ASSERT_EQ(lhs.get(entt::entity{4}), 0);
-    ASSERT_EQ(lhs.get(entt::entity{5}), 0);
-
-    rhs.emplace(entt::entity{3}, 0);
-    rhs.emplace(entt::entity{2}, 0);
-    rhs.emplace(entt::entity{6}, 0);
-    rhs.emplace(entt::entity{1}, 0);
-    rhs.emplace(entt::entity{4}, 0);
-    rhs.emplace(entt::entity{5}, 0);
-
-    ASSERT_EQ(rhs.get(entt::entity{3}), 0);
-    ASSERT_EQ(rhs.get(entt::entity{2}), 0);
-    ASSERT_EQ(rhs.get(entt::entity{6}), 0);
-    ASSERT_EQ(rhs.get(entt::entity{1}), 0);
-    ASSERT_EQ(rhs.get(entt::entity{4}), 0);
-    ASSERT_EQ(rhs.get(entt::entity{5}), 0);
+    entt::entity lhs_entities[5u]{entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
+    int lhs_values[5u]{1, 2, 3, 4, 5};
+    lhs.insert(std::begin(lhs_entities), std::end(lhs_entities), std::begin(lhs_values), std::end(lhs_values));
+
+    entt::entity rhs_entities[6u]{entt::entity{3}, entt::entity{2}, entt::entity{6}, entt::entity{1}, entt::entity{4}, entt::entity{5}};
+    int rhs_values[6u]{3, 2, 6, 1, 4, 5};
+    rhs.insert(std::begin(rhs_entities), std::end(rhs_entities), std::begin(rhs_values), std::end(rhs_values));
+
+    ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
+    ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
+
+    ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
+    ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
 
     rhs.respect(lhs);
 
-    ASSERT_EQ(*(lhs.data() + 0u), entt::entity{1});
-    ASSERT_EQ(*(lhs.data() + 1u), entt::entity{2});
-    ASSERT_EQ(*(lhs.data() + 2u), entt::entity{3});
-    ASSERT_EQ(*(lhs.data() + 3u), entt::entity{4});
-    ASSERT_EQ(*(lhs.data() + 4u), entt::entity{5});
-
-    ASSERT_EQ(*(rhs.data() + 0u), entt::entity{6});
-    ASSERT_EQ(*(rhs.data() + 1u), entt::entity{1});
-    ASSERT_EQ(*(rhs.data() + 2u), entt::entity{2});
-    ASSERT_EQ(*(rhs.data() + 3u), entt::entity{3});
-    ASSERT_EQ(*(rhs.data() + 4u), entt::entity{4});
-    ASSERT_EQ(*(rhs.data() + 5u), entt::entity{5});
+    auto begin = rhs.begin();
+    auto end = rhs.end();
+
+    ASSERT_EQ(*(begin++), 5);
+    ASSERT_EQ(*(begin++), 4);
+    ASSERT_EQ(*(begin++), 3);
+    ASSERT_EQ(*(begin++), 2);
+    ASSERT_EQ(*(begin++), 1);
+    ASSERT_EQ(*(begin++), 6);
+    ASSERT_EQ(begin, end);
+
+    ASSERT_EQ(rhs.data()[0u], entt::entity{6});
+    ASSERT_EQ(rhs.data()[1u], entt::entity{1});
+    ASSERT_EQ(rhs.data()[2u], entt::entity{2});
+    ASSERT_EQ(rhs.data()[3u], entt::entity{3});
+    ASSERT_EQ(rhs.data()[4u], entt::entity{4});
+    ASSERT_EQ(rhs.data()[5u], entt::entity{5});
 }
 
 TEST(Storage, CanModifyDuringIteration) {