Explorar o código

cloning an entity is no longer allowed

Michele Caini %!s(int64=7) %!d(string=hai) anos
pai
achega
e34bec7dee

+ 3 - 9
README.md

@@ -396,25 +396,19 @@ Entities are represented by _entity identifiers_. An entity identifier is an
 opaque type that users should not inspect or modify in any way. It carries
 opaque type that users should not inspect or modify in any way. It carries
 information about the entity itself and its version.
 information about the entity itself and its version.
 
 
-A registry can be used both to construct and destroy entities, as well as to
-clone already existing entities:
+A registry can be used both to construct and destroy entities:
 
 
 ```cpp
 ```cpp
 // constructs a naked entity with no components and returns its identifier
 // constructs a naked entity with no components and returns its identifier
 auto entity = registry.create();
 auto entity = registry.create();
 
 
-// clones an entity and assigns all its components by copy to the newly created one
-auto other = registry.clone(entity);
-
 // destroys an entity and all its components
 // destroys an entity and all its components
 registry.destroy(entity);
 registry.destroy(entity);
 ```
 ```
 
 
-Be aware that cloning an entity can lead to unexpected results under certain
-conditions. Please refer to the inline documentation for more details.<br/>
-Once an entity is deleted, the registry can freely reuse it internally with a
+When an entity is destroyed, the registry can freely reuse it internally with a
 slightly different identifier. In particular, the version of an entity is
 slightly different identifier. In particular, the version of an entity is
-increased each and every time it's destroyed.<br/>
+increased each and every time it's discarded.<br/>
 In case entity identifiers are stored around, the registry offers all the
 In case entity identifiers are stored around, the registry offers all the
 functionalities required to test them and get out of the them all the
 functionalities required to test them and get out of the them all the
 information they carry:
 information they carry:

+ 0 - 45
src/entt/entity/registry.hpp

@@ -408,51 +408,6 @@ public:
         return entity;
         return entity;
     }
     }
 
 
