Browse Source

added component-to-entity functionality to the sparse sets + renamed some member functions

Michele Caini 7 years ago
parent
commit
200012fd41

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

@@ -449,7 +449,7 @@ public:
     }
 
     /**
-     * @brief Checks if an entity identifier refers to a valid entity.
+     * @brief Checks if an entity identifier refers to a valid entity (unsafe).
      *
      * Alternative version of `valid`. It accesses the internal data structures
      * without bounds checking and thus it's both unsafe and risky to use.<br/>
@@ -465,7 +465,7 @@ public:
      * @param entity A valid entity identifier.
      * @return True if the identifier is valid, false otherwise.
      */
-    bool fast(const entity_type entity) const ENTT_NOEXCEPT {
+    bool unsafe_valid(const entity_type entity) const ENTT_NOEXCEPT {
         const auto pos = size_type(entity & traits_type::entity_mask);
         assert(pos < entities.size());
         return (entities[pos] == entity);
@@ -1466,8 +1466,8 @@ public:
      * listeners of interest to the new registry and to set up groups.
      *
      * @warning
-     * Attempting to clone components that aren't copyable can result in
-     * unexpected behaviors.<br/>
+     * Attempting to clone components that aren't copyable results in unexpected
+     * behaviors.<br/>
      * A static assertion will abort the compilation when the components
      * provided aren't copy constructible. Otherwise, an assertion will abort
      * the execution at runtime in debug mode in case one or more pools cannot

+ 1 - 1
src/entt/entity/runtime_view.hpp

@@ -82,7 +82,7 @@ class basic_runtime_view {
             const auto sz = size_type(entt & traits_type::entity_mask);
 
             return sz < extent && std::all_of(from, to, [entt](const auto *view) {
-                return view->fast(entt);
+                return view->unsafe_has(entt);
             });
         }
 

+ 41 - 3
src/entt/entity/sparse_set.hpp

@@ -313,15 +313,15 @@ public:
      * you are doing. Prefer the `has` member function instead.
      *
      * @warning
-     * Attempting to use an entity that doesn't belong to the sparse set can
-     * result in undefined behavior.<br/>
+     * Attempting to use an entity that doesn't belong to the sparse set results
+     * in undefined behavior.<br/>
      * An assertion will abort the execution at runtime in debug mode in case of
      * bounds violation.
      *
      * @param entt A valid entity identifier.
      * @return True if the sparse set contains the entity, false otherwise.
      */
-    bool fast(const entity_type entt) const ENTT_NOEXCEPT {
+    bool unsafe_has(const entity_type entt) const ENTT_NOEXCEPT {
         const auto pos = size_type(entt & traits_type::entity_mask);
         assert(pos < reverse.size());
         // testing against null permits to avoid accessing the direct vector
@@ -805,6 +805,44 @@ public:
         return const_cast<object_type *>(std::as_const(*this).raw());
     }
 
+    /**
+     * @brief Returns the entity to which a given component is assigned.
+     * @param instance A valid reference to an object.
+     * @return A valid entity identifier if the instance belongs to the sparse
+     * set, the null entity otherwise.
+     */
+    inline entity_type entity(const object_type &instance) {
+        const auto address = std::addressof(instance);
+        const bool valid = !(instances.data() > address) && (address < (instances.data() + instances.size()));
+        return valid ? sparse_set<entity_type>::data()[address - instances.data()] : null;
+    }
+
+    /**
+     * @brief Returns the entity to which a given component is assigned
+     * (unsafe).
+     *
+     * Alternative version of `entity`. It accesses the underlying data
+     * structures without bounds checking and thus it's both unsafe and risky to
+     * use.<br/>
+     * You should not invoke directly this function unless you know exactly what
+     * you are doing. Prefer the `entity` member function instead.
+     *
+     * @warning
+     * Attempting to use an instance that doesn't belong to the sparse set
+     * results in undefined behavior.<br/>
+     * An assertion will abort the execution at runtime in debug mode in case of
+     * bounds violation.
+     *
+     * @param instance An object that belongs to the sparse set.
+     * @return A valid entity identifier.
+     */
+    inline entity_type unsafe_entity(const object_type &instance) {
+        const auto address = std::addressof(instance);
+        assert(!(instances.data() > address));
+        assert(address < (instances.data() + instances.size()));
+        return sparse_set<entity_type>::data()[address - instances.data()];
+    }
+
     /**
      * @brief Returns an iterator to the beginning.
      *

+ 2 - 2
src/entt/entity/view.hpp

@@ -98,7 +98,7 @@ class basic_view {
             const auto sz = size_type(entt& traits_type::entity_mask);
 
             return sz < extent && std::all_of(unchecked.cbegin(), unchecked.cend(), [entt](const sparse_set<Entity> *view) {
-                return view->fast(entt);
+                return view->unsafe_has(entt);
             });
         }
 
@@ -196,7 +196,7 @@ class basic_view {
             const auto it = std::get<component_iterator_type<Comp>>(raw)++;
             const auto sz = size_type(entt & traits_type::entity_mask);
 
-            if(((sz < extent) && ... && std::get<Indexes>(other)->fast(entt))) {
+            if(((sz < extent) && ... && std::get<Indexes>(other)->unsafe_has(entt))) {
                 // avoided at least the indirection due to the sparse set for the pivot type (see get for more details)
                 if constexpr(std::is_invocable_v<Func, std::add_lvalue_reference_t<Component>...>) {
                     func(get<Comp, Component>(it, entt)...);

+ 3 - 3
test/entt/entity/registry.cpp

@@ -164,11 +164,11 @@ TEST(Registry, Functionalities) {
     ASSERT_EQ(registry.current(e2), entt::registry::version_type{1});
 
     ASSERT_TRUE(registry.valid(e0));
-    ASSERT_TRUE(registry.fast(e0));
+    ASSERT_TRUE(registry.unsafe_valid(e0));
     ASSERT_TRUE(registry.valid(e1));
-    ASSERT_TRUE(registry.fast(e1));
+    ASSERT_TRUE(registry.unsafe_valid(e1));
     ASSERT_FALSE(registry.valid(e2));
-    ASSERT_FALSE(registry.fast(e2));
+    ASSERT_FALSE(registry.unsafe_valid(e2));
 
     ASSERT_EQ(registry.size(), entt::registry::size_type{3});
     ASSERT_EQ(registry.alive(), entt::registry::size_type{2});

+ 39 - 2
test/entt/entity/sparse_set.cpp

@@ -31,7 +31,7 @@ TEST(SparseSetNoType, Functionalities) {
     ASSERT_NE(set.begin(), set.end());
     ASSERT_FALSE(set.has(0));
     ASSERT_TRUE(set.has(42));
-    ASSERT_TRUE(set.fast(42));
+    ASSERT_TRUE(set.unsafe_has(42));
     ASSERT_EQ(set.get(42), 0u);
 
     set.destroy(42);
@@ -392,7 +392,7 @@ TEST(SparseSetWithType, Functionalities) {
     ASSERT_NE(set.begin(), set.end());
     ASSERT_FALSE(set.has(0));
     ASSERT_TRUE(set.has(42));
-    ASSERT_TRUE(set.fast(42));
+    ASSERT_TRUE(set.unsafe_has(42));
     ASSERT_EQ(set.get(42), 3);
     ASSERT_EQ(*set.try_get(42), 3);
     ASSERT_EQ(set.try_get(99), nullptr);
@@ -426,6 +426,43 @@ TEST(SparseSetWithType, Functionalities) {
     other = std::move(set);
 }
 
+TEST(SparseSetWithType, EntityFromComponent) {
+    entt::sparse_set<std::uint64_t, int> set;
+    typename entt::sparse_set<std::uint64_t, int>::entity_type invalid = entt::null;
+
+    set.reserve(3);
+
+    const auto &first = set.construct(42, 3);
+    const auto &second = set.construct(3, 9);
+    const auto &third = set.construct(99, 7);
+
+    ASSERT_NE(set.entity(first), invalid);
+    ASSERT_EQ(set.get(set.entity(first)), first);
+    ASSERT_EQ(&set.get(set.entity(first)), &first);
+
+    ASSERT_NE(set.unsafe_entity(first), invalid);
+    ASSERT_EQ(set.get(set.unsafe_entity(first)), first);
+    ASSERT_EQ(&set.get(set.unsafe_entity(first)), &first);
+
+    ASSERT_NE(set.entity(second), invalid);
+    ASSERT_EQ(set.get(set.entity(second)), second);
+    ASSERT_EQ(&set.get(set.entity(second)), &second);
+
+    ASSERT_NE(set.unsafe_entity(second), invalid);
+    ASSERT_EQ(set.get(set.unsafe_entity(second)), second);
+    ASSERT_EQ(&set.get(set.unsafe_entity(second)), &second);
+
+    ASSERT_NE(set.entity(third), invalid);
+    ASSERT_EQ(set.get(set.entity(third)), third);
+    ASSERT_EQ(&set.get(set.entity(third)), &third);
+
+    ASSERT_NE(set.unsafe_entity(third), invalid);
+    ASSERT_EQ(set.get(set.unsafe_entity(third)), third);
+    ASSERT_EQ(&set.get(set.unsafe_entity(third)), &third);
+
+    ASSERT_EQ(set.entity(0), invalid);
+}
+
 TEST(SparseSetWithType, EmptyType) {
     entt::sparse_set<std::uint64_t, empty_type> set;