Browse Source

registry::stomp supports foreign registries (close #315)

Michele Caini 6 years ago
parent
commit
28e5267132
3 changed files with 50 additions and 5 deletions
  1. 1 1
      TODO
  2. 26 4
      src/entt/entity/registry.hpp
  3. 23 0
      test/entt/entity/registry.cpp

+ 1 - 1
TODO

@@ -21,7 +21,6 @@
   - use direct access (pool-like) also for context variables
   - allow for key/value variables where the key is an ENTT_ID_TYPE
   - improves multi-stomp
-* range based registry::remove and some others?
 * add examples (and credits) from @alanjfs :)
 * static reflection, hint: template<> meta_type_t<Type>: meta_descriptor<name, func..., props..., etc...>
 * ENTT_NAMED_TYPE -> ENTT_EXPORT and add also ENTT_EXPORT_WITH_NAME
@@ -34,4 +33,5 @@
   - and so on (I'm lazy) :)
 * named types: almost-stable index optimization for direct access to pools, no more linear searches
   - can implicitly generate types for meta benefit from a similar approach?
+  * registry::each to iterate all components of an entity
 * multi component registry::remove and some others?

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

@@ -42,6 +42,10 @@ namespace entt {
  */
 template<typename Entity>
 class basic_registry {
+    /*! @brief Registries are friend with one another. */
+    template<typename>
+    friend class basic_registry;
+
     using context_family = family<struct internal_registry_context_family>;
     using component_family = family<struct internal_registry_component_family>;
     using traits_type = entt_traits<std::underlying_type_t<Entity>>;
@@ -1542,6 +1546,13 @@ public:
      * lists. An excluded type will never be copied.
      *
      * @warning
+     * Stomping entities between registries with different types of identifiers
+     * without a component list is allowed only if the target registry already
+     * contains the required pools.<br/>
+     * An assertion will abort the execution at runtime in debug mode in case a
+     * pool is missing.
+     *
+     * @warning
      * Attempting to copy components that aren't copyable results in unexpected
      * behaviors.<br/>
      * A static assertion will abort the compilation when the components
@@ -1555,22 +1566,33 @@ public:
      * invalid entities.
      *
      * @tparam Component Types of components to copy.
+     * @tparam Entt A valid entity type (see entt_traits for more details).
      * @tparam Exclude Types of components not to be copied.
      * @param dst A valid entity identifier to copy to.
      * @param src A valid entity identifier to be copied.
      * @param other The registry that owns the source entity.
      */
-    template<typename... Component, typename... Exclude>
-    void stomp(const entity_type dst, const entity_type src, const basic_registry &other, exclude_t<Exclude...> = {}) {
+    template<typename... Component, typename Entt, typename... Exclude>
+    void stomp(const entity_type dst, const Entt src, const basic_registry<Entt> &other, exclude_t<Exclude...> = {}) {
         if constexpr(sizeof...(Component) == 0) {
             for(auto pos = other.pools.size(); pos; --pos) {
                 if(const auto &pdata = other.pools[pos-1]; pdata.set && ((pdata.runtime_type != to_integer(type<Exclude>())) && ...) && pdata.pool->has(src)) {
-                    pdata.set(*this, dst, pdata.get(*pdata.pool, src));
+                    if constexpr(std::is_same_v<entity_type, Entt>) {
+                        pdata.set(*this, dst, pdata.get(*pdata.pool, src));
+                    } else {
+                        if(const auto ctype = pdata.runtime_type; ctype < pools.size() && pools[ctype].pool && pools[ctype].runtime_type == ctype) {
+                            pools[ctype].set(*this, dst, pdata.get(*pdata.pool, src));
+                        } else {
+                            const auto it = std::find_if(pools.cbegin(), pools.cend(), [ctype](auto &&curr) { return curr.pool && curr.runtime_type == ctype; });
+                            ENTT_ASSERT(it != pools.cend());
+                            it->set(*this, dst, pdata.get(*pdata.pool, src));
+                        }
+                    }
                 }
             }
         } else {
             static_assert(sizeof...(Exclude) == 0 && std::conjunction_v<std::is_copy_constructible<Component>...>);
-            (assign_or_replace<Component>(dst, other.get<Component>(src)), ...);
+            (assign_or_replace<Component>(dst, other.template get<Component>(src)), ...);
         }
     }
 

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

@@ -6,9 +6,11 @@
 #include <cstdint>
 #include <type_traits>
 #include <gtest/gtest.h>
+#include <entt/core/type_traits.hpp>
 #include <entt/entity/registry.hpp>
 #include <entt/entity/entity.hpp>
 
+ENTT_OPAQUE_TYPE(opaque, std::uint64_t);
 ENTT_NAMED_TYPE(int);
 
 struct empty_type {};
@@ -1500,6 +1502,27 @@ TEST(Registry, StompMoveOnlyComponent) {
     ASSERT_FALSE(registry.has<std::unique_ptr<int>>(entity));
 }
 
+TEST(Registry, StompBetweenRegistriesWithDifferentIdentifiers) {
+    entt::basic_registry<opaque> source;
+    entt::registry destination;
+
+    const auto entity = source.create();
+    const auto other = destination.create();
+
+    source.assign<char>(entity, 'c');
+    source.assign<double>(entity, 0.);
+    source.assign<int>(entity, 42);
+
+    destination.prepare<int>();
+    destination.prepare<char>();
+    destination.stomp(other, entity, source, entt::exclude<double>);
+
+    ASSERT_TRUE((destination.has<char, int>(other)));
+    ASSERT_FALSE(destination.has<double>(other));
+    ASSERT_EQ(destination.get<char>(other), 'c');
+    ASSERT_EQ(destination.get<int>(other), 42);
+}
+
 TEST(Registry, GetOrAssign) {
     entt::registry registry;
     const auto entity = registry.create();