-    /**
-     * @brief Clones an entity and returns the newly created one.
-     *
-     * There are two kinds of entity identifiers:
-     *
-     * * Newly created ones in case no entities have been previously destroyed.
-     * * Recycled ones with updated versions.
-     *
-     * Users should not care about the type of the returned entity identifier.
-     * In case entity identifers are stored around, the `valid` member
-     * function can be used to know if they are still valid or the entity has
-     * been destroyed and potentially recycled.
-     *
-     * @warning
-     * In case there are listeners that observe the construction of components
-     * and assign other components to the entity in their bodies, the result of
-     * invoking this function may not be as expected. In the worst case, it
-     * could lead to undefined behavior. An assertion will abort the execution
-     * at runtime in debug mode if a violation is detected.
-     *
-     * @warning
-     * Attempting to clone an invalid entity results in undefined behavior.<br/>
-     * An assertion will abort the execution at runtime in debug mode in case of
-     * invalid entity.
-     *
-     * @param entity A valid entity identifier
-     * @return A valid entity identifier.
-     */
-    entity_type clone(const entity_type entity) ENTT_NOEXCEPT {
-        assert(valid(entity));
-        const auto other = create();
-
-        for(auto pos = pools.size(); pos; --pos) {
-            auto &tup = pools[pos-1];
-            auto &cpool = std::get<0>(tup);
-
-            if(cpool && cpool->has(entity)) {
-                cpool->clone(other, entity);
-                std::get<1>(tup).publish(*this, other);
-            }
-        }
-
-        return other;
-    }
-
     /**
     /**
      * @brief Destroys an entity and lets the registry recycle the identifier.
      * @brief Destroys an entity and lets the registry recycle the identifier.
      *
      *

+ 0 - 40
src/entt/entity/sparse_set.hpp

@@ -377,28 +377,6 @@ public:
         direct.push_back(entity);
         direct.push_back(entity);
     }
     }
 
 
-    /**
-     * @brief Assigns an entity to a sparse set by cloning another entity.
-     *
-     * @warning
-     * Attempting to clone an entity that doesn't belong to the sparse set or to
-     * assign an entity that already belongs to the sparse set results in
-     * undefined behavior.<br/>
-     * An assertion will abort the execution at runtime in debug mode if the
-     * sparse set doesn't contain the entity to clone or if it already contains
-     * the given entity.
-     *
-     * @param entity A valid entity identifier.
-     * @param source A valid entity identifier from which to clone.
-     */
-    inline virtual void clone(const entity_type entity, const entity_type source) {
-        assert(has(source));
-        assert(!has(entity));
-        construct(entity);
-        // useful to suppress warnings when asserts are disabled
-        (void)source;
-    }
-
     /**
     /**
      * @brief Removes an entity from a sparse set.
      * @brief Removes an entity from a sparse set.
      *
      *
@@ -842,24 +820,6 @@ public:
         return instances.back();
         return instances.back();
     }
     }
 
 
-    /**
-     * @brief Assigns an entity to a sparse set by cloning another entity.
-     *
-     * @warning
-     * Attempting to clone an entity that doesn't belong to the sparse set or to
-     * assign an entity that already belongs to the sparse set results in
-     * undefined behavior.<br/>
-     * An assertion will abort the execution at runtime in debug mode if the
-     * sparse set doesn't contain the entity to clone or if it already contains
-     * the given entity.
-     *
-     * @param entity A valid entity identifier.
-     * @param source A valid entity identifier from which to clone.
-     */
-    inline void clone(const entity_type entity, const entity_type source) override {
-        construct(entity, get(source));
-    }
-
     /**
     /**
      * @brief Removes an entity from a sparse set and destroies its object.
      * @brief Removes an entity from a sparse set and destroies its object.
      *
      *

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

@@ -354,23 +354,6 @@ TEST(DefaultRegistry, CreateDestroyEntities) {
     ASSERT_EQ(registry.current(pre), registry.current(post));
     ASSERT_EQ(registry.current(pre), registry.current(post));
 }
 }
 
 
-TEST(DefaultRegistry, CloneEntities) {
-    entt::DefaultRegistry registry;
-
-    const auto entity = registry.create();
-    registry.assign<int>(entity, 42);
-    registry.assign<char>(entity, 'c');
-
-    const auto other = registry.clone(entity);
-
-    ASSERT_TRUE(registry.has<int>(other));
-    ASSERT_TRUE(registry.has<char>(other));
-    ASSERT_EQ(registry.get<int>(entity), registry.get<int>(other));
-    ASSERT_EQ(registry.get<char>(entity), registry.get<char>(other));
-    ASSERT_EQ(registry.get<int>(other), 42);
-    ASSERT_EQ(registry.get<char>(other), 'c');
-}
-
 TEST(DefaultRegistry, AttachSetRemoveTags) {
 TEST(DefaultRegistry, AttachSetRemoveTags) {
     entt::DefaultRegistry registry;
     entt::DefaultRegistry registry;
     const auto &cregistry = registry;
     const auto &cregistry = registry;
@@ -719,11 +702,6 @@ TEST(DefaultRegistry, ComponentSignals) {
 
 
     ASSERT_EQ(listener.counter, 1);
     ASSERT_EQ(listener.counter, 1);
     ASSERT_EQ(listener.last, e1);
     ASSERT_EQ(listener.last, e1);
-
-    e1 = registry.clone(e0);
-
-    ASSERT_EQ(listener.counter, 2);
-    ASSERT_EQ(listener.last, e1);
 }
 }
 
 
 TEST(DefaultRegistry, TagSignals) {
 TEST(DefaultRegistry, TagSignals) {

+ 15 - 37
test/entt/entity/sparse_set.cpp

@@ -54,23 +54,6 @@ TEST(SparseSetNoType, Functionalities) {
     other = std::move(set);
     other = std::move(set);
 }
 }
 
 
-TEST(SparseSetNoType, Clone) {
-    entt::SparseSet<unsigned int> set;
-
-    ASSERT_FALSE(set.has(0));
-    ASSERT_FALSE(set.has(42));
-
-    set.construct(0);
-
-    ASSERT_TRUE(set.has(0));
-    ASSERT_FALSE(set.has(42));
-
-    set.clone(42, 0);
-
-    ASSERT_TRUE(set.has(0));
-    ASSERT_TRUE(set.has(42));
-}
-
 TEST(SparseSetNoType, DataBeginEnd) {
 TEST(SparseSetNoType, DataBeginEnd) {
     entt::SparseSet<unsigned int> set;
     entt::SparseSet<unsigned int> set;
 
 
@@ -324,26 +307,6 @@ TEST(SparseSetWithType, Functionalities) {
     other = std::move(set);
     other = std::move(set);
 }
 }
 
 
-TEST(SparseSetWithType, Clone) {
-    entt::SparseSet<unsigned int, int> set;
-
-    ASSERT_FALSE(set.has(0));
-    ASSERT_FALSE(set.has(42));
-
-    set.construct(0, 3);
-
-    ASSERT_TRUE(set.has(0));
-    ASSERT_FALSE(set.has(42));
-    ASSERT_EQ(set.get(0), 3);
-
-    set.clone(42, 0);
-
-    ASSERT_TRUE(set.has(0));
-    ASSERT_TRUE(set.has(42));
-    ASSERT_EQ(set.get(0), set.get(42));
-    ASSERT_EQ(set.get(42), 3);
-}
-
 TEST(SparseSetWithType, AggregatesMustWork) {
 TEST(SparseSetWithType, AggregatesMustWork) {
     struct AggregateType { int value; };
     struct AggregateType { int value; };
     // the goal of this test is to enforce the requirements for aggregate types
     // the goal of this test is to enforce the requirements for aggregate types
@@ -723,3 +686,18 @@ TEST(SparseSetWithType, ReferencesGuaranteed) {
     ASSERT_EQ(set.get(0).value, 3);
     ASSERT_EQ(set.get(0).value, 3);
     ASSERT_EQ(set.get(1).value, 3);
     ASSERT_EQ(set.get(1).value, 3);
 }
 }
+
+TEST(SparseSetWithType, MoveOnlyComponent) {
+    struct MoveOnlyComponent {
+        MoveOnlyComponent() = default;
+        ~MoveOnlyComponent() = default;
+        MoveOnlyComponent(const MoveOnlyComponent &) = delete;
+        MoveOnlyComponent(MoveOnlyComponent &&) = default;
+        MoveOnlyComponent & operator=(const MoveOnlyComponent &) = delete;
+        MoveOnlyComponent & operator=(MoveOnlyComponent &&) = default;
+    };
+
+    // it's purpose is to ensure that move only components are always accepted
+    entt::SparseSet<unsigned int, MoveOnlyComponent> set;
+    (void)set;
+}