Bläddra i källkod

more on context variables

Michele Caini 7 år sedan
förälder
incheckning
e7f2c6b5ba
4 ändrade filer med 30 tillägg och 32 borttagningar
  1. 1 0
      TODO
  2. 5 4
      docs/entity.md
  3. 11 17
      src/entt/entity/registry.hpp
  4. 13 11
      test/entt/entity/registry.cpp

+ 1 - 0
TODO

@@ -21,3 +21,4 @@
 * add a sort of "fast each" for when users know they are not to add/remove components, it can use directly raw access and improve even further performance
 * types defined at runtime that refer to the same compile-time type (but to different pools) are possible, the library is almost there
 * view/group iterators that return entities and components? I'd still like to have it :-)
+* use try_get in the multi component view (each), it should have better perf

+ 5 - 4
docs/entity.md

@@ -838,15 +838,16 @@ newly created instance later on:
 // creates a new context variable initialized with the given values
 registry.set<my_type>(42, 'c');
 
-// gets a context variable associated with a registry
-auto &var = registry.ctx<my_type>();
+if(auto *var = registry.ctx<my_type>(); var) {
+    // uses the context variable associated with a registry, if any
+}
 ```
 
 The type of a context variable must be such that it's default constructible and
 can be moved. The `set` member function either creates a new instance of the
 context variable or overwrites an already existing one if any. The `ctx` member
-function requires that the context variable exist to work properly and doesn't
-create it silently under the hood.
+function returns a pointer to the context variable if it exists, otherwise it
+returns a null pointer. This fits well with the `if` statement with initializer.
 
 # Views and Groups
 

+ 11 - 17
src/entt/entity/registry.hpp

@@ -1605,7 +1605,8 @@ public:
                 std::swap(vars[ctype], vars.back());
                 wrapper = vars[ctype].get();
             } else if(!wrapper) {
-                wrapper = vars.emplace_back(std::make_unique<type_wrapper<Type>>()).get();
+                vars[ctype] = std::make_unique<type_wrapper<Type>>();
+                wrapper = vars[ctype].get();
             }
         }
 
@@ -1617,19 +1618,13 @@ public:
     }
 
     /**
-     * @brief Returns a reference to an object in the context of the registry.
-     *
-     * @warning
-     * Attempting to get an object that doesn't exist in the context of the
-     * registry results in undefined behavior.<br/>
-     * An assertion will abort the execution at runtime in debug mode if the
-     * object isn't part of the context of the registry.
-     *
+     * @brief Returns a pointer to an object in the context of the registry.
      * @tparam Type Type of object to get.
-     * @return A reference to the object.
+     * @return A pointer to the object if it exists in the context of the
+     * registry, a null pointer otherwise.
      */
     template<typename Type>
-    const Type & ctx() const ENTT_NOEXCEPT {
+    const Type * ctx() const ENTT_NOEXCEPT {
         const auto ctype = runtime_type<Type, context_family>();
 
         if constexpr(is_named_type_v<Type>) {
@@ -1637,18 +1632,17 @@ public:
                 return candidate && candidate->runtime_type == ctype;
             });
 
-            assert(it != vars.cend());
-            return static_cast<const type_wrapper<Type> *>(it->get())->value;
+            return (it == vars.cend()) ? nullptr : &static_cast<const type_wrapper<Type> &>(**it).value;
         } else {
-            assert(ctype < vars.size() && vars[ctype] && vars[ctype]->runtime_type == ctype);
-            return static_cast<const type_wrapper<Type> *>(vars[ctype].get())->value;
+            const bool valid = ctype < vars.size() && vars[ctype] && vars[ctype]->runtime_type == ctype;
+            return valid ? &static_cast<const type_wrapper<Type> &>(*vars[ctype]).value : nullptr;
         }
     }
 
     /*! @copydoc ctx */
     template<typename Type>
-    Type & ctx() ENTT_NOEXCEPT {
-        return const_cast<Type &>(std::as_const(*this).template ctx<Type>());
+    Type * ctx() ENTT_NOEXCEPT {
+        return const_cast<Type *>(std::as_const(*this).template ctx<Type>());
     }
 
 private:

+ 13 - 11
test/entt/entity/registry.cpp

@@ -35,22 +35,24 @@ struct listener {
 TEST(Registry, Context) {
     entt::registry registry;
 
-    const auto &ivalue = registry.set<int>(0);
-    const auto &cvalue = registry.set<char>('c');
-    const auto &dvalue = registry.set<double>(1.);
+    registry.set<char>('c');
+    registry.set<int>(0);
+    registry.set<double>(1.);
     registry.set<int>(42);
 
-    ASSERT_EQ(ivalue, 42);
-    ASSERT_EQ(ivalue, registry.ctx<int>());
-    ASSERT_EQ(registry.ctx<int>(), std::as_const(registry).ctx<int>());
-
-    ASSERT_EQ(cvalue, 'c');
-    ASSERT_EQ(cvalue, registry.ctx<char>());
+    ASSERT_EQ(*registry.ctx<char>(), 'c');
+    ASSERT_NE(registry.ctx<char>(), nullptr);
     ASSERT_EQ(registry.ctx<char>(), std::as_const(registry).ctx<char>());
 
-    ASSERT_EQ(dvalue, 1.);
-    ASSERT_EQ(dvalue, registry.ctx<double>());
+    ASSERT_EQ(*registry.ctx<int>(), 42);
+    ASSERT_NE(registry.ctx<int>(), nullptr);
+    ASSERT_EQ(registry.ctx<int>(), std::as_const(registry).ctx<int>());
+
+    ASSERT_EQ(*registry.ctx<double>(), 1.);
+    ASSERT_NE(registry.ctx<double>(), nullptr);
     ASSERT_EQ(registry.ctx<double>(), std::as_const(registry).ctx<double>());
+
+    ASSERT_EQ(registry.ctx<float>(), nullptr);
 }
 
 TEST(Registry, Types) {