Kaynağa Gözat

registry: range-assign with optional init function(s)

Michele Caini 6 yıl önce
ebeveyn
işleme
a580bac385
3 değiştirilmiş dosya ile 29 ekleme ve 8 silme
  1. 1 0
      TODO
  2. 19 6
      src/entt/entity/registry.hpp
  3. 9 2
      test/entt/entity/registry.cpp

+ 1 - 0
TODO

@@ -14,6 +14,7 @@
 * use underlying_type as entity type within pools and registry? it would make different registries work together flawlessy
 * can we write a bool conv func for entt::entity that silently compares it to null?
 * reset... reset everywhere...
+* is it possible to make 0 the entity null?
 * document undocumented parts (entt::overload and a few others)
 * any-of rule for views/groups (eg entity has A and any of B/C/D)
   - get -> all, exclude -> none

+ 19 - 6
src/entt/entity/registry.hpp

@@ -73,10 +73,11 @@ class basic_registry {
             return this->get(entt);
         }
 
-        template<typename It>
+        template<typename It, typename... Func>
         std::enable_if_t<std::is_same_v<typename std::iterator_traits<It>::value_type, Entity>, void>
-        assign(basic_registry &owner, It first, It last) {
+        assign(basic_registry &owner, It first, It last, Func... func) {
             this->construct(first, last);
+            (func(this->raw() + this->size() - std::distance(first, last)), ...);
 
             if(!construction.empty()) {
                 std::for_each(first, last, [this, &owner](const auto entt) { construction.publish(entt, owner); });
@@ -635,20 +636,32 @@ public:
     /**
      * @brief Assigns each entity in a range the given component.
      *
-     * The component type must be at least move and default insertable.
+     * Function objects are optional. They are invoked to give the caller a
+     * chance to initialize the components before they are passed to any
+     * registered listener.<br/>
+     * The signature of the functions should be equivalent to the following:
+     *
+     * @code{.cpp}
+     * void(It it);
+     * @endcode
+     *
+     * Where `it` is an iterator to the first element of the range of newly
+     * created objects.
      *
      * @sa assign
      *
      * @tparam Component Type of component to create.
      * @tparam It Type of input iterator.
+     * @tparam Func Types of the function objects to invoke.
      * @param first An iterator to the first element of the range of entities.
      * @param last An iterator past the last element of the range of entities.
+     * @param func Valid function objects.
      */
-    template<typename Component, typename It>
+    template<typename Component, typename It, typename... Func>
     std::enable_if_t<std::is_same_v<typename std::iterator_traits<It>::value_type, entity_type>, void>
-    assign(It first, It last) {
+    assign(It first, It last, Func... func) {
         ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }));
-        assure<Component>().assign(*this, first, last);
+        assure<Component>().assign(*this, first, last, std::move(func)...);
     }
 
     /**

+ 9 - 2
test/entt/entity/registry.cpp

@@ -1193,9 +1193,16 @@ TEST(Registry, RangeAssign) {
     const auto view = registry.view<int, char>();
     registry.assign<float>(view.begin(), view.end());
 
-    ASSERT_TRUE(registry.has<float>(e0));
-    ASSERT_TRUE(registry.has<float>(e1));
+    ASSERT_EQ(registry.get<float>(e0), 0.f);
+    ASSERT_EQ(registry.get<float>(e1), 0.f);
     ASSERT_FALSE(registry.has<float>(e2));
+
+    registry.clear<float>();
+    registry.assign<float>(registry.data<int>(), registry.data<int>() + registry.size<int>(), [](float *raw) { *(++raw) = 1.f; });
+
+    ASSERT_EQ(registry.get<float>(e0), 0.f);
+    ASSERT_EQ(registry.get<float>(e1), 1.f);
+    ASSERT_EQ(registry.get<float>(e2), 0.f);
 }
 
 TEST(Registry, RangeRemove) {