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

cloning an entity is no longer allowed

Michele Caini 7 лет назад
Родитель
Сommit
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
 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
 // constructs a naked entity with no components and returns its identifier
 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
 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
-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
 functionalities required to test them and get out of the them all the
 information they carry:

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

@@ -408,51 +408,6 @@ public:
         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.
      *

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

@@ -377,28 +377,6 @@ public:
         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.
      *
@@ -842,24 +820,6 @@ public:
         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.
      *

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

@@ -354,23 +354,6 @@ TEST(DefaultRegistry, CreateDestroyEntities) {
     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) {
     entt::DefaultRegistry registry;
     const auto &cregistry = registry;
@@ -719,11 +702,6 @@ TEST(DefaultRegistry, ComponentSignals) {
 
     ASSERT_EQ(listener.counter, 1);
     ASSERT_EQ(listener.last, e1);
-
-    e1 = registry.clone(e0);
-
-    ASSERT_EQ(listener.counter, 2);
-    ASSERT_EQ(listener.last, e1);
 }
 
 TEST(DefaultRegistry, TagSignals) {

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

@@ -54,23 +54,6 @@ TEST(SparseSetNoType, Functionalities) {
     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) {
     entt::SparseSet<unsigned int> set;
 
@@ -324,26 +307,6 @@ TEST(SparseSetWithType, Functionalities) {
     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) {
     struct AggregateType { int value; };
     // 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(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;
+}