Kaynağa Gözat

added get_if where possible

Michele Caini 7 yıl önce
ebeveyn
işleme
5859a18b3a

+ 0 - 1
TODO

@@ -15,7 +15,6 @@
 * composable looper so as to pack erased systems, compose runners at different rates and run them at once in the loop
 * meta: sort of meta view based on meta stuff to iterate entities, void * and meta info objects
 * meta: move-to-head optimization when searching by name on parts (data, func, etc)
-* registry::probe<component>(entt) (returns a component * if entt has the component, nullptr otherwise)
 * hashed string: add implicit check on construction for uniqueness (optional)
 * add a note about multithreading support to the README file
 * signals on entity creation/destruction

+ 32 - 12
src/entt/entity/actor.hpp

@@ -120,23 +120,43 @@ struct actor {
     }
 
     /**
-     * @brief Returns a reference to the given component for an actor.
-     * @tparam Component Type of the component to get.
-     * @return A reference to the instance of the component owned by the actor.
+     * @brief Returns references to the given components for an actor.
+     * @tparam Component Types of components to get.
+     * @return References to the components owned by the actor.
      */
-    template<typename Component>
-    const Component & get() const ENTT_NOEXCEPT {
-        return reg->template get<Component>(entt);
+    template<typename... Component>
+    decltype(auto) get() const ENTT_NOEXCEPT {
+        return reg->template get<Component...>(entt);
     }
 
     /**
-     * @brief Returns a reference to the given component for an actor.
-     * @tparam Component Type of the component to get.
-     * @return A reference to the instance of the component owned by the actor.
+     * @brief Returns references to the given components for an actor.
+     * @tparam Component Types of components to get.
+     * @return References to the components owned by the actor.
      */
-    template<typename Component>
-    inline Component & get() ENTT_NOEXCEPT {
-        return const_cast<Component &>(std::as_const(*this).template get<Component>());
+    template<typename... Component>
+    decltype(auto) get() ENTT_NOEXCEPT {
+        return reg->template get<Component...>(entt);
+    }
+
+    /**
+     * @brief Returns pointers to the given components for an actor.
+     * @tparam Component Types of components to get.
+     * @return Pointers to the components owned by the actor.
+     */
+    template<typename... Component>
+    auto get_if() const ENTT_NOEXCEPT {
+        return reg->template get_if<Component...>(entt);
+    }
+
+    /**
+     * @brief Returns pointers to the given components for an actor.
+     * @tparam Component Types of components to get.
+     * @return Pointers to the components owned by the actor.
+     */
+    template<typename... Component>
+    auto get_if() ENTT_NOEXCEPT {
+        return reg->template get_if<Component...>(entt);
     }
 
     /**

+ 31 - 6
src/entt/entity/prototype.hpp

@@ -49,11 +49,6 @@ class prototype final {
         basic_fn_type *assign;
     };
 
-    template<typename Component>
-    inline const Component & component() const ENTT_NOEXCEPT {
-        return reg->template get<component_wrapper<Component>>(entity).component;
-    }
-
     void release() {
         if(reg->valid(entity)) {
             reg->destroy(entity);
@@ -189,7 +184,8 @@ public:
     template<typename... Component>
     decltype(auto) get() const ENTT_NOEXCEPT {
         if constexpr(sizeof...(Component) == 1) {
-            return component<Component...>();
+            const auto &component = reg->template get<component_wrapper<Component...>>(entity).component;
+            return component;
         } else {
             return std::tuple<const Component &...>{get<Component>()...};
         }
@@ -216,6 +212,35 @@ public:
         }
     }
 
+    /**
+     * @brief Returns pointers to the given components.
+     * @tparam Component Types of components to get.
+     * @return Pointers to the components owned by the prototype.
+     */
+    template<typename... Component>
+    auto get_if() const ENTT_NOEXCEPT {
+        if constexpr(sizeof...(Component) == 1) {
+            const auto *wrapper = reg->template get_if<component_wrapper<Component...>>(entity);
+            return wrapper ? &wrapper->component : nullptr;
+        } else {
+            return std::tuple<const Component *...>{get_if<Component>()...};
+        }
+    }
+
+    /**
+     * @brief Returns pointers to the given components.
+     * @tparam Component Types of components to get.
+     * @return Pointers to the components owned by the prototype.
+     */
+    template<typename... Component>
+    inline auto get_if() ENTT_NOEXCEPT {
+        if constexpr(sizeof...(Component) == 1) {
+            return (const_cast<Component *>(std::as_const(*this).template get_if<Component>()), ...);
+        } else {
+            return std::tuple<Component *...>{get_if<Component>()...};
+        }
+    }
+
     /**
      * @brief Creates a new entity using a given prototype.
      *

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

@@ -624,6 +624,50 @@ public:
         }
     }
 
+    /**
+     * @brief Returns pointers to the given components for an entity.
+     *
+     * @warning
+     * Attempting to use an invalid entity results in undefined behavior.<br/>
+     * An assertion will abort the execution at runtime in debug mode in case of
+     * invalid entity.
+     *
+     * @tparam Component Types of components to get.
+     * @param entity A valid entity identifier.
+     * @return Pointers to the components owned by the entity.
+     */
+    template<typename... Component>
+    auto get_if([[maybe_unused]] const entity_type entity) const ENTT_NOEXCEPT {
+        assert(valid(entity));
+
+        if constexpr(sizeof...(Component) == 1) {
+            return managed<Component...>() ? pool<Component...>().get_if(entity) : nullptr;
+        } else {
+            return std::tuple<const Component *...>{get_if<Component>(entity)...};
+        }
+    }
+
+    /**
+     * @brief Returns pointers to the given components for an entity.
+     *
+     * @warning
+     * Attempting to use an invalid entity results in undefined behavior.<br/>
+     * An assertion will abort the execution at runtime in debug mode in case of
+     * invalid entity.
+     *
+     * @tparam Component Types of components to get.
+     * @param entity A valid entity identifier.
+     * @return Pointers to the components owned by the entity.
+     */
+    template<typename... Component>
+    inline auto get_if([[maybe_unused]] const entity_type entity) ENTT_NOEXCEPT {
+        if constexpr(sizeof...(Component) == 1) {
+            return (const_cast<Component *>(std::as_const(*this).template get_if<Component>(entity)), ...);
+        } else {
+            return std::tuple<Component *...>{get_if<Component>(entity)...};
+        }
+    }
+
     /**
      * @brief Replaces the given component for an entity.
      *

+ 24 - 6
src/entt/entity/sparse_set.hpp

@@ -683,7 +683,7 @@ class sparse_set<Entity, Type>: public sparse_set<Entity> {
     };
 
 public:
-    /*! @brief Type of the objects associated to the entities. */
+    /*! @brief Type of the objects associated with the entities. */
     using object_type = Type;
     /*! @brief Underlying entity identifier. */
     using entity_type = typename underlying_type::entity_type;
@@ -881,7 +881,7 @@ public:
     }
 
     /**
-     * @brief Returns the object associated to an entity.
+     * @brief Returns the object associated with an entity.
      *
      * @warning
      * Attempting to use an entity that doesn't belong to the sparse set results
@@ -890,14 +890,14 @@ public:
      * sparse set doesn't contain the given entity.
      *
      * @param entity A valid entity identifier.
-     * @return The object associated to the entity.
+     * @return The object associated with the entity.
      */
     const object_type & get(const entity_type entity) const ENTT_NOEXCEPT {
         return instances[underlying_type::get(entity)];
     }
 
     /**
-     * @brief Returns the object associated to an entity.
+     * @brief Returns the object associated with an entity.
      *
      * @warning
      * Attempting to use an entity that doesn't belong to the sparse set results
@@ -906,12 +906,30 @@ public:
      * sparse set doesn't contain the given entity.
      *
      * @param entity A valid entity identifier.
-     * @return The object associated to the entity.
+     * @return The object associated with the entity.
      */
     inline object_type & get(const entity_type entity) ENTT_NOEXCEPT {
         return const_cast<object_type &>(std::as_const(*this).get(entity));
     }
 
+    /**
+     * @brief Returns a pointer to the object associated with an entity, if any.
+     * @param entity A valid entity identifier.
+     * @return The object associated with the entity, if any.
+     */
+    const object_type * get_if(const entity_type entity) const ENTT_NOEXCEPT {
+        return underlying_type::has(entity) ? (instances.data() + underlying_type::get(entity)) : nullptr;
+    }
+
+    /**
+     * @brief Returns a pointer to the object associated with an entity, if any.
+     * @param entity A valid entity identifier.
+     * @return The object associated with the entity, if any.
+     */
+    inline object_type * get_if(const entity_type entity) ENTT_NOEXCEPT {
+        return const_cast<object_type *>(std::as_const(*this).get_if(entity));
+    }
+
     /**
      * @brief Assigns an entity to a sparse set and constructs its object.
      *
@@ -929,7 +947,7 @@ public:
      * @tparam Args Types of arguments to use to construct the object.
      * @param entity A valid entity identifier.
      * @param args Parameters to use to construct an object for the entity.
-     * @return The object associated to the entity.
+     * @return The object associated with the entity.
      */
     template<typename... Args>
     object_type & construct(const entity_type entity, Args &&... args) {

+ 27 - 17
test/entt/entity/actor.cpp

@@ -3,8 +3,6 @@
 #include <entt/entity/actor.hpp>
 #include <entt/entity/registry.hpp>
 
-struct actor_component final {};
-
 TEST(Actor, Component) {
     entt::registry<> registry;
     entt::actor actor{registry};
@@ -12,31 +10,43 @@ TEST(Actor, Component) {
 
     ASSERT_EQ(&registry, &actor.backend());
     ASSERT_EQ(&registry, &cactor.backend());
-    ASSERT_TRUE(registry.empty<actor_component>());
+    ASSERT_TRUE(registry.empty<int>());
     ASSERT_FALSE(registry.empty());
-    ASSERT_FALSE(actor.has<actor_component>());
-
-    const auto &component = actor.assign<actor_component>();
-
-    ASSERT_EQ(&component, &actor.get<actor_component>());
-    ASSERT_EQ(&component, &cactor.get<actor_component>());
-    ASSERT_FALSE(registry.empty<actor_component>());
+    ASSERT_FALSE(actor.has<int>());
+
+    const auto &cint = actor.assign<int>();
+    const auto &cchar = actor.assign<char>();
+
+    ASSERT_EQ(&cint, &actor.get<int>());
+    ASSERT_EQ(&cchar, &cactor.get<char>());
+    ASSERT_EQ(&cint, &std::get<0>(actor.get<int, char>()));
+    ASSERT_EQ(&cchar, &std::get<1>(actor.get<int, char>()));
+    ASSERT_EQ(&cint, std::get<0>(actor.get_if<int, char, double>()));
+    ASSERT_EQ(&cchar, std::get<1>(actor.get_if<int, char, double>()));
+    ASSERT_EQ(nullptr, std::get<2>(actor.get_if<int, char, double>()));
+    ASSERT_EQ(nullptr, actor.get_if<double>());
+    ASSERT_EQ(&cchar, actor.get_if<char>());
+    ASSERT_EQ(&cint, actor.get_if<int>());
+
+    ASSERT_FALSE(registry.empty<int>());
     ASSERT_FALSE(registry.empty());
-    ASSERT_TRUE(actor.has<actor_component>());
+    ASSERT_TRUE(actor.has<int>());
+    ASSERT_TRUE(actor.has<char>());
+    ASSERT_FALSE(actor.has<double>());
 
-    actor.remove<actor_component>();
+    actor.remove<int>();
 
-    ASSERT_TRUE(registry.empty<actor_component>());
+    ASSERT_TRUE(registry.empty<int>());
     ASSERT_FALSE(registry.empty());
-    ASSERT_FALSE(actor.has<actor_component>());
+    ASSERT_FALSE(actor.has<int>());
 }
 
 TEST(Actor, EntityLifetime) {
     entt::registry<> registry;
     auto *actor = new entt::actor{registry};
-    actor->assign<actor_component>();
+    actor->assign<int>();
 
-    ASSERT_FALSE(registry.empty<actor_component>());
+    ASSERT_FALSE(registry.empty<int>());
     ASSERT_FALSE(registry.empty());
 
     registry.each([actor](const auto entity) {
@@ -45,6 +55,6 @@ TEST(Actor, EntityLifetime) {
 
     delete actor;
 
-    ASSERT_TRUE(registry.empty<actor_component>());
+    ASSERT_TRUE(registry.empty<int>());
     ASSERT_TRUE(registry.empty());
 }

+ 8 - 0
test/entt/entity/prototype.cpp

@@ -21,6 +21,14 @@ TEST(Prototype, SameRegistry) {
     ASSERT_EQ(std::get<0>(prototype.get<int, char>()), 3);
     ASSERT_EQ(std::get<1>(cprototype.get<int, char>()), 'c');
 
+    ASSERT_NE(prototype.get_if<int>(), nullptr);
+    ASSERT_NE(prototype.get_if<char>(), nullptr);
+    ASSERT_EQ(prototype.get_if<double>(), nullptr);
+    ASSERT_EQ(*prototype.get_if<int>(), 3);
+    ASSERT_EQ(*cprototype.get_if<char>(), 'c');
+    ASSERT_EQ(*std::get<0>(prototype.get_if<int, char, double>()), 3);
+    ASSERT_EQ(*std::get<1>(cprototype.get_if<int, char, double>()), 'c');
+
     const auto e0 = prototype.create();
 
     ASSERT_TRUE((prototype.has<int, char>()));

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

@@ -74,6 +74,13 @@ TEST(Registry, Functionalities) {
     ASSERT_FALSE((registry.has<int, char>(e0)));
     ASSERT_TRUE((registry.has<int, char>(e1)));
 
+    ASSERT_EQ(registry.get_if<int>(e0), nullptr);
+    ASSERT_NE(registry.get_if<int>(e1), nullptr);
+    ASSERT_EQ(registry.get_if<char>(e0), nullptr);
+    ASSERT_NE(registry.get_if<char>(e1), nullptr);
+    ASSERT_EQ(registry.get_if<double>(e0), nullptr);
+    ASSERT_EQ(registry.get_if<double>(e1), nullptr);
+
     ASSERT_EQ(registry.assign<int>(e0, 42), 42);
     ASSERT_EQ(registry.assign<char>(e0, 'c'), 'c');
     ASSERT_NO_THROW(registry.remove<int>(e1));
@@ -96,8 +103,16 @@ TEST(Registry, Functionalities) {
     ASSERT_EQ(registry.get<int>(e0), 42);
     ASSERT_EQ(registry.get<char>(e0), 'c');
 
+    ASSERT_NE(registry.get_if<int>(e0), nullptr);
+    ASSERT_NE(registry.get_if<char>(e0), nullptr);
+    ASSERT_EQ(registry.get_if<double>(e0), nullptr);
+    ASSERT_EQ(*registry.get_if<int>(e0), 42);
+    ASSERT_EQ(*registry.get_if<char>(e0), 'c');
+
     ASSERT_EQ(std::get<0>(registry.get<int, char>(e0)), 42);
+    ASSERT_EQ(*std::get<0>(registry.get_if<int, char, double>(e0)), 42);
     ASSERT_EQ(std::get<1>(static_cast<const entt::registry<> &>(registry).get<int, char>(e0)), 'c');
+    ASSERT_EQ(*std::get<1>(static_cast<const entt::registry<> &>(registry).get_if<int, char, double>(e0)), 'c');
 
     ASSERT_EQ(registry.get<int>(e0), registry.get<int>(e2));
     ASSERT_EQ(registry.get<char>(e0), registry.get<char>(e2));