Răsfoiți Sursa

added the possibility to sort free instances for owned types

Michele Caini 6 ani în urmă
părinte
comite
9126651cb9
5 a modificat fișierele cu 100 adăugiri și 17 ștergeri
  1. 2 1
      TODO
  2. 10 4
      docs/md/entity.md
  3. 17 10
      src/entt/entity/registry.hpp
  4. 2 2
      src/entt/entity/storage.hpp
  5. 69 0
      test/entt/entity/registry.cpp

+ 2 - 1
TODO

@@ -23,6 +23,7 @@
 * meta: opaque references and pointers
 * meta: opaque references and pointers
 
 
 TODO
 TODO
-* registry::sort also for types that are part of a group (untracked items only)
 * add sort by type to the non-owning group
 * add sort by type to the non-owning group
 * custom (decoupled) pools ==> double buffering, shared components, multi-model
 * 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

+ 10 - 4
docs/md/entity.md

@@ -1373,9 +1373,11 @@ them as fast as possible.
 
 
 Sorting owned components is no longer allowed once the group has been created.
 Sorting owned components is no longer allowed once the group has been created.
 However, full-owning groups can be sorted by means of their `sort` member
 However, full-owning groups can be sorted by means of their `sort` member
-functions, if required. Sorting a full-owning group affects all the instance of
+functions, if required. Sorting a full-owning group affects all the instances of
 the same group (it means that users don't have to call `sort` on each instance
 the same group (it means that users don't have to call `sort` on each instance
-to sort all of them because they share the underlying data structure).
+to sort all of them because they share the underlying data structure).<br/>
+The elements that aren't part of the group can still be sorted separately for
+each pool using the `sort` member function of the registry.
 
 
 ### Partial-owning groups
 ### Partial-owning groups
 
 
@@ -1404,9 +1406,13 @@ doesn't pass to the group instead.
 
 
 Sorting owned components is no longer allowed once the group has been created.
 Sorting owned components is no longer allowed once the group has been created.
 However, partial-owning groups can be sorted by means of their `sort` member
 However, partial-owning groups can be sorted by means of their `sort` member
-functions, if required. Sorting a partial-owning group affects all the instance
+functions, if required. Sorting a partial-owning group affects all the instances
 of the same group (it means that users don't have to call `sort` on each
 of the same group (it means that users don't have to call `sort` on each
-instance to sort all of them because they share the underlying data structure).
+instance to sort all of them because they share the underlying data
+structure).<br/>
+Regarding the owned types, the elements that aren't part of the group can still
+be sorted separately for each pool using the `sort` member function of the
+registry.
 
 
 ### Non-owning groups
 ### Non-owning groups
 
 

+ 17 - 10
src/entt/entity/registry.hpp

