瀏覽代碼

any/registry:
* copying an entt::any always returns a copy of the contained object
* registry::storage returns references (eventually const) to the poly storage

Michele Caini 5 年之前
父節點
當前提交
e94c0d003a
共有 5 個文件被更改,包括 53 次插入17 次删除
  1. 0 1
      TODO
  2. 8 5
      src/entt/core/any.hpp
  3. 6 5
      src/entt/entity/registry.hpp
  4. 32 0
      test/entt/core/any.cpp
  5. 7 6
      test/entt/entity/poly_storage.cpp

+ 0 - 1
TODO

@@ -18,7 +18,6 @@
   - ...
 
 WIP:
-* HP: registry::ctx can return entt::any objects directly
 * HP: merge view and view pack
 * HP: invalid view auto-refresh
 * HP: paginate pools

+ 8 - 5
src/entt/core/any.hpp

@@ -42,19 +42,22 @@ class any {
     static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const any &from, [[maybe_unused]] const void *to) {
         if constexpr(!std::is_void_v<Type>) {
             if constexpr(std::is_lvalue_reference_v<Type>) {
-                using base_type = std::remove_reference_t<Type>;
+                using base_type = std::remove_const_t<std::remove_reference_t<Type>>;
 
                 switch(op) {
                 case operation::COPY:
-                    as<any>(to).vtable = from.vtable;
+                    if constexpr(std::is_copy_constructible_v<base_type>) {
+                        as<any>(to).emplace<base_type>(*static_cast<const base_type *>(from.instance));
+                    }
+                    break;
                 case operation::MOVE:
                     as<any>(to).instance = from.instance;
                 case operation::DTOR:
                     break;
                 case operation::COMP:
-                    return compare<std::remove_const_t<base_type>>(from.instance, to) ? to : nullptr;
+                    return compare<base_type>(from.instance, to) ? to : nullptr;
                 case operation::ADDR:
-                    return std::is_const_v<base_type> ? nullptr : from.instance;
+                    return std::is_const_v<std::remove_reference_t<Type>> ? nullptr : from.instance;
                 case operation::CADDR:
                     return from.instance;
                 case operation::REF:
@@ -66,7 +69,7 @@ class any {
                     as<any>(to).instance = from.instance;
                     break;
                 case operation::TYPE:
-                    as<type_info>(to) = type_id<std::remove_const_t<base_type>>();
+                    as<type_info>(to) = type_id<base_type>();
                     break;
                 }
             } else if constexpr(in_situ<Type>) {

+ 6 - 5
src/entt/entity/registry.hpp

@@ -181,14 +181,15 @@ public:
      * @return A valid poly storage if a pool for the given type exists, an
      * empty and thus invalid element otherwise.
      */
-    poly_storage storage(const type_info info) {
-        return info.seq() < pools.size() ? pools[info.seq()].poly : poly_storage{};
+    poly_storage & storage(const type_info info) {
+        ENTT_ASSERT(info.seq() < pools.size() && pools[info.seq()].poly);
+        return pools[info.seq()].poly;
     }
 
     /*! @copydoc storage */
-    poly_storage storage(const type_info info) const {
-        // as_ref forces a constness conversion for the underlying pool
-        return info.seq() < pools.size() ? as_ref(pools[info.seq()].poly) : poly_storage{};
+    const poly_storage & storage(const type_info info) const {
+        ENTT_ASSERT(info.seq() < pools.size() && pools[info.seq()].poly);
+        return pools[info.seq()].poly;
     }
 
     /**

+ 32 - 0
test/entt/core/any.cpp

@@ -837,3 +837,35 @@ TEST(Any, Array) {
 
     ASSERT_EQ(entt::any_cast<const int(&)[1]>(std::as_const(any))[0], 42);
 }
+
+TEST(Any, CopyMoveReference) {
+    auto test = [](int &value, auto ref) {
+        value = 3;
+
+        entt::any any{ref};
+        entt::any move = std::move(any);
+        entt::any copy = move;
+
+        ASSERT_FALSE(any);
+        ASSERT_TRUE(move);
+        ASSERT_TRUE(copy);
+
+        ASSERT_EQ(move.type(), entt::type_id<int>());
+        ASSERT_EQ(copy.type(), entt::type_id<int>());
+
+        ASSERT_EQ(std::as_const(move).data(), &value);
+        ASSERT_NE(std::as_const(copy).data(), &value);
+
+        ASSERT_EQ(entt::any_cast<int>(move), 3);
+        ASSERT_EQ(entt::any_cast<int>(copy), 3);
+
+        value = 42;
+
+        ASSERT_EQ(entt::any_cast<const int &>(move), 42);
+        ASSERT_EQ(entt::any_cast<const int &>(copy), 3);
+    };
+
+    int value{};
+    test(value, std::ref(value));
+    test(value, std::cref(value));
+}

+ 7 - 6
test/entt/entity/poly_storage.cpp

@@ -13,7 +13,7 @@ struct PolyStorage: entt::type_list_cat_t<
     entt::type_list<
         void(entt::basic_registry<Entity> &, const Entity, const void *),
         const void *(const Entity) const,
-        void(entt::basic_registry<Entity> &, entt::basic_registry<Entity> &)
+        void(const entt::basic_registry<Entity> &, entt::basic_registry<Entity> &) const
     >
 > {
     using entity_type = Entity;
@@ -31,7 +31,7 @@ struct PolyStorage: entt::type_list_cat_t<
             return entt::poly_call<base + 1>(*this, entity);
         }
 
-        void copy(entt::basic_registry<Entity> &owner, entt::basic_registry<Entity> &other) {
+        void copy(const entt::basic_registry<Entity> &owner, entt::basic_registry<Entity> &other) const {
             entt::poly_call<base + 2>(*this, owner, other);
         }
     };
@@ -46,7 +46,7 @@ struct PolyStorage: entt::type_list_cat_t<
             return &self.get(entity);
         }
 
-        static void copy(Type &self, entt::basic_registry<entity_type> &owner, entt::basic_registry<entity_type> &other) {
+        static void copy(const Type &self, const entt::basic_registry<entity_type> &owner, entt::basic_registry<entity_type> &other) {
             other.template insert<typename Type::value_type>(self.data(), self.data() + self.size(), self.raw(), self.raw() + self.size());
         }
     };
@@ -79,7 +79,7 @@ TEST(PolyStorage, CopyEntity) {
     ASSERT_FALSE((registry.any_of<int, char>(other)));
 
     registry.visit(entity, [&](const auto info) {
-        auto storage = registry.storage(info);
+        auto &&storage = registry.storage(info);
         storage->emplace(registry, other, storage->get(entity));
     });
 
@@ -103,7 +103,7 @@ TEST(PolyStorage, CopyRegistry) {
     ASSERT_EQ(other.size(), 0u);
 
     other.assign(registry.data(), registry.data() + registry.size(), registry.destroyed());
-    registry.visit([&](const auto info) { registry.storage(info)->copy(registry, other); });
+    registry.visit([&](const auto info) { std::as_const(registry).storage(info)->copy(registry, other); });
 
     ASSERT_EQ(registry.size(), other.size());
     ASSERT_EQ((registry.view<int, char>().size_hint()), (other.view<int, char>().size_hint()));
@@ -122,12 +122,13 @@ TEST(PolyStorage, Constness) {
     entity[0] = registry.create();
     registry.emplace<int>(entity[0], 42);
 
+    // cannot invoke remove on a const storage, let's copy the returned value
     auto cstorage = cregistry.storage(entt::type_id<int>());
 
     ASSERT_DEATH(cstorage->remove(registry, std::begin(entity), std::end(entity)), ".*");
     ASSERT_TRUE(registry.all_of<int>(entity[0]));
 
-    auto storage = registry.storage(entt::type_id<int>());
+    auto &&storage = registry.storage(entt::type_id<int>());
     storage->remove(registry, std::begin(entity), std::end(entity));
 
     ASSERT_FALSE(registry.all_of<int>(entity[0]));