Sfoglia il codice sorgente

review sigh + added set/move for tags

Michele Caini 8 anni fa
parent
commit
28ce491dd5
5 ha cambiato i file con 98 aggiunte e 21 eliminazioni
  1. 13 1
      README.md
  2. 0 2
      TODO
  3. 56 8
      src/entt/entity/registry.hpp
  4. 13 9
      src/entt/signal/sigh.hpp
  5. 16 1
      test/entt/entity/registry.cpp

+ 13 - 1
README.md

@@ -556,7 +556,19 @@ registry.remove<PlayingCharacter>();
 registry.remove<Camera>();
 ```
 
-If in doubt about whether or not a tag has already an owner, the `has` member
+In case a tag already has an owner, its content can be updated by means of the
+`set` member function template and the ownership of the tag can be transferred
+to another entity using the `move` member function template:
+
+```
+// replaces the content of the given tag
+Point &point = registry.set<Point>(1.f, 1.f);
+
+// transfers the ownership of the tag to another entity
+entity_type prev = registry.move<Point>(next);
+```
+
+If in doubt about whether or not a tag already has an owner, the `has` member
 function template may be useful:
 
 ```cpp

+ 0 - 2
TODO

@@ -1,11 +1,9 @@
 * custom allocators and EnTT allocator-aware in general (long term feature, I don't actually need it at the moment) - see #22
 * to analyze, long term feature: systems organizer based on dependency graphs for implicit parallelism (I don't want to think anymore in future :-))
-* save/restore functionalities - see #27
 * scene management (I prefer the concept of spaces, that is a kind of scene anyway)
 * blueprint registry - kind of factory to create entitites template for initialization (get rid of the extra versions of Registry::create)
 * review doc: separate it in multiple md/dox files, reduce the readme to a minimum and provide users with links to the online documentation on gh-pages
 * debugging tools (#60): the issue online already contains interesting tips on this, look at it
 * signals on component creation/destruction: crtp + internal detection, probably it works - test it!!
 * define a macro for the noexcept policy, so as to provide users with an easy way to disable exception handling
-* explore a way to safely define a "replace" function for tags (mainly for consistency with components)
 * AOB

+ 56 - 8
src/entt/entity/registry.hpp

@@ -477,7 +477,7 @@ public:
     }
 
     /**
-     * @brief Attaches a tag to an entity.
+     * @brief Attaches the given tag to an entity.
      *
      * Usually, pools of components allocate enough memory to store a bunch of
      * elements even if only one of them is used. On the other hand, there are
@@ -513,7 +513,7 @@ public:
     }
 
     /**
-     * @brief Removes a tag from its owner, if any.
+     * @brief Removes the given tag from its owner, if any.
      * @tparam Tag Type of tag to remove.
      */
     template<typename Tag>
@@ -524,7 +524,7 @@ public:
     }
 
     /**
-     * @brief Checks if a tag has an owner.
+     * @brief Checks if the given tag has an owner.
      * @tparam Tag Type of tag for which to perform the check.
      * @return True if the tag already has an owner, false otherwise.
      */
@@ -539,7 +539,7 @@ public:
     }
 
     /**
-     * @brief Returns a reference to a tag.
+     * @brief Returns a reference to the given tag.
      *
      * @warning
      * Attempting to get a tag that hasn't an owner results in undefined
@@ -557,7 +557,7 @@ public:
     }
 
     /**
-     * @brief Returns a reference to a tag.
+     * @brief Returns a reference to the given tag.
      *
      * @warning
      * Attempting to get a tag that hasn't an owner results in undefined
@@ -574,7 +574,56 @@ public:
     }
 
     /**
-     * @brief Gets the owner of a tag, if any.
+     * @brief Replaces the given tag.
+     *
+     * A new instance of the given tag is created and initialized with the
+     * arguments provided (the tag must have a proper constructor or be of
+     * aggregate type).
+     *
+     * @warning
+     * Attempting to replace a tag that hasn't an owner results in undefined
+     * behavior.<br/>
+     * An assertion will abort the execution at runtime in debug mode if the
+     * tag hasn't been previously attached to an entity.
+     *
+     * @tparam Tag Type of tag to replace.
+     * @tparam Args Types of arguments to use to construct the tag.
+     * @param args Parameters to use to initialize the tag.
+     * @return A reference to the tag.
+     */
+    template<typename Tag, typename... Args>
+    Tag & set(Args &&... args) {
+        return get<Tag>() = Tag{std::forward<Args>(args)...};
+    }
+
+    /**
+     * @brief Changes the owner of the given tag.
+     *
+     * The ownership of the tag is transferred from one entity to another.
+     *
+     * @warning
+     * Attempting to use an invalid entity or to transfer the ownership of a tag
+     * that hasn't an owner results in undefined behavior.<br/>
+     * An assertion will abort the execution at runtime in debug mode in case of
+     * invalid entity or if the tag hasn't been previously attached to an
+     * entity.
+     *
+     * @tparam Tag Type of tag of which to transfer the ownership.
+     * @param entity A valid entity identifier.
+     * @return A valid entity identifier.
+     */
+    template<typename Tag>
+    entity_type move(entity_type entity) {
+        assert(valid(entity));
+        assert(has<Tag>());
+        const auto ttype = tag_family::type<Tag>();
+        const auto owner = tags[ttype]->entity;
+        tags[ttype]->entity = entity;
+        return owner;
+    }
+
+    /**
+     * @brief Gets the owner of the given tag, if any.
      *
      * @warning
      * Attempting to get the owner of a tag that hasn't been previously attached
@@ -759,8 +808,7 @@ public:
      */
     template<typename Component, typename... Args>
     Component & replace(entity_type entity, Args &&... args) {
-        assert(valid(entity));
-        return (pool<Component>().get(entity) = Component{std::forward<Args>(args)...});
+        return (get<Component>(entity) = Component{std::forward<Args>(args)...});
     }
 
     /**

+ 13 - 9
src/entt/signal/sigh.hpp

@@ -24,17 +24,21 @@ struct Invoker<Ret(Args...), Collector> {
 
     virtual ~Invoker() = default;
 
-    template<typename SFINAE = Ret>
-    typename std::enable_if_t<std::is_void<SFINAE>::value, bool>
-    invoke(Collector &, proto_type proto, void *instance, Args... args) {
-        proto(instance, args...);
-        return true;
+    bool invoke(Collector &collector, proto_type proto, void *instance, Args... args) {
+        return collector(proto(instance, args...));
     }
+};
 
-    template<typename SFINAE = Ret>
-    typename std::enable_if_t<!std::is_void<SFINAE>::value, bool>
-    invoke(Collector &collector, proto_type proto, void *instance, Args... args) {
-        return collector(proto(instance, args...));
+
+template<typename... Args, typename Collector>
+struct Invoker<void(Args...), Collector> {
+    using proto_type = void(*)(void *, Args...);
+    using call_type = std::pair<void *, proto_type>;
+
+    virtual ~Invoker() = default;
+
+    bool invoke(Collector &, proto_type proto, void *instance, Args... args) {
+        return (proto(instance, args...), true);
     }
 };
 

+ 16 - 1
test/entt/entity/registry.cpp

@@ -285,7 +285,7 @@ TEST(DefaultRegistry, CreateDestroyEntities) {
     ASSERT_EQ(registry.current(pre), registry.current(post));
 }
 
-TEST(DefaultRegistry, AttachRemoveTags) {
+TEST(DefaultRegistry, AttachSetRemoveTags) {
     entt::DefaultRegistry registry;
     const auto &cregistry = registry;
 
@@ -299,6 +299,21 @@ TEST(DefaultRegistry, AttachRemoveTags) {
     ASSERT_EQ(cregistry.get<int>(), 42);
     ASSERT_EQ(registry.attachee<int>(), entity);
 
+    registry.set<int>(3);
+
+    ASSERT_TRUE(registry.has<int>());
+    ASSERT_EQ(registry.get<int>(), 3);
+    ASSERT_EQ(cregistry.get<int>(), 3);
+    ASSERT_EQ(registry.attachee<int>(), entity);
+
+    auto other = registry.create();
+    registry.move<int>(other);
+
+    ASSERT_TRUE(registry.has<int>());
+    ASSERT_EQ(registry.get<int>(), 3);
+    ASSERT_EQ(cregistry.get<int>(), 3);
+    ASSERT_EQ(registry.attachee<int>(), other);
+
     registry.remove<int>();
 
     ASSERT_FALSE(registry.has<int>());