@@ -45,9 +45,13 @@ class basic_registry {
     using component_family = family<struct internal_registry_component_family>;
     using component_family = family<struct internal_registry_component_family>;
     using traits_type = entt_traits<std::underlying_type_t<Entity>>;
     using traits_type = entt_traits<std::underlying_type_t<Entity>>;
 
 
+    struct group_type {
+        std::size_t owned{};
+    };
+
     template<typename Component>
     template<typename Component>
     struct pool_handler: storage<Entity, Component> {
     struct pool_handler: storage<Entity, Component> {
-        void *group{};
+        group_type *group{};
 
 
         pool_handler() ENTT_NOEXCEPT = default;
         pool_handler() ENTT_NOEXCEPT = default;
 
 
@@ -164,9 +168,8 @@ class basic_registry {
     };
     };
 
 
     template<typename... Exclude, typename... Get, typename... Owned>
     template<typename... Exclude, typename... Get, typename... Owned>
-    struct group_handler<type_list<Exclude...>, type_list<Get...>, Owned...> {
+    struct group_handler<type_list<Exclude...>, type_list<Get...>, Owned...>: group_type {
         std::tuple<pool_type<Owned> *..., pool_type<Get> *..., pool_type<Exclude> *...> cpools{};
         std::tuple<pool_type<Owned> *..., pool_type<Get> *..., pool_type<Exclude> *...> cpools{};
-        std::size_t owned{};
 
 
         template<typename Component>
         template<typename Component>
         void maybe_valid_if(const basic_registry &, const Entity entt) {
         void maybe_valid_if(const basic_registry &, const Entity entt) {
@@ -1019,9 +1022,10 @@ public:
      * this member function.
      * this member function.
      *
      *
      * @warning
      * @warning
-     * Pools of components that are owned by a group cannot be sorted.<br/>
-     * An assertion will abort the execution at runtime in debug mode in case
-     * the pool is owned by a group.
+     * Pools of components owned by a group are only partially sorted.<br/>
+     * In other words, only the elements that aren't part of the group are
+     * sorted by this function. Use the `sort` member function of a group to
+     * sort the other half of the pool.
      *
      *
      * @tparam Component Type of components to sort.
      * @tparam Component Type of components to sort.
      * @tparam Compare Type of comparison function object.
      * @tparam Compare Type of comparison function object.
@@ -1033,9 +1037,12 @@ public:
      */
      */
     template<typename Component, typename Compare, typename Sort = std_sort, typename... Args>
     template<typename Component, typename Compare, typename Sort = std_sort, typename... Args>
     void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
     void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
-        ENTT_ASSERT(!owned<Component>());
-        auto *cpool = assure<Component>();
-        cpool->sort(cpool->begin(), cpool->end(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
+        if(auto *cpool = assure<Component>(); cpool->group) {
+            const auto last = cpool->end() - cpool->group->owned;
+            cpool->sort(cpool->begin(), last, std::move(compare), std::move(algo), std::forward<Args>(args)...);
+        } else {
+            cpool->sort(cpool->begin(), cpool->end(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
+        }
     }
     }
 
 
     /**
     /**
@@ -1066,7 +1073,7 @@ public:
      * Any subsequent change to `B` won't affect the order in `A`.
      * Any subsequent change to `B` won't affect the order in `A`.
      *
      *
      * @warning
      * @warning
-     * Pools of components that are owned by a group cannot be sorted.<br/>
+     * Pools of components owned by a group cannot be sorted this way.<br/>
      * An assertion will abort the execution at runtime in debug mode in case
      * An assertion will abort the execution at runtime in debug mode in case
      * the pool is owned by a group.
      * the pool is owned by a group.
      *
      *

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

@@ -451,7 +451,7 @@ public:
             static_assert(!std::is_empty_v<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) {
             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]));
+                return compare(std::as_const(instances[lhs + offset]), std::as_const(instances[rhs + offset]));
             }, std::forward<Args>(args)...);
             }, std::forward<Args>(args)...);
         } else {
         } else {
             algo(copy.rbegin(), copy.rend(), [offset, compare = std::move(compare), data = underlying_type::data()](const auto lhs, const auto rhs) {
             algo(copy.rbegin(), copy.rend(), [offset, compare = std::move(compare), data = underlying_type::data()](const auto lhs, const auto rhs) {
@@ -464,7 +464,7 @@ public:
             auto next = copy[curr];
             auto next = copy[curr];
 
 
             while(curr != next) {
             while(curr != next) {
-                swap(copy[curr]+offset, copy[next]+offset);
+                swap(copy[curr] + offset, copy[next] + offset);
                 copy[curr] = curr;
                 copy[curr] = curr;
                 curr = next;
                 curr = next;
                 next = copy[curr];
                 next = copy[curr];

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

@@ -784,6 +784,75 @@ TEST(Registry, SortMulti) {
     }
     }
 }
 }
 
 
+TEST(Registry, SortOwned) {
+    entt::registry registry;
+    registry.group<int>(entt::get<char>);
+
+    for(auto i = 0; i < 5; ++i) {
+        const auto entity = registry.create();
+        registry.assign<int>(entity, i);
+
+        if(i < 2) {
+            registry.assign<char>(entity);
+        }
+    }
+
+    ASSERT_TRUE((registry.has<int, char>(*(registry.data<int>()+0))));
+    ASSERT_TRUE((registry.has<int, char>(*(registry.data<int>()+1))));
+
+    ASSERT_EQ(*(registry.raw<int>()+0), 0);
+    ASSERT_EQ(*(registry.raw<int>()+1), 1);
+    ASSERT_EQ(*(registry.raw<int>()+2), 2);
+    ASSERT_EQ(*(registry.raw<int>()+3), 3);
+    ASSERT_EQ(*(registry.raw<int>()+4), 4);
+
+    registry.sort<int>([](const int lhs, const int rhs) {
+        return lhs < rhs;
+    });
+
+    ASSERT_EQ(*(registry.raw<int>()+0), 0);
+    ASSERT_EQ(*(registry.raw<int>()+1), 1);
+    ASSERT_EQ(*(registry.raw<int>()+2), 4);
+    ASSERT_EQ(*(registry.raw<int>()+3), 3);
+    ASSERT_EQ(*(registry.raw<int>()+4), 2);
+
+    registry.reset<char>();
+    registry.sort<int>([](const int lhs, const int rhs) {
+        return lhs < rhs;
+    });
+
+    ASSERT_EQ(*(registry.raw<int>()+0), 4);
+    ASSERT_EQ(*(registry.raw<int>()+1), 3);
+    ASSERT_EQ(*(registry.raw<int>()+2), 2);
+    ASSERT_EQ(*(registry.raw<int>()+3), 1);
+    ASSERT_EQ(*(registry.raw<int>()+4), 0);
+
+    registry.each([&registry](const auto entity) {
+        registry.assign<char>(entity);
+    });
+
+    registry.sort<int>([](const int lhs, const int rhs) {
+        return lhs > rhs;
+    });
+
+    ASSERT_EQ(*(registry.raw<int>()+0), 4);
+    ASSERT_EQ(*(registry.raw<int>()+1), 3);
+    ASSERT_EQ(*(registry.raw<int>()+2), 2);
+    ASSERT_EQ(*(registry.raw<int>()+3), 1);
+    ASSERT_EQ(*(registry.raw<int>()+4), 0);
+
+    registry.reset<char>();
+    registry.sort<int>([](const int lhs, const int rhs) {
+        return lhs > rhs;
+    });
+
+    ASSERT_EQ(*(registry.raw<int>()+0), 0);
+    ASSERT_EQ(*(registry.raw<int>()+1), 1);
+    ASSERT_EQ(*(registry.raw<int>()+2), 2);
+    ASSERT_EQ(*(registry.raw<int>()+3), 3);
+    ASSERT_EQ(*(registry.raw<int>()+4), 4);
+}
+
 TEST(Registry, ComponentsWithTypesFromStandardTemplateLibrary) {
 TEST(Registry, ComponentsWithTypesFromStandardTemplateLibrary) {
     // see #37 - the test shouldn't crash, that's all
     // see #37 - the test shouldn't crash, that's all
     entt::registry registry;
     entt::registry registry;