diff --git a/src/entt/entity/registry.hpp b/src/entt/entity/registry.hpp index 2b3da961b..4411a86fb 100644 --- a/src/entt/entity/registry.hpp +++ b/src/entt/entity/registry.hpp @@ -72,9 +72,15 @@ class Registry { }; template - const SparseSet & pool() const ENTT_NOEXCEPT { + bool managed() const ENTT_NOEXCEPT { + const auto ctype = component_family::type(); + return ctype < pools.size() && std::get<0>(pools[ctype]); + } + + template + const SparseSet & pool() const ENTT_NOEXCEPT { + assert(managed()); const auto ctype = component_family::type(); - assert(ctype < pools.size() && std::get<0>(pools[ctype])); return static_cast &>(*std::get<0>(pools[ctype])); } @@ -175,8 +181,7 @@ public: */ template size_type size() const ENTT_NOEXCEPT { - const auto ctype = component_family::type(); - return ((ctype < pools.size()) && std::get<0>(pools[ctype])) ? std::get<0>(pools[ctype])->size() : size_type{}; + return managed() ? pool().size() : size_type{}; } /** @@ -230,8 +235,7 @@ public: */ template bool empty() const ENTT_NOEXCEPT { - const auto ctype = component_family::type(); - return (!(ctype < pools.size()) || !std::get<0>(pools[ctype]) || std::get<0>(pools[ctype])->empty()); + return !managed() || pool().empty(); } /** @@ -242,6 +246,63 @@ public: return entities.size() == available; } + /** + * @brief Direct access to the list of components of a given pool. + * + * The returned pointer is such that range + * `[raw(), raw() + size()]` is always a + * valid range, even if the container is empty. + * + * @note + * There are no guarantees on the order of the components. Use a view if you + * want to iterate entities and components in the expected order. + * + * @tparam Component Type of component in which one is interested. + * @return A pointer to the array of components of the given type. + */ + template + const Component * raw() const ENTT_NOEXCEPT { + return managed() ? pool().raw() : nullptr; + } + + /** + * @brief Direct access to the list of components of a given pool. + * + * The returned pointer is such that range + * `[raw(), raw() + size()]` is always a + * valid range, even if the container is empty. + * + * @note + * There are no guarantees on the order of the components. Use a view if you + * want to iterate entities and components in the expected order. + * + * @tparam Component Type of component in which one is interested. + * @return A pointer to the array of components of the given type. + */ + template + Component * raw() ENTT_NOEXCEPT { + return const_cast(const_cast(this)->raw()); + } + + /** + * @brief Direct access to the list of entities of a given pool. + * + * The returned pointer is such that range + * `[data(), data() + size()]` is always a + * valid range, even if the container is empty. + * + * @note + * There are no guarantees on the order of the entities. Use a view if you + * want to iterate entities and components in the expected order. + * + * @tparam Component Type of component in which one is interested. + * @return A pointer to the array of entities. + */ + template + const entity_type * data() const ENTT_NOEXCEPT { + return managed() ? pool().data() : nullptr; + } + /** * @brief Checks if an entity identifier refers to a valid entity. * @param entity An entity identifier, either valid or not. @@ -480,8 +541,8 @@ public: template void remove(entity_type entity) { assert(valid(entity)); + assert(managed()); const auto ctype = component_family::type(); - assert(ctype < pools.size() && std::get<0>(pools[ctype])); std::get<2>(pools[ctype]).publish(*this, entity); pool().destroy(entity); } @@ -522,9 +583,8 @@ public: assert(valid(entity)); using accumulator_type = bool[]; bool all = true; - auto test = [entity, this](auto ctype) { return (ctype < pools.size()) && std::get<0>(pools[ctype]) && std::get<0>(pools[ctype])->has(entity); }; - accumulator_type accumulator = { all, (all = all && test(component_family::type()))... }; - (void)test, (void)accumulator; + accumulator_type accumulator = { all, (all = all && managed() && pool().has(entity))... }; + (void)accumulator; return all; } @@ -580,9 +640,8 @@ public: template const Component & get(entity_type entity) const ENTT_NOEXCEPT { assert(valid(entity)); - const auto ctype = component_family::type(); - assert((ctype < pools.size()) && std::get<0>(pools[ctype])); - return static_cast &>(*std::get<0>(pools[ctype])).get(entity); + assert(managed()); + return pool().get(entity); } /** @@ -1315,7 +1374,6 @@ public: */ Snapshot snapshot() const { using follow_fn_type = entity_type(*)(const Registry &, entity_type); - using raw_fn_type = const entity_type *(*)(const Registry &, component_type); const entity_type seed = available ? (next | (entities[next] & ~traits_type::entity_mask)) : next; follow_fn_type follow = [](const Registry ®istry, entity_type entity) -> entity_type { @@ -1325,12 +1383,7 @@ public: return (next | (entities[next] & ~traits_type::entity_mask)); }; - raw_fn_type raw = [](const Registry ®istry, component_type component) -> const entity_type * { - const auto &pools = registry.pools; - return (component < pools.size() && std::get<0>(pools[component])) ? std::get<0>(pools[component])->data() : nullptr; - }; - - return { *this, seed, available, follow, raw }; + return { *this, seed, available, follow }; } /** diff --git a/src/entt/entity/snapshot.hpp b/src/entt/entity/snapshot.hpp index df95cd01b..641a66b15 100644 --- a/src/entt/entity/snapshot.hpp +++ b/src/entt/entity/snapshot.hpp @@ -40,21 +40,18 @@ class Snapshot final { friend class Registry; using follow_fn_type = Entity(*)(const Registry &, Entity); - using raw_fn_type = const Entity *(*)(const Registry &, typename Registry::component_type); - Snapshot(const Registry ®istry, Entity seed, std::size_t size, follow_fn_type follow, raw_fn_type raw) ENTT_NOEXCEPT + Snapshot(const Registry ®istry, Entity seed, std::size_t size, follow_fn_type follow) ENTT_NOEXCEPT : registry{registry}, seed{seed}, size{size}, - follow{follow}, - raw{raw} + follow{follow} {} template void get(Archive &archive, const Registry ®istry) { - const auto component = registry.template type(); const auto sz = registry.template size(); - const auto *entities = raw(registry, component); + const auto *entities = registry.template data(); archive(static_cast(sz)); @@ -176,7 +173,6 @@ private: const Entity seed; const std::size_t size; follow_fn_type follow; - raw_fn_type raw; }; diff --git a/test/entt/entity/registry.cpp b/test/entt/entity/registry.cpp index 8bcb64fa2..eb4674158 100644 --- a/test/entt/entity/registry.cpp +++ b/test/entt/entity/registry.cpp @@ -195,6 +195,26 @@ TEST(DefaultRegistry, Functionalities) { ASSERT_TRUE(registry.empty()); } +TEST(DefaultRegistry, RawData) { + entt::DefaultRegistry registry; + const entt::DefaultRegistry &cregistry = registry; + const auto entity = registry.create(); + + ASSERT_EQ(registry.raw(), nullptr); + ASSERT_EQ(cregistry.raw(), nullptr); + ASSERT_EQ(cregistry.data(), nullptr); + + registry.assign(entity, 42); + + ASSERT_NE(registry.raw(), nullptr); + ASSERT_NE(cregistry.raw(), nullptr); + ASSERT_NE(cregistry.data(), nullptr); + + ASSERT_EQ(*registry.raw(), 42); + ASSERT_EQ(*cregistry.raw(), 42); + ASSERT_EQ(*cregistry.data(), entity); +} + TEST(DefaultRegistry, CreateDestroyCornerCase) { entt::DefaultRegistry registry;