helper: storage-based to_entity function

This commit is contained in:
Michele Caini
2023-10-17 14:07:04 +02:00
parent 173c4e1c78
commit 9d33ae86be
3 changed files with 93 additions and 58 deletions

2
TODO
View File

@@ -16,7 +16,7 @@ TODO (high prio):
* update view doc: single vs multi type views are no longer a thing actually
* further improve meta resolve function by id (bimap)
* make ::pack part of the sparse set interface
* storage-based to_entity and invoke helpers
* storage-based invoke helpers (update sigh mixin to also support storage based cbs)
* make nth_argument use function types rather than pointers
* ===> TEST: view (scoped begin) tests after the last changes

View File

@@ -9,6 +9,7 @@
#include "../signal/delegate.hpp"
#include "fwd.hpp"
#include "group.hpp"
#include "storage.hpp"
#include "view.hpp"
namespace entt {
@@ -115,27 +116,41 @@ void invoke(Registry &reg, const typename Registry::entity_type entt) {
* @brief Returns the entity associated with a given component.
*
* @warning
* Currently, this function only works correctly with the default pool as it
* Currently, this function only works correctly with the default storage as it
* makes assumptions about how the components are laid out.
*
* @tparam Registry Basic registry type.
* @tparam Args Storage type template parameters.
* @param storage A storage that contains the given component.
* @param instance A valid component instance.
* @return The entity associated with the given component.
*/
template<typename... Args>
auto to_entity(const basic_storage<Args...> &storage, const typename basic_storage<Args...>::value_type &instance) -> typename basic_storage<Args...>::entity_type {
constexpr auto page_size = basic_storage<Args...>::traits_type::page_size;
const typename basic_storage<Args...>::base_type &base = storage;
const auto *addr = std::addressof(instance);
for(auto it = base.rbegin(), last = base.rend(); it < last; it += page_size) {
if(const auto dist = (addr - std::addressof(storage.get(*it))); dist >= 0 && dist < static_cast<decltype(dist)>(page_size)) {
return *(it + dist);
}
}
return null;
}
/**
* @copybrief to_entity
* @tparam Args Registry type template parameters.
* @tparam Component Type of component.
* @param reg A registry that contains the given entity and its components.
* @param instance A valid component instance.
* @return The entity associated with the given component.
*/
template<typename Registry, typename Component>
typename Registry::entity_type to_entity(const Registry &reg, const Component &instance) {
template<typename... Args, typename Component>
[[deprecated("use storage based to_entity instead")]] typename basic_registry<Args...>::entity_type to_entity(const basic_registry<Args...> &reg, const Component &instance) {
if(const auto *storage = reg.template storage<Component>(); storage) {
constexpr auto page_size = std::remove_const_t<std::remove_pointer_t<decltype(storage)>>::traits_type::page_size;
const typename Registry::common_type &base = *storage;
const auto *addr = std::addressof(instance);
for(auto it = base.rbegin(), last = base.rend(); it < last; it += page_size) {
if(const auto dist = (addr - std::addressof(storage->get(*it))); dist >= 0 && dist < static_cast<decltype(dist)>(page_size)) {
return *(it + dist);
}
}
return to_entity(*storage, instance);
}
return null;

View File

@@ -1,4 +1,5 @@
#include <gtest/gtest.h>
#include <entt/entity/component.hpp>
#include <entt/entity/entity.hpp>
#include <entt/entity/helper.hpp>
#include <entt/entity/registry.hpp>
@@ -11,16 +12,29 @@ struct clazz {
entt::entity entt{entt::null};
};
struct stable_type {
static constexpr auto in_place_delete = true;
int value;
};
void sigh_callback(int &value) {
++value;
}
TEST(Helper, AsView) {
struct pointer_stable {
static constexpr auto in_place_delete = true;
int value{};
};
template<typename Type>
struct ToEntity: testing::Test {
using type = Type;
};
template<typename Type>
using ToEntityDeprecated = ToEntity<Type>;
using ToEntityTypes = ::testing::Types<int, pointer_stable>;
TYPED_TEST_SUITE(ToEntity, ToEntityTypes, );
TYPED_TEST_SUITE(ToEntityDeprecated, ToEntityTypes, );
TEST(AsView, Functionalities) {
entt::registry registry;
const entt::registry cregistry;
@@ -30,7 +44,7 @@ TEST(Helper, AsView) {
([](entt::view<entt::get_t<const char, const double>, entt::exclude_t<const int>>) {})(entt::as_view{cregistry});
}
TEST(Helper, AsGroup) {
TEST(AsGroup, Functionalities) {
entt::registry registry;
const entt::registry cregistry;
@@ -39,7 +53,7 @@ TEST(Helper, AsGroup) {
([](entt::group<entt::owned_t<const double>, entt::get_t<const char>, entt::exclude_t<const int>>) {})(entt::as_group{cregistry});
}
TEST(Helper, Invoke) {
TEST(Invoke, Functionalities) {
entt::registry registry;
const auto entity = registry.create();
@@ -49,87 +63,93 @@ TEST(Helper, Invoke) {
ASSERT_EQ(entity, registry.get<clazz>(entity).entt);
}
TEST(Helper, ToEntity) {
TYPED_TEST(ToEntity, Functionalities) {
using value_type = typename TestFixture::type;
using traits_type = entt::component_traits<value_type>;
entt::registry registry;
const entt::entity null = entt::null;
constexpr auto page_size = entt::storage_type_t<int>::traits_type::page_size;
const int value = 42;
auto &storage = registry.storage<value_type>();
constexpr auto page_size = entt::storage_type_t<value_type>::traits_type::page_size;
const value_type value{42};
ASSERT_EQ(entt::to_entity(registry, 42), null);
ASSERT_EQ(entt::to_entity(registry, value), null);
ASSERT_EQ(entt::to_entity(storage, value_type{42}), null);
ASSERT_EQ(entt::to_entity(storage, value), null);
const auto entity = registry.create();
auto &&storage = registry.storage<int>();
storage.emplace(entity);
while(storage.size() < (page_size - 1u)) {
while(storage.size() < (page_size - (1u + traits_type::in_place_delete))) {
storage.emplace(registry.create(), value);
}
const auto other = registry.create();
const auto next = registry.create();
registry.emplace<int>(other);
registry.emplace<int>(next);
registry.emplace<value_type>(other);
registry.emplace<value_type>(next);
ASSERT_EQ(entt::to_entity(registry, registry.get<int>(entity)), entity);
ASSERT_EQ(entt::to_entity(registry, registry.get<int>(other)), other);
ASSERT_EQ(entt::to_entity(registry, registry.get<int>(next)), next);
ASSERT_EQ(entt::to_entity(storage, registry.get<value_type>(entity)), entity);
ASSERT_EQ(entt::to_entity(storage, registry.get<value_type>(other)), other);
ASSERT_EQ(entt::to_entity(storage, registry.get<value_type>(next)), next);
ASSERT_EQ(&registry.get<int>(entity) + page_size - 1u, &registry.get<int>(other));
ASSERT_EQ(&registry.get<value_type>(entity) + page_size - (1u + traits_type::in_place_delete), &registry.get<value_type>(other));
registry.destroy(other);
ASSERT_EQ(entt::to_entity(registry, registry.get<int>(entity)), entity);
ASSERT_EQ(entt::to_entity(registry, registry.get<int>(next)), next);
ASSERT_EQ(entt::to_entity(storage, registry.get<value_type>(entity)), entity);
ASSERT_EQ(entt::to_entity(storage, registry.get<value_type>(next)), next);
ASSERT_EQ(&registry.get<int>(entity) + page_size - 1u, &registry.get<int>(next));
ASSERT_EQ(&registry.get<value_type>(entity) + page_size - 1u, &registry.get<value_type>(next));
ASSERT_EQ(entt::to_entity(registry, 42), null);
ASSERT_EQ(entt::to_entity(registry, value), null);
ASSERT_EQ(entt::to_entity(storage, value_type{42}), null);
ASSERT_EQ(entt::to_entity(storage, value), null);
}
TEST(Helper, ToEntityStableType) {
TYPED_TEST(ToEntityDeprecated, Functionalities) {
using value_type = typename TestFixture::type;
using traits_type = entt::component_traits<value_type>;
entt::registry registry;
const entt::entity null = entt::null;
constexpr auto page_size = entt::storage_type_t<stable_type>::traits_type::page_size;
const stable_type value{42};
constexpr auto page_size = entt::storage_type_t<value_type>::traits_type::page_size;
const value_type value{42};
ASSERT_EQ(entt::to_entity(registry, stable_type{42}), null);
ASSERT_EQ(entt::to_entity(registry, value_type{42}), null);
ASSERT_EQ(entt::to_entity(registry, value), null);
const auto entity = registry.create();
auto &&storage = registry.storage<stable_type>();
registry.emplace<stable_type>(entity);
auto &&storage = registry.storage<value_type>();
storage.emplace(entity);
while(storage.size() < (page_size - 2u)) {
while(storage.size() < (page_size - (1u + traits_type::in_place_delete))) {
storage.emplace(registry.create(), value);
}
const auto other = registry.create();
const auto next = registry.create();
registry.emplace<stable_type>(other);
registry.emplace<stable_type>(next);
registry.emplace<value_type>(other);
registry.emplace<value_type>(next);
ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(entity)), entity);
ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(other)), other);
ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(next)), next);
ASSERT_EQ(entt::to_entity(registry, registry.get<value_type>(entity)), entity);
ASSERT_EQ(entt::to_entity(registry, registry.get<value_type>(other)), other);
ASSERT_EQ(entt::to_entity(registry, registry.get<value_type>(next)), next);
ASSERT_EQ(&registry.get<stable_type>(entity) + page_size - 2u, &registry.get<stable_type>(other));
ASSERT_EQ(&registry.get<value_type>(entity) + page_size - (1u + traits_type::in_place_delete), &registry.get<value_type>(other));
registry.destroy(other);
ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(entity)), entity);
ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(next)), next);
ASSERT_EQ(entt::to_entity(registry, registry.get<value_type>(entity)), entity);
ASSERT_EQ(entt::to_entity(registry, registry.get<value_type>(next)), next);
ASSERT_EQ(&registry.get<stable_type>(entity) + page_size - 1u, &registry.get<stable_type>(next));
ASSERT_EQ(&registry.get<value_type>(entity) + page_size - 1u, &registry.get<value_type>(next));
ASSERT_EQ(entt::to_entity(registry, stable_type{42}), null);
ASSERT_EQ(entt::to_entity(registry, value_type{42}), null);
ASSERT_EQ(entt::to_entity(registry, value), null);
}
TEST(Helper, SighHelper) {
TEST(SighHelper, Functionalities) {
using namespace entt::literals;
entt::registry registry{};