Browse Source

is now possible to sort non-owning groups using a custom comparison function

Michele Caini 6 years ago
parent
commit
87d901b1ae

+ 1 - 3
TODO

@@ -17,13 +17,11 @@
 * add take functionality, eg registry.take(entity, other); where it takes the entity and all its components from registry and move them to other
 * add opaque input iterators to views and groups that return tuples <entity, T &...> (proxy), multi-pass guaranteed
 * add fast lane for raw iterations, extend mt doc to describe allowed add/remove with pre-allocations on fast lanes
+* registry.each<T...>(first, last) by iterators, entities/components guaranteed
 * multi component registry::remove and some others?
 * can I use opaque connection also for the emitter?
 * built-in support for dual (or N-) buffering
 * meta: opaque references and pointers
 
 TODO
-* add sort by type to the non-owning group
 * custom (decoupled) pools ==> double buffering, shared components, multi-model
-* registry.each<T...>(first, last) by iterators, entities/components guaranteed
-* non-owning groups shouldn't store entities, but positions => optimized each

+ 62 - 3
src/entt/entity/group.hpp

@@ -384,6 +384,64 @@ public:
         traverse(std::move(func), type_list_cat_t<get_type_list, other_type_list>{});
     }
 
+    /**
+     * @brief Sort a group according to the given comparison function.
+     *
+     * Sort the group so that iterating it with a couple of iterators returns
+     * entities and components 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:
+     *
+     * @code{.cpp}
+     * bool(std::tuple<Component &...>, std::tuple<Component &...>);
+     * bool(const Component &..., const Component &...);
+     * bool(const Entity, const Entity);
+     * @endcode
+     *
+     * Where `Component` are such that they are iterated by the group.<br/>
+     * Moreover, the comparison function object shall induce a
+     * _strict weak ordering_ on the values.
+     *
+     * The sort function oject must offer a member function template
+     * `operator()` that accepts three arguments:
+     *
+     * * An iterator to the first element of the range to sort.
+     * * An iterator past the last element of the range to sort.
+     * * A comparison function to use to compare the elements.
+     *
+     * The comparison function object received by the sort function object
+     * hasn't necessarily the type of the one passed along with the other
+     * parameters to this member function.
+     *
+     * @note
+     * Attempting to iterate elements using a raw pointer returned by a call to
+     * either `data` or `raw` gives no guarantees on the order, even though
+     * `sort` has been invoked.
+     *
+     * @tparam Component Optional types of components to compare.
+     * @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... Component, typename Compare, typename Sort = std_sort, typename... Args>
+    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>);
+            handler->sort(handler->begin(), handler->end(), std::move(compare), 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) {
+                // useless this-> used to suppress a warning with clang
+                return compare(this->get<Component...>(lhs), this->get<Component...>(rhs));
+            }, std::move(algo), std::forward<Args>(args)...);
+        }
+    }
+
     /**
      * @brief Sort the shared pool of entities according to the given component.
      *
@@ -763,7 +821,8 @@ public:
      * comparison function should be equivalent to one of the following:
      *
      * @code{.cpp}
-     * bool(const Component &..., const Component &...);
+     * bool(std::tuple<Component &...>, std::tuple<Component &...>);
+     * bool(const Component &, const Component &);
      * bool(const Entity, const Entity);
      * @endcode
      *
@@ -804,9 +863,9 @@ public:
             static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>);
             cpool->sort(cpool->end()-*length, cpool->end(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
         } else {
-            cpool->sort(cpool->end()-*length, cpool->end(), [compare = std::move(compare), this](const entity_type lhs, const entity_type rhs) {
+            cpool->sort(cpool->end()-*length, cpool->end(), [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
                 // useless this-> used to suppress a warning with clang
-                return compare(this->get<Component>(lhs)..., this->get<Component>(rhs)...);
+                return compare(this->get<Component...>(lhs), this->get<Component...>(rhs));
             }, std::move(algo), std::forward<Args>(args)...);
         }
 

+ 4 - 4
src/entt/entity/registry.hpp

@@ -92,7 +92,7 @@ class basic_registry {
                 storage<Entity, Component>::batch(first, last);
 
                 if(!construction.empty()) {
-                    std::for_each(first, last, [&registry, this](const auto entt) {
+                    std::for_each(first, last, [this, &registry](const auto entt) {
                         construction.publish(registry, entt, Component{});
                     });
                 }
@@ -100,7 +100,7 @@ class basic_registry {
                 component = storage<Entity, Component>::batch(first, last);
 
                 if(!construction.empty()) {
-                    std::for_each(first, last, [&registry, component, this](const auto entt) mutable {
+                    std::for_each(first, last, [this, &registry, component](const auto entt) mutable {
                         construction.publish(registry, entt, *(component++));
                     });
                 }
@@ -600,7 +600,7 @@ public:
 
         available -= sz;
 
-        const auto tail = std::generate_n(first, sz, [&candidate, this]() mutable {
+        const auto tail = std::generate_n(first, sz, [this, &candidate]() mutable {
             if constexpr(sizeof...(Component) > 0) {
                 candidate = entity_type{std::max(candidate, next)};
             } else {
@@ -1219,7 +1219,7 @@ public:
     void orphans(Func func) const {
         static_assert(std::is_invocable_v<Func, entity_type>);
 
-        each([&func, this](const auto entity) {
+        each([this, &func](const auto entity) {
             if(orphan(entity)) {
                 func(entity);
             }

+ 71 - 1
src/entt/entity/sparse_set.hpp

@@ -8,8 +8,10 @@
 #include <vector>
 #include <memory>
 #include <cstddef>
+#include <numeric>
 #include <type_traits>
 #include "../config/config.h"
+#include "../core/algorithm.hpp"
 #include "entity.hpp"
 #include "fwd.hpp"
 
@@ -415,7 +417,7 @@ public:
      */
     template<typename It>
     void batch(It first, It last) {
-        std::for_each(first, last, [next = direct.size(), this](const auto entt) mutable {
+        std::for_each(first, last, [this, next = direct.size()](const auto entt) mutable {
             ENTT_ASSERT(!has(entt));
             auto [page, offset] = index(entt);
             assure(page);
@@ -470,6 +472,74 @@ public:
         std::swap(direct[lhs], direct[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 the following:
+     *
+     * @code{.cpp}
+     * bool(const Entity, const Entity);
+     * @endcode
+     *
+     * Moreover, the comparison function object shall induce a
+     * _strict weak ordering_ on the values.
+     *
+     * The sort function oject must offer a member function template
+     * `operator()` that accepts three arguments:
+     *
+     * * An iterator to the first element of the range to sort.
+     * * An iterator past the last element of the range to sort.
+     * * A comparison function to use to compare the elements.
+     *
+     * The comparison function object received by the sort function object
+     * hasn't necessarily the type of the one passed along with the other
+     * parameters to this member function.
+     *
+     * @note
+     * Attempting to iterate elements using a raw pointer returned by a call to
+     * either `data` or `raw` gives no guarantees on the order, even though
+     * `sort` has been invoked.
+     *
+     * @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 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_type first, iterator_type last, Compare compare, Sort algo = Sort{}, Args &&... args) {
+        ENTT_ASSERT(!(first > last));
+
+        std::vector<size_type> copy(last - first);
+        const auto offset = std::distance(last, end());
+        std::iota(copy.begin(), copy.end(), size_type{});
+
+        algo(copy.rbegin(), copy.rend(), [this, offset, compare = std::move(compare)](const auto lhs, const auto rhs) {
+            return compare(std::as_const(direct[lhs+offset]), std::as_const(direct[rhs+offset]));
+        }, std::forward<Args>(args)...);
+
+        for(size_type pos{}, length = copy.size(); pos < length; ++pos) {
+            auto curr = pos;
+            auto next = copy[curr];
+
+            while(curr != next) {
+                swap(copy[curr] + offset, copy[next] + offset);
+                copy[curr] = curr;
+                curr = next;
+                next = copy[curr];
+            }
+        }
+    }
+
     /**
      * @brief Sort entities according to their order in another sparse set.
      *

+ 6 - 21
src/entt/entity/storage.hpp

@@ -443,32 +443,17 @@ public:
     void sort(iterator_type first, iterator_type last, Compare compare, Sort algo = Sort{}, Args &&... args) {
         ENTT_ASSERT(!(first > last));
 
-        std::vector<size_type> copy(last - first);
-        const auto offset = std::distance(last, end());
-        std::iota(copy.begin(), copy.end(), size_type{});
+        const auto from = underlying_type::begin() + std::distance(begin(), first);
+        const auto to = from + std::distance(first, last);
 
         if constexpr(std::is_invocable_v<Compare, const object_type &, const object_type &>) {
             static_assert(!std::is_empty_v<object_type>);
 
-            algo(copy.rbegin(), copy.rend(), [this, offset, compare = std::move(compare)](const auto lhs, const auto rhs) {
-                return compare(std::as_const(instances[lhs + offset]), std::as_const(instances[rhs + offset]));
-            }, std::forward<Args>(args)...);
+            underlying_type::sort(from, to, [this, compare = std::move(compare)](const auto lhs, const auto rhs) {
+                return compare(std::as_const(instances[underlying_type::get(lhs)]), std::as_const(instances[underlying_type::get(rhs)]));
+            }, std::move(algo), std::forward<Args>(args)...);
         } else {
-            algo(copy.rbegin(), copy.rend(), [offset, compare = std::move(compare), data = underlying_type::data()](const auto lhs, const auto rhs) {
-                return compare(std::as_const(data[lhs+offset]), std::as_const(data[rhs+offset]));
-            }, std::forward<Args>(args)...);
-        }
-
-        for(size_type pos{}, length = copy.size(); pos < length; ++pos) {
-            auto curr = pos;
-            auto next = copy[curr];
-
-            while(curr != next) {
-                swap(copy[curr] + offset, copy[next] + offset);
-                copy[curr] = curr;
-                curr = next;
-                next = copy[curr];
-            }
+            underlying_type::sort(from, to, std::move(compare), std::move(algo), std::forward<Args>(args)...);
         }
     }
 

+ 2 - 2
src/entt/entity/view.hpp

@@ -177,7 +177,7 @@ class basic_view {
         auto begin = std::get<pool_type<Comp> *>(pools)->sparse_set<Entity>::begin();
 
         if constexpr(std::disjunction_v<std::is_same<Comp, Type>...>) {
-            std::for_each(begin, end, [raw = std::get<pool_type<Comp> *>(pools)->begin(), &func, this](const auto entity) mutable {
+            std::for_each(begin, end, [this, raw = std::get<pool_type<Comp> *>(pools)->begin(), &func](const auto entity) mutable {
                 auto curr = raw++;
 
                 if((std::get<pool_type<Other> *>(pools)->has(entity) && ...)) {
@@ -189,7 +189,7 @@ class basic_view {
                 }
             });
         } else {
-            std::for_each(begin, end, [&func, this](const auto entity) mutable {
+            std::for_each(begin, end, [this, &func](const auto entity) mutable {
                 if((std::get<pool_type<Other> *>(pools)->has(entity) && ...)) {
                     if constexpr(std::is_invocable_v<Func, decltype(get<Type>({}))...>) {
                         func(std::get<pool_type<Type> *>(pools)->get(entity)...);

+ 58 - 18
test/entt/entity/group.cpp

@@ -1,6 +1,7 @@
 #include <utility>
 #include <iterator>
 #include <algorithm>
+#include <type_traits>
 #include <gtest/gtest.h>
 #include <entt/entity/helper.hpp>
 #include <entt/entity/registry.hpp>
@@ -132,15 +133,8 @@ TEST(NonOwningGroup, Empty) {
     registry.assign<char>(e1);
     registry.assign<float>(e1);
 
-    for(auto entity: registry.group(entt::get<char, int, float>)) {
-        (void)entity;
-        FAIL();
-    }
-
-    for(auto entity: registry.group(entt::get<double, char, int, float>)) {
-        (void)entity;
-        FAIL();
-    }
+    ASSERT_TRUE(registry.group(entt::get<char, int, float>).empty());
+    ASSERT_TRUE(registry.group(entt::get<double, char, int, float>).empty());
 }
 
 TEST(NonOwningGroup, Each) {
@@ -177,6 +171,59 @@ TEST(NonOwningGroup, Sort) {
     const auto e1 = registry.create();
     const auto e2 = registry.create();
 
+    registry.assign<unsigned int>(e0, 0u);
+    registry.assign<unsigned int>(e1, 1u);
+    registry.assign<unsigned int>(e2, 2u);
+
+    registry.assign<int>(e0, 0);
+    registry.assign<int>(e1, 1);
+    registry.assign<int>(e2, 2);
+
+    ASSERT_EQ(*(group.raw<unsigned int>() + 0u), 0u);
+    ASSERT_EQ(*(group.raw<unsigned int>() + 1u), 1u);
+    ASSERT_EQ(*(group.raw<unsigned int>() + 2u), 2u);
+
+    ASSERT_EQ(*(group.raw<const int>() + 0u), 0);
+    ASSERT_EQ(*(group.raw<const int>() + 1u), 1);
+    ASSERT_EQ(*(group.raw<const int>() + 2u), 2);
+
+    ASSERT_EQ(*(group.data() + 0u), e0);
+    ASSERT_EQ(*(group.data() + 1u), e1);
+    ASSERT_EQ(*(group.data() + 2u), e2);
+
+    group.sort([](const entt::entity lhs, const entt::entity rhs) {
+        return std::underlying_type_t<entt::entity>(lhs) < std::underlying_type_t<entt::entity>(rhs);
+    });
+
+    ASSERT_EQ(*(group.raw<unsigned int>() + 0u), 0u);
+    ASSERT_EQ(*(group.raw<unsigned int>() + 1u), 1u);
+    ASSERT_EQ(*(group.raw<unsigned int>() + 2u), 2u);
+
+    ASSERT_EQ(*(group.raw<const int>() + 0u), 0);
+    ASSERT_EQ(*(group.raw<const int>() + 1u), 1);
+    ASSERT_EQ(*(group.raw<const int>() + 2u), 2);
+
+    ASSERT_EQ(*(group.data() + 0u), e2);
+    ASSERT_EQ(*(group.data() + 1u), e1);
+    ASSERT_EQ(*(group.data() + 2u), e0);
+
+    group.sort<const int>([](const int lhs, const int rhs) {
+        return lhs > rhs;
+    });
+
+    ASSERT_EQ(*(group.data() + 0u), e0);
+    ASSERT_EQ(*(group.data() + 1u), e1);
+    ASSERT_EQ(*(group.data() + 2u), e2);
+}
+
+TEST(NonOwningGroup, SortAsAPool) {
+    entt::registry registry;
+    auto group = registry.group(entt::get<const int, unsigned int>);
+
+    const auto e0 = registry.create();
+    const auto e1 = registry.create();
+    const auto e2 = registry.create();
+
     auto uval = 0u;
     auto ival = 0;
 
@@ -533,15 +580,8 @@ TEST(OwningGroup, Empty) {
     registry.assign<char>(e1);
     registry.assign<float>(e1);
 
-    for(auto entity: registry.group<char, int>(entt::get<float>)) {
-        (void)entity;
-        FAIL();
-    }
-
-    for(auto entity: registry.group<double, float>(entt::get<char, int>)) {
-        (void)entity;
-        FAIL();
-    }
+    ASSERT_TRUE((registry.group<char, int>(entt::get<float>).empty()));
+    ASSERT_TRUE((registry.group<double, float>(entt::get<char, int>).empty()));
 }
 
 TEST(OwningGroup, Each) {

+ 174 - 0
test/entt/entity/sparse_set.cpp

@@ -221,6 +221,180 @@ TEST(SparseSet, Data) {
     ASSERT_EQ(*(set.data() + 2u), entt::entity{42});
 }
 
+TEST(SparseSet, SortOrdered) {
+    entt::sparse_set<entt::entity> set;
+
+    set.construct(entt::entity{42});
+    set.construct(entt::entity{12});
+    set.construct(entt::entity{9});
+    set.construct(entt::entity{7});
+    set.construct(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(), [](const auto lhs, const auto rhs) {
+        return std::underlying_type_t<entt::entity>(lhs) < std::underlying_type_t<entt::entity>(rhs);
+    });
+
+    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();
+
+    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);
+}
+
+TEST(SparseSet, SortReverse) {
+    entt::sparse_set<entt::entity> set;
+
+    set.construct(entt::entity{3});
+    set.construct(entt::entity{7});
+    set.construct(entt::entity{9});
+    set.construct(entt::entity{12});
+    set.construct(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(), [](const auto lhs, const auto rhs) {
+        return std::underlying_type_t<entt::entity>(lhs) < std::underlying_type_t<entt::entity>(rhs);
+    });
+
+    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();
+
+    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);
+}
+
+TEST(SparseSet, SortUnordered) {
+    entt::sparse_set<entt::entity> set;
+
+    set.construct(entt::entity{9});
+    set.construct(entt::entity{7});
+    set.construct(entt::entity{3});
+    set.construct(entt::entity{12});
+    set.construct(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(), [](const auto lhs, const auto rhs) {
+        return std::underlying_type_t<entt::entity>(lhs) < std::underlying_type_t<entt::entity>(rhs);
+    });
+
+    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();
+
+    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);
+}
+
+TEST(SparseSet, SortRange) {
+    entt::sparse_set<entt::entity> set;
+
+    set.construct(entt::entity{9});
+    set.construct(entt::entity{7});
+    set.construct(entt::entity{3});
+    set.construct(entt::entity{12});
+    set.construct(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(), [](const auto lhs, const auto rhs) {
+        return std::underlying_type_t<entt::entity>(lhs) < std::underlying_type_t<entt::entity>(rhs);
+    });
+
+    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(), [](const auto lhs, const auto rhs) {
+        return std::underlying_type_t<entt::entity>(lhs) < std::underlying_type_t<entt::entity>(rhs);
+    });
+
+    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, [](const auto lhs, const auto rhs) {
+        return std::underlying_type_t<entt::entity>(lhs) < std::underlying_type_t<entt::entity>(rhs);
+    });
+
+    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(), [](const auto lhs, const auto rhs) {
+        return std::underlying_type_t<entt::entity>(lhs) < std::underlying_type_t<entt::entity>(rhs);
+    });
+
+    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});
+
+    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, end);
+}
+
 TEST(SparseSet, RespectDisjoint) {
     entt::sparse_set<entt::entity> lhs;
     entt::sparse_set<entt::entity> rhs;

+ 282 - 282
test/entt/entity/storage.cpp

@@ -21,135 +21,135 @@ struct throwing_component {
 };
 
 TEST(Storage, Functionalities) {
-    entt::storage<entt::entity, int> set;
+    entt::storage<entt::entity, int> pool;
 
-    set.reserve(42);
+    pool.reserve(42);
 
-    ASSERT_EQ(set.capacity(), 42);
-    ASSERT_TRUE(set.empty());
-    ASSERT_EQ(set.size(), 0u);
-    ASSERT_EQ(std::as_const(set).begin(), std::as_const(set).end());
-    ASSERT_EQ(set.begin(), set.end());
-    ASSERT_FALSE(set.has(entt::entity{0}));
-    ASSERT_FALSE(set.has(entt::entity{41}));
+    ASSERT_EQ(pool.capacity(), 42);
+    ASSERT_TRUE(pool.empty());
+    ASSERT_EQ(pool.size(), 0u);
+    ASSERT_EQ(std::as_const(pool).begin(), std::as_const(pool).end());
+    ASSERT_EQ(pool.begin(), pool.end());
+    ASSERT_FALSE(pool.has(entt::entity{0}));
+    ASSERT_FALSE(pool.has(entt::entity{41}));
 
-    set.construct(entt::entity{41}, 3);
+    pool.construct(entt::entity{41}, 3);
 
-    ASSERT_FALSE(set.empty());
-    ASSERT_EQ(set.size(), 1u);
-    ASSERT_NE(std::as_const(set).begin(), std::as_const(set).end());
-    ASSERT_NE(set.begin(), set.end());
-    ASSERT_FALSE(set.has(entt::entity{0}));
-    ASSERT_TRUE(set.has(entt::entity{41}));
-    ASSERT_EQ(set.get(entt::entity{41}), 3);
-    ASSERT_EQ(*set.try_get(entt::entity{41}), 3);
-    ASSERT_EQ(set.try_get(entt::entity{99}), nullptr);
+    ASSERT_FALSE(pool.empty());
+    ASSERT_EQ(pool.size(), 1u);
+    ASSERT_NE(std::as_const(pool).begin(), std::as_const(pool).end());
+    ASSERT_NE(pool.begin(), pool.end());
+    ASSERT_FALSE(pool.has(entt::entity{0}));
+    ASSERT_TRUE(pool.has(entt::entity{41}));
+    ASSERT_EQ(pool.get(entt::entity{41}), 3);
+    ASSERT_EQ(*pool.try_get(entt::entity{41}), 3);
+    ASSERT_EQ(pool.try_get(entt::entity{99}), nullptr);
 
-    set.destroy(entt::entity{41});
+    pool.destroy(entt::entity{41});
 
-    ASSERT_TRUE(set.empty());
-    ASSERT_EQ(set.size(), 0u);
-    ASSERT_EQ(std::as_const(set).begin(), std::as_const(set).end());
-    ASSERT_EQ(set.begin(), set.end());
-    ASSERT_FALSE(set.has(entt::entity{0}));
-    ASSERT_FALSE(set.has(entt::entity{41}));
+    ASSERT_TRUE(pool.empty());
+    ASSERT_EQ(pool.size(), 0u);
+    ASSERT_EQ(std::as_const(pool).begin(), std::as_const(pool).end());
+    ASSERT_EQ(pool.begin(), pool.end());
+    ASSERT_FALSE(pool.has(entt::entity{0}));
+    ASSERT_FALSE(pool.has(entt::entity{41}));
 
-    set.construct(entt::entity{41}, 12);
+    pool.construct(entt::entity{41}, 12);
 
-    ASSERT_EQ(set.get(entt::entity{41}), 12);
-    ASSERT_EQ(*set.try_get(entt::entity{41}), 12);
-    ASSERT_EQ(set.try_get(entt::entity{99}), nullptr);
+    ASSERT_EQ(pool.get(entt::entity{41}), 12);
+    ASSERT_EQ(*pool.try_get(entt::entity{41}), 12);
+    ASSERT_EQ(pool.try_get(entt::entity{99}), nullptr);
 
-    set.reset();
+    pool.reset();
 
-    ASSERT_TRUE(set.empty());
-    ASSERT_EQ(set.size(), 0u);
-    ASSERT_EQ(std::as_const(set).begin(), std::as_const(set).end());
-    ASSERT_EQ(set.begin(), set.end());
-    ASSERT_FALSE(set.has(entt::entity{0}));
-    ASSERT_FALSE(set.has(entt::entity{41}));
+    ASSERT_TRUE(pool.empty());
+    ASSERT_EQ(pool.size(), 0u);
+    ASSERT_EQ(std::as_const(pool).begin(), std::as_const(pool).end());
+    ASSERT_EQ(pool.begin(), pool.end());
+    ASSERT_FALSE(pool.has(entt::entity{0}));
+    ASSERT_FALSE(pool.has(entt::entity{41}));
 
-    ASSERT_EQ(set.capacity(), 42);
+    ASSERT_EQ(pool.capacity(), 42);
 
-    set.shrink_to_fit();
+    pool.shrink_to_fit();
 
-    ASSERT_EQ(set.capacity(), 0);
+    ASSERT_EQ(pool.capacity(), 0);
 
-    (void)entt::storage<entt::entity, int>{std::move(set)};
+    (void)entt::storage<entt::entity, int>{std::move(pool)};
     entt::storage<entt::entity, int> other;
-    other = std::move(set);
+    other = std::move(pool);
 }
 
 TEST(Storage, EmptyType) {
-    entt::storage<entt::entity, empty_type> set;
+    entt::storage<entt::entity, empty_type> pool;
 
-    set.construct(entt::entity{42});
-    set.construct(entt::entity{99});
+    pool.construct(entt::entity{42});
+    pool.construct(entt::entity{99});
 
-    ASSERT_TRUE(set.has(entt::entity{42}));
-    ASSERT_TRUE(set.has(entt::entity{99}));
+    ASSERT_TRUE(pool.has(entt::entity{42}));
+    ASSERT_TRUE(pool.has(entt::entity{99}));
 
-    auto &&component = set.get(entt::entity{42});
+    auto &&component = pool.get(entt::entity{42});
 
     ASSERT_TRUE((std::is_same_v<decltype(component), empty_type &&>));
 }
 
 TEST(Storage, BatchAdd) {
-    entt::storage<entt::entity, int> set;
+    entt::storage<entt::entity, int> pool;
     entt::storage<entt::entity, int>::entity_type entities[2];
 
     entities[0] = entt::entity{3};
     entities[1] = entt::entity{42};
 
-    set.reserve(4);
-    set.construct(entt::entity{12}, 21);
-    auto *component = set.batch(std::begin(entities), std::end(entities));
-    set.construct(entt::entity{24}, 42);
-
-    ASSERT_TRUE(set.has(entities[0]));
-    ASSERT_TRUE(set.has(entities[1]));
-    ASSERT_FALSE(set.has(entt::entity{0}));
-    ASSERT_FALSE(set.has(entt::entity{9}));
-    ASSERT_TRUE(set.has(entt::entity{12}));
-    ASSERT_TRUE(set.has(entt::entity{24}));
-
-    ASSERT_FALSE(set.empty());
-    ASSERT_EQ(set.size(), 4u);
-    ASSERT_EQ(set.get(entt::entity{12}), 21);
-    ASSERT_EQ(set.get(entities[0]), 0);
-    ASSERT_EQ(set.get(entities[1]), 0);
-    ASSERT_EQ(set.get(entt::entity{24}), 42);
+    pool.reserve(4);
+    pool.construct(entt::entity{12}, 21);
+    auto *component = pool.batch(std::begin(entities), std::end(entities));
+    pool.construct(entt::entity{24}, 42);
+
+    ASSERT_TRUE(pool.has(entities[0]));
+    ASSERT_TRUE(pool.has(entities[1]));
+    ASSERT_FALSE(pool.has(entt::entity{0}));
+    ASSERT_FALSE(pool.has(entt::entity{9}));
+    ASSERT_TRUE(pool.has(entt::entity{12}));
+    ASSERT_TRUE(pool.has(entt::entity{24}));
+
+    ASSERT_FALSE(pool.empty());
+    ASSERT_EQ(pool.size(), 4u);
+    ASSERT_EQ(pool.get(entt::entity{12}), 21);
+    ASSERT_EQ(pool.get(entities[0]), 0);
+    ASSERT_EQ(pool.get(entities[1]), 0);
+    ASSERT_EQ(pool.get(entt::entity{24}), 42);
 
     component[0] = 1;
     component[1] = 2;
 
-    ASSERT_EQ(set.get(entities[0]), 1);
-    ASSERT_EQ(set.get(entities[1]), 2);
+    ASSERT_EQ(pool.get(entities[0]), 1);
+    ASSERT_EQ(pool.get(entities[1]), 2);
 }
 
 TEST(Storage, BatchAddEmptyType) {
-    entt::storage<entt::entity, empty_type> set;
+    entt::storage<entt::entity, empty_type> pool;
     entt::storage<entt::entity, empty_type>::entity_type entities[2];
 
     entities[0] = entt::entity{3};
     entities[1] = entt::entity{42};
 
-    set.reserve(4);
-    set.construct(entt::entity{12});
-    set.batch(std::begin(entities), std::end(entities));
-    set.construct(entt::entity{24});
+    pool.reserve(4);
+    pool.construct(entt::entity{12});
+    pool.batch(std::begin(entities), std::end(entities));
+    pool.construct(entt::entity{24});
 
-    ASSERT_TRUE(set.has(entities[0]));
-    ASSERT_TRUE(set.has(entities[1]));
-    ASSERT_FALSE(set.has(entt::entity{0}));
-    ASSERT_FALSE(set.has(entt::entity{9}));
-    ASSERT_TRUE(set.has(entt::entity{12}));
-    ASSERT_TRUE(set.has(entt::entity{24}));
+    ASSERT_TRUE(pool.has(entities[0]));
+    ASSERT_TRUE(pool.has(entities[1]));
+    ASSERT_FALSE(pool.has(entt::entity{0}));
+    ASSERT_FALSE(pool.has(entt::entity{9}));
+    ASSERT_TRUE(pool.has(entt::entity{12}));
+    ASSERT_TRUE(pool.has(entt::entity{24}));
 
-    ASSERT_FALSE(set.empty());
-    ASSERT_EQ(set.size(), 4u);
+    ASSERT_FALSE(pool.empty());
+    ASSERT_EQ(pool.size(), 4u);
 
-    auto &&component = set.get(entities[0]);
+    auto &&component = pool.get(entities[0]);
 
     ASSERT_TRUE((std::is_same_v<decltype(component), empty_type &&>));
 }
@@ -162,184 +162,184 @@ TEST(Storage, AggregatesMustWork) {
 
 TEST(Storage, TypesFromStandardTemplateLibraryMustWork) {
     // see #37 - this test shouldn't crash, that's all
-    entt::storage<entt::entity, std::unordered_set<int>> set;
-    set.construct(entt::entity{0}).insert(42);
-    set.destroy(entt::entity{0});
+    entt::storage<entt::entity, std::unordered_set<int>> pool;
+    pool.construct(entt::entity{0}).insert(42);
+    pool.destroy(entt::entity{0});
 }
 
 TEST(Storage, Iterator) {
     using iterator_type = typename entt::storage<entt::entity, boxed_int>::iterator_type;
 
-    entt::storage<entt::entity, boxed_int> set;
-    set.construct(entt::entity{3}, 42);
+    entt::storage<entt::entity, boxed_int> pool;
+    pool.construct(entt::entity{3}, 42);
 
-    iterator_type end{set.begin()};
+    iterator_type end{pool.begin()};
     iterator_type begin{};
-    begin = set.end();
+    begin = pool.end();
     std::swap(begin, end);
 
-    ASSERT_EQ(begin, set.begin());
-    ASSERT_EQ(end, set.end());
+    ASSERT_EQ(begin, pool.begin());
+    ASSERT_EQ(end, pool.end());
     ASSERT_NE(begin, end);
 
-    ASSERT_EQ(begin++, set.begin());
-    ASSERT_EQ(begin--, set.end());
+    ASSERT_EQ(begin++, pool.begin());
+    ASSERT_EQ(begin--, pool.end());
 
-    ASSERT_EQ(begin+1, set.end());
-    ASSERT_EQ(end-1, set.begin());
+    ASSERT_EQ(begin+1, pool.end());
+    ASSERT_EQ(end-1, pool.begin());
 
-    ASSERT_EQ(++begin, set.end());
-    ASSERT_EQ(--begin, set.begin());
+    ASSERT_EQ(++begin, pool.end());
+    ASSERT_EQ(--begin, pool.begin());
 
-    ASSERT_EQ(begin += 1, set.end());
-    ASSERT_EQ(begin -= 1, set.begin());
+    ASSERT_EQ(begin += 1, pool.end());
+    ASSERT_EQ(begin -= 1, pool.begin());
 
-    ASSERT_EQ(begin + (end - begin), set.end());
-    ASSERT_EQ(begin - (begin - end), set.end());
+    ASSERT_EQ(begin + (end - begin), pool.end());
+    ASSERT_EQ(begin - (begin - end), pool.end());
 
-    ASSERT_EQ(end - (end - begin), set.begin());
-    ASSERT_EQ(end + (begin - end), set.begin());
+    ASSERT_EQ(end - (end - begin), pool.begin());
+    ASSERT_EQ(end + (begin - end), pool.begin());
 
-    ASSERT_EQ(begin[0].value, set.begin()->value);
+    ASSERT_EQ(begin[0].value, pool.begin()->value);
 
     ASSERT_LT(begin, end);
-    ASSERT_LE(begin, set.begin());
+    ASSERT_LE(begin, pool.begin());
 
     ASSERT_GT(end, begin);
-    ASSERT_GE(end, set.end());
+    ASSERT_GE(end, pool.end());
 }
 
 TEST(Storage, ConstIterator) {
     using iterator_type = typename entt::storage<entt::entity, boxed_int>::const_iterator_type;
 
-    entt::storage<entt::entity, boxed_int> set;
-    set.construct(entt::entity{3}, 42);
+    entt::storage<entt::entity, boxed_int> pool;
+    pool.construct(entt::entity{3}, 42);
 
-    iterator_type cend{set.cbegin()};
+    iterator_type cend{pool.cbegin()};
     iterator_type cbegin{};
-    cbegin = set.cend();
+    cbegin = pool.cend();
     std::swap(cbegin, cend);
 
-    ASSERT_EQ(cbegin, set.cbegin());
-    ASSERT_EQ(cend, set.cend());
+    ASSERT_EQ(cbegin, pool.cbegin());
+    ASSERT_EQ(cend, pool.cend());
     ASSERT_NE(cbegin, cend);
 
-    ASSERT_EQ(cbegin++, set.cbegin());
-    ASSERT_EQ(cbegin--, set.cend());
+    ASSERT_EQ(cbegin++, pool.cbegin());
+    ASSERT_EQ(cbegin--, pool.cend());
 
-    ASSERT_EQ(cbegin+1, set.cend());
-    ASSERT_EQ(cend-1, set.cbegin());
+    ASSERT_EQ(cbegin+1, pool.cend());
+    ASSERT_EQ(cend-1, pool.cbegin());
 
-    ASSERT_EQ(++cbegin, set.cend());
-    ASSERT_EQ(--cbegin, set.cbegin());
+    ASSERT_EQ(++cbegin, pool.cend());
+    ASSERT_EQ(--cbegin, pool.cbegin());
 
-    ASSERT_EQ(cbegin += 1, set.cend());
-    ASSERT_EQ(cbegin -= 1, set.cbegin());
+    ASSERT_EQ(cbegin += 1, pool.cend());
+    ASSERT_EQ(cbegin -= 1, pool.cbegin());
 
-    ASSERT_EQ(cbegin + (cend - cbegin), set.cend());
-    ASSERT_EQ(cbegin - (cbegin - cend), set.cend());
+    ASSERT_EQ(cbegin + (cend - cbegin), pool.cend());
+    ASSERT_EQ(cbegin - (cbegin - cend), pool.cend());
 
-    ASSERT_EQ(cend - (cend - cbegin), set.cbegin());
-    ASSERT_EQ(cend + (cbegin - cend), set.cbegin());
+    ASSERT_EQ(cend - (cend - cbegin), pool.cbegin());
+    ASSERT_EQ(cend + (cbegin - cend), pool.cbegin());
 
-    ASSERT_EQ(cbegin[0].value, set.cbegin()->value);
+    ASSERT_EQ(cbegin[0].value, pool.cbegin()->value);
 
     ASSERT_LT(cbegin, cend);
-    ASSERT_LE(cbegin, set.cbegin());
+    ASSERT_LE(cbegin, pool.cbegin());
 
     ASSERT_GT(cend, cbegin);
-    ASSERT_GE(cend, set.cend());
+    ASSERT_GE(cend, pool.cend());
 }
 
 TEST(Storage, IteratorEmptyType) {
     using iterator_type = typename entt::storage<entt::entity, empty_type>::iterator_type;
-    entt::storage<entt::entity, empty_type> set;
-    set.construct(entt::entity{3});
+    entt::storage<entt::entity, empty_type> pool;
+    pool.construct(entt::entity{3});
 
-    iterator_type end{set.begin()};
+    iterator_type end{pool.begin()};
     iterator_type begin{};
-    begin = set.end();
+    begin = pool.end();
     std::swap(begin, end);
 
-    ASSERT_EQ(begin, set.begin());
-    ASSERT_EQ(end, set.end());
+    ASSERT_EQ(begin, pool.begin());
+    ASSERT_EQ(end, pool.end());
     ASSERT_NE(begin, end);
 
-    ASSERT_EQ(begin++, set.begin());
-    ASSERT_EQ(begin--, set.end());
+    ASSERT_EQ(begin++, pool.begin());
+    ASSERT_EQ(begin--, pool.end());
 
-    ASSERT_EQ(begin+1, set.end());
-    ASSERT_EQ(end-1, set.begin());
+    ASSERT_EQ(begin+1, pool.end());
+    ASSERT_EQ(end-1, pool.begin());
 
-    ASSERT_EQ(++begin, set.end());
-    ASSERT_EQ(--begin, set.begin());
+    ASSERT_EQ(++begin, pool.end());
+    ASSERT_EQ(--begin, pool.begin());
 
-    ASSERT_EQ(begin += 1, set.end());
-    ASSERT_EQ(begin -= 1, set.begin());
+    ASSERT_EQ(begin += 1, pool.end());
+    ASSERT_EQ(begin -= 1, pool.begin());
 
-    ASSERT_EQ(begin + (end - begin), set.end());
-    ASSERT_EQ(begin - (begin - end), set.end());
+    ASSERT_EQ(begin + (end - begin), pool.end());
+    ASSERT_EQ(begin - (begin - end), pool.end());
 
-    ASSERT_EQ(end - (end - begin), set.begin());
-    ASSERT_EQ(end + (begin - end), set.begin());
+    ASSERT_EQ(end - (end - begin), pool.begin());
+    ASSERT_EQ(end + (begin - end), pool.begin());
 
-    ASSERT_EQ(set.begin().operator->(), nullptr);
+    ASSERT_EQ(pool.begin().operator->(), nullptr);
 
     ASSERT_LT(begin, end);
-    ASSERT_LE(begin, set.begin());
+    ASSERT_LE(begin, pool.begin());
 
     ASSERT_GT(end, begin);
-    ASSERT_GE(end, set.end());
+    ASSERT_GE(end, pool.end());
 
-    set.construct(entt::entity{33});
+    pool.construct(entt::entity{33});
     auto &&component = *begin;
 
     ASSERT_TRUE((std::is_same_v<decltype(component), empty_type &&>));
 }
 
 TEST(Storage, Raw) {
-    entt::storage<entt::entity, int> set;
+    entt::storage<entt::entity, int> pool;
 
-    set.construct(entt::entity{3}, 3);
-    set.construct(entt::entity{12}, 6);
-    set.construct(entt::entity{42}, 9);
+    pool.construct(entt::entity{3}, 3);
+    pool.construct(entt::entity{12}, 6);
+    pool.construct(entt::entity{42}, 9);
 
-    ASSERT_EQ(set.get(entt::entity{3}), 3);
-    ASSERT_EQ(std::as_const(set).get(entt::entity{12}), 6);
-    ASSERT_EQ(set.get(entt::entity{42}), 9);
+    ASSERT_EQ(pool.get(entt::entity{3}), 3);
+    ASSERT_EQ(std::as_const(pool).get(entt::entity{12}), 6);
+    ASSERT_EQ(pool.get(entt::entity{42}), 9);
 
-    ASSERT_EQ(*(set.raw() + 0u), 3);
-    ASSERT_EQ(*(std::as_const(set).raw() + 1u), 6);
-    ASSERT_EQ(*(set.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<entt::entity, boxed_int> set;
+    entt::storage<entt::entity, boxed_int> pool;
 
-    set.construct(entt::entity{12}, boxed_int{12});
-    set.construct(entt::entity{42}, boxed_int{9});
-    set.construct(entt::entity{7}, boxed_int{6});
-    set.construct(entt::entity{3}, boxed_int{3});
-    set.construct(entt::entity{9}, boxed_int{1});
+    pool.construct(entt::entity{12}, boxed_int{12});
+    pool.construct(entt::entity{42}, boxed_int{9});
+    pool.construct(entt::entity{7}, boxed_int{6});
+    pool.construct(entt::entity{3}, boxed_int{3});
+    pool.construct(entt::entity{9}, boxed_int{1});
 
-    ASSERT_EQ(set.get(entt::entity{12}).value, 12);
-    ASSERT_EQ(set.get(entt::entity{42}).value, 9);
-    ASSERT_EQ(set.get(entt::entity{7}).value, 6);
-    ASSERT_EQ(set.get(entt::entity{3}).value, 3);
-    ASSERT_EQ(set.get(entt::entity{9}).value, 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);
 
-    set.sort(set.begin(), set.end(), [](auto lhs, auto rhs) {
+    pool.sort(pool.begin(), pool.end(), [](auto lhs, auto rhs) {
         return lhs.value < rhs.value;
     });
 
-    ASSERT_EQ((set.raw() + 0u)->value, 12);
-    ASSERT_EQ((set.raw() + 1u)->value, 9);
-    ASSERT_EQ((set.raw() + 2u)->value, 6);
-    ASSERT_EQ((set.raw() + 3u)->value, 3);
-    ASSERT_EQ((set.raw() + 4u)->value, 1);
+    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 = set.begin();
-    auto end = set.end();
+    auto begin = pool.begin();
+    auto end = pool.end();
 
     ASSERT_EQ((begin++)->value, 1);
     ASSERT_EQ((begin++)->value, 3);
@@ -350,32 +350,32 @@ TEST(Storage, SortOrdered) {
 }
 
 TEST(Storage, SortReverse) {
-    entt::storage<entt::entity, boxed_int> set;
-
-    set.construct(entt::entity{12}, boxed_int{1});
-    set.construct(entt::entity{42}, boxed_int{3});
-    set.construct(entt::entity{7}, boxed_int{6});
-    set.construct(entt::entity{3}, boxed_int{9});
-    set.construct(entt::entity{9}, boxed_int{12});
-
-    ASSERT_EQ(set.get(entt::entity{12}).value, 1);
-    ASSERT_EQ(set.get(entt::entity{42}).value, 3);
-    ASSERT_EQ(set.get(entt::entity{7}).value, 6);
-    ASSERT_EQ(set.get(entt::entity{3}).value, 9);
-    ASSERT_EQ(set.get(entt::entity{9}).value, 12);
-
-    set.sort(set.begin(), set.end(), [&set](entt::entity lhs, entt::entity rhs) {
-        return set.get(lhs).value < set.get(rhs).value;
+    entt::storage<entt::entity, boxed_int> pool;
+
+    pool.construct(entt::entity{12}, boxed_int{1});
+    pool.construct(entt::entity{42}, boxed_int{3});
+    pool.construct(entt::entity{7}, boxed_int{6});
+    pool.construct(entt::entity{3}, boxed_int{9});
+    pool.construct(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((set.raw() + 0u)->value, 12);
-    ASSERT_EQ((set.raw() + 1u)->value, 9);
-    ASSERT_EQ((set.raw() + 2u)->value, 6);
-    ASSERT_EQ((set.raw() + 3u)->value, 3);
-    ASSERT_EQ((set.raw() + 4u)->value, 1);
+    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 = set.begin();
-    auto end = set.end();
+    auto begin = pool.begin();
+    auto end = pool.end();
 
     ASSERT_EQ((begin++)->value, 1);
     ASSERT_EQ((begin++)->value, 3);
@@ -386,32 +386,32 @@ TEST(Storage, SortReverse) {
 }
 
 TEST(Storage, SortUnordered) {
-    entt::storage<entt::entity, boxed_int> set;
+    entt::storage<entt::entity, boxed_int> pool;
 
-    set.construct(entt::entity{12}, boxed_int{6});
-    set.construct(entt::entity{42}, boxed_int{3});
-    set.construct(entt::entity{7}, boxed_int{1});
-    set.construct(entt::entity{3}, boxed_int{9});
-    set.construct(entt::entity{9}, boxed_int{12});
+    pool.construct(entt::entity{12}, boxed_int{6});
+    pool.construct(entt::entity{42}, boxed_int{3});
+    pool.construct(entt::entity{7}, boxed_int{1});
+    pool.construct(entt::entity{3}, boxed_int{9});
+    pool.construct(entt::entity{9}, boxed_int{12});
 
-    ASSERT_EQ(set.get(entt::entity{12}).value, 6);
-    ASSERT_EQ(set.get(entt::entity{42}).value, 3);
-    ASSERT_EQ(set.get(entt::entity{7}).value, 1);
-    ASSERT_EQ(set.get(entt::entity{3}).value, 9);
-    ASSERT_EQ(set.get(entt::entity{9}).value, 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);
 
-    set.sort(set.begin(), set.end(), [](auto lhs, auto rhs) {
+    pool.sort(pool.begin(), pool.end(), [](auto lhs, auto rhs) {
         return lhs.value < rhs.value;
     });
 
-    ASSERT_EQ((set.raw() + 0u)->value, 12);
-    ASSERT_EQ((set.raw() + 1u)->value, 9);
-    ASSERT_EQ((set.raw() + 2u)->value, 6);
-    ASSERT_EQ((set.raw() + 3u)->value, 3);
-    ASSERT_EQ((set.raw() + 4u)->value, 1);
+    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 = set.begin();
-    auto end = set.end();
+    auto begin = pool.begin();
+    auto end = pool.end();
 
     ASSERT_EQ((begin++)->value, 1);
     ASSERT_EQ((begin++)->value, 3);
@@ -422,62 +422,62 @@ TEST(Storage, SortUnordered) {
 }
 
 TEST(Storage, SortRange) {
-    entt::storage<entt::entity, boxed_int> set;
+    entt::storage<entt::entity, boxed_int> pool;
 
-    set.construct(entt::entity{12}, boxed_int{6});
-    set.construct(entt::entity{42}, boxed_int{3});
-    set.construct(entt::entity{7}, boxed_int{1});
-    set.construct(entt::entity{3}, boxed_int{9});
-    set.construct(entt::entity{9}, boxed_int{12});
+    pool.construct(entt::entity{12}, boxed_int{6});
+    pool.construct(entt::entity{42}, boxed_int{3});
+    pool.construct(entt::entity{7}, boxed_int{1});
+    pool.construct(entt::entity{3}, boxed_int{9});
+    pool.construct(entt::entity{9}, boxed_int{12});
 
-    ASSERT_EQ(set.get(entt::entity{12}).value, 6);
-    ASSERT_EQ(set.get(entt::entity{42}).value, 3);
-    ASSERT_EQ(set.get(entt::entity{7}).value, 1);
-    ASSERT_EQ(set.get(entt::entity{3}).value, 9);
-    ASSERT_EQ(set.get(entt::entity{9}).value, 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);
 
-    set.sort(set.end(), set.end(), [](auto lhs, auto rhs) {
+    pool.sort(pool.end(), pool.end(), [](auto lhs, auto rhs) {
         return lhs.value < rhs.value;
     });
 
-    ASSERT_EQ(set.get(entt::entity{12}).value, 6);
-    ASSERT_EQ(set.get(entt::entity{42}).value, 3);
-    ASSERT_EQ(set.get(entt::entity{7}).value, 1);
-    ASSERT_EQ(set.get(entt::entity{3}).value, 9);
-    ASSERT_EQ(set.get(entt::entity{9}).value, 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);
 
-    set.sort(set.begin(), set.begin(), [](auto lhs, auto rhs) {
+    pool.sort(pool.begin(), pool.begin(), [](auto lhs, auto rhs) {
         return lhs.value < rhs.value;
     });
 
-    ASSERT_EQ(set.get(entt::entity{12}).value, 6);
-    ASSERT_EQ(set.get(entt::entity{42}).value, 3);
-    ASSERT_EQ(set.get(entt::entity{7}).value, 1);
-    ASSERT_EQ(set.get(entt::entity{3}).value, 9);
-    ASSERT_EQ(set.get(entt::entity{9}).value, 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);
 
-    set.sort(set.begin()+2, set.begin()+3, [](auto lhs, auto rhs) {
+    pool.sort(pool.begin()+2, pool.begin()+3, [](auto lhs, auto rhs) {
         return lhs.value < rhs.value;
     });
 
-    ASSERT_EQ(set.get(entt::entity{12}).value, 6);
-    ASSERT_EQ(set.get(entt::entity{42}).value, 3);
-    ASSERT_EQ(set.get(entt::entity{7}).value, 1);
-    ASSERT_EQ(set.get(entt::entity{3}).value, 9);
-    ASSERT_EQ(set.get(entt::entity{9}).value, 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);
 
-    set.sort(++set.begin(), --set.end(), [](auto lhs, auto rhs) {
+    pool.sort(++pool.begin(), --pool.end(), [](auto lhs, auto rhs) {
         return lhs.value < rhs.value;
     });
 
-    ASSERT_EQ((set.raw() + 0u)->value, 6);
-    ASSERT_EQ((set.raw() + 1u)->value, 9);
-    ASSERT_EQ((set.raw() + 2u)->value, 3);
-    ASSERT_EQ((set.raw() + 3u)->value, 1);
-    ASSERT_EQ((set.raw() + 4u)->value, 12);
+    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);
 
-    auto begin = set.begin();
-    auto end = set.end();
+    auto begin = pool.begin();
+    auto end = pool.end();
 
     ASSERT_EQ((begin++)->value, 12);
     ASSERT_EQ((begin++)->value, 1);
@@ -703,15 +703,15 @@ TEST(Storage, RespectOverlapEmptyType) {
 }
 
 TEST(Storage, CanModifyDuringIteration) {
-    entt::storage<entt::entity, int> set;
-    set.construct(entt::entity{0}, 42);
+    entt::storage<entt::entity, int> pool;
+    pool.construct(entt::entity{0}, 42);
 
-    ASSERT_EQ(set.capacity(), (entt::storage<entt::entity, int>::size_type{1}));
+    ASSERT_EQ(pool.capacity(), (entt::storage<entt::entity, int>::size_type{1}));
 
-    const auto it = set.cbegin();
-    set.reserve(entt::storage<entt::entity, int>::size_type{2});
+    const auto it = pool.cbegin();
+    pool.reserve(entt::storage<entt::entity, int>::size_type{2});
 
-    ASSERT_EQ(set.capacity(), (entt::storage<entt::entity, int>::size_type{2}));
+    ASSERT_EQ(pool.capacity(), (entt::storage<entt::entity, int>::size_type{2}));
 
     // this should crash with asan enabled if we break the constraint
     const auto entity = *it;
@@ -719,46 +719,46 @@ TEST(Storage, CanModifyDuringIteration) {
 }
 
 TEST(Storage, ReferencesGuaranteed) {
-    entt::storage<entt::entity, boxed_int> set;
+    entt::storage<entt::entity, boxed_int> pool;
 
-    set.construct(entt::entity{0}, 0);
-    set.construct(entt::entity{1}, 1);
+    pool.construct(entt::entity{0}, 0);
+    pool.construct(entt::entity{1}, 1);
 
-    ASSERT_EQ(set.get(entt::entity{0}).value, 0);
-    ASSERT_EQ(set.get(entt::entity{1}).value, 1);
+    ASSERT_EQ(pool.get(entt::entity{0}).value, 0);
+    ASSERT_EQ(pool.get(entt::entity{1}).value, 1);
 
-    for(auto &&type: set) {
+    for(auto &&type: pool) {
         if(type.value) {
             type.value = 42;
         }
     }
 
-    ASSERT_EQ(set.get(entt::entity{0}).value, 0);
-    ASSERT_EQ(set.get(entt::entity{1}).value, 42);
+    ASSERT_EQ(pool.get(entt::entity{0}).value, 0);
+    ASSERT_EQ(pool.get(entt::entity{1}).value, 42);
 
-    auto begin = set.begin();
+    auto begin = pool.begin();
 
-    while(begin != set.end()) {
+    while(begin != pool.end()) {
         (begin++)->value = 3;
     }
 
-    ASSERT_EQ(set.get(entt::entity{0}).value, 3);
-    ASSERT_EQ(set.get(entt::entity{1}).value, 3);
+    ASSERT_EQ(pool.get(entt::entity{0}).value, 3);
+    ASSERT_EQ(pool.get(entt::entity{1}).value, 3);
 }
 
 TEST(Storage, MoveOnlyComponent) {
     // the purpose is to ensure that move only components are always accepted
-    entt::storage<entt::entity, std::unique_ptr<int>> set;
-    (void)set;
+    entt::storage<entt::entity, std::unique_ptr<int>> pool;
+    (void)pool;
 }
 
-TEST(Storage, ConstructorExceptionDoesNotAddToSet) {
-    entt::storage<entt::entity, throwing_component> set;
+TEST(Storage, ConstructorExceptionDoesNotAddToStorage) {
+    entt::storage<entt::entity, throwing_component> pool;
 
     try {
-        set.construct(entt::entity{0});
+        pool.construct(entt::entity{0});
         FAIL() << "Expected constructor_exception to be thrown";
     } catch (const throwing_component::constructor_exception &) {
-        ASSERT_TRUE(set.empty());
+        ASSERT_TRUE(pool.empty());
     }
 }