any/registry:

* copying an entt::any always returns a copy of the contained object
* registry::storage returns references (eventually const) to the poly storage
This commit is contained in:
Michele Caini
2021-02-08 11:46:22 +01:00
parent 5c46ccb37e
commit e94c0d003a
5 changed files with 53 additions and 17 deletions

1
TODO
View File

@@ -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

View File

@@ -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>) {

View File

@@ -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;
}
/**

View File

@@ -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));
}

View File

@@ -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]));