Просмотр исходного кода

added the possibility to sort free instances for owned types

Michele Caini 6 лет назад
Родитель
Сommit
9126651cb9
5 измененных файлов с 100 добавлено и 17 удалено
  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
 
 TODO
-* registry::sort also for types that are part of a group (untracked items only)
 * 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

+ 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.
 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
-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
 
@@ -1404,9 +1406,13 @@ doesn't pass to the group instead.
 
 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
-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
-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
 

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

@@ -45,9 +45,13 @@ class basic_registry {
     using component_family = family<struct internal_registry_component_family>;
     using traits_type = entt_traits<std::underlying_type_t<Entity>>;
 
+    struct group_type {
+        std::size_t owned{};
+    };
+
     template<typename Component>
     struct pool_handler: storage<Entity, Component> {
-        void *group{};
+        group_type *group{};
 
         pool_handler() ENTT_NOEXCEPT = default;
 
@@ -164,9 +168,8 @@ class basic_registry {
     };
 
     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::size_t owned{};
 
         template<typename Component>
         void maybe_valid_if(const basic_registry &, const Entity entt) {
@@ -1019,9 +1022,10 @@ public:
      * this member function.
      *
      * @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 Compare Type of comparison function object.
@@ -1033,9 +1037,12 @@ public:
      */
     template<typename Component, typename Compare, typename Sort = std_sort, typename... 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`.
      *
      * @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
      * 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>);
 
             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)...);
         } else {
             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];
 
             while(curr != next) {
-                swap(copy[curr]+offset, copy[next]+offset);
+                swap(copy[curr] + offset, copy[next] + offset);
                 copy[curr] = curr;
                 curr = next;
                 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) {
     // see #37 - the test shouldn't crash, that's all
     entt::registry registry;