mixin: make sigh mixin work with custom registry types - close #1079

This commit is contained in:
Michele Caini
2023-11-22 10:15:17 +01:00
parent 24c95e493f
commit e3475c026c
3 changed files with 141 additions and 97 deletions

View File

@@ -28,46 +28,8 @@ class basic_sparse_set;
template<typename Type, typename = entity, typename = std::allocator<Type>, typename = void>
class basic_storage;
template<typename Type>
class sigh_mixin;
/**
* @brief Provides a common way to define storage types.
* @tparam Type Storage value type.
* @tparam Entity A valid entity type.
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Type, typename Entity = entity, typename Allocator = std::allocator<Type>, typename = void>
struct storage_type {
/*! @brief Type-to-storage conversion result. */
using type = sigh_mixin<basic_storage<Type, Entity, Allocator>>;
};
/**
* @brief Helper type.
* @tparam Args Arguments to forward.
*/
template<typename... Args>
using storage_type_t = typename storage_type<Args...>::type;
/**
* Type-to-storage conversion utility that preserves constness.
* @tparam Type Storage value type, eventually const.
* @tparam Entity A valid entity type.
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Type, typename Entity = entity, typename Allocator = std::allocator<std::remove_const_t<Type>>>
struct storage_for {
/*! @brief Type-to-storage conversion result. */
using type = constness_as_t<storage_type_t<std::remove_const_t<Type>, Entity, Allocator>, Type>;
};
/**
* @brief Helper type.
* @tparam Args Arguments to forward.
*/
template<typename... Args>
using storage_for_t = typename storage_for<Args...>::type;
template<typename, typename>
class basic_sigh_mixin;
template<typename Entity = entity, typename = std::allocator<Entity>>
class basic_registry;
@@ -99,6 +61,67 @@ class basic_snapshot_loader;
template<typename>
class basic_continuous_loader;
/*! @brief Alias declaration for the most common use case. */
using sparse_set = basic_sparse_set<>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Type Type of objects assigned to the entities.
*/
template<typename Type>
using storage = basic_storage<Type>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Type Underlying storage type.
*/
template<typename Type>
using sigh_mixin = basic_sigh_mixin<Type, basic_registry<typename Type::entity_type, typename Type::base_type::allocator_type>>;
/*! @brief Alias declaration for the most common use case. */
using registry = basic_registry<>;
/*! @brief Alias declaration for the most common use case. */
using observer = basic_observer<registry>;
/*! @brief Alias declaration for the most common use case. */
using organizer = basic_organizer<registry>;
/*! @brief Alias declaration for the most common use case. */
using handle = basic_handle<registry>;
/*! @brief Alias declaration for the most common use case. */
using const_handle = basic_handle<const registry>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
*/
template<typename... Args>
using handle_view = basic_handle<registry, Args...>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
*/
template<typename... Args>
using const_handle_view = basic_handle<const registry, Args...>;
/*! @brief Alias declaration for the most common use case. */
using snapshot = basic_snapshot<registry>;
/*! @brief Alias declaration for the most common use case. */
using snapshot_loader = basic_snapshot_loader<registry>;
/*! @brief Alias declaration for the most common use case. */
using continuous_loader = basic_continuous_loader<registry>;
/*! @brief Alias declaration for the most common use case. */
using runtime_view = basic_runtime_view<sparse_set>;
/*! @brief Alias declaration for the most common use case. */
using const_runtime_view = basic_runtime_view<const sparse_set>;
/**
* @brief Alias for exclusion lists.
* @tparam Type List of types.
@@ -183,53 +206,43 @@ struct type_list_transform<owned_t<Type...>, Op> {
using type = owned_t<typename Op<Type>::type...>;
};
/*! @brief Alias declaration for the most common use case. */
using sparse_set = basic_sparse_set<>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Type Type of objects assigned to the entities.
* @brief Provides a common way to define storage types.
* @tparam Type Storage value type.
* @tparam Entity A valid entity type.
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Type>
using storage = basic_storage<Type>;
/*! @brief Alias declaration for the most common use case. */
using registry = basic_registry<>;
/*! @brief Alias declaration for the most common use case. */
using observer = basic_observer<registry>;
/*! @brief Alias declaration for the most common use case. */
using organizer = basic_organizer<registry>;
/*! @brief Alias declaration for the most common use case. */
using handle = basic_handle<registry>;
/*! @brief Alias declaration for the most common use case. */
using const_handle = basic_handle<const registry>;
template<typename Type, typename Entity = entity, typename Allocator = std::allocator<Type>, typename = void>
struct storage_type {
/*! @brief Type-to-storage conversion result. */
using type = sigh_mixin<basic_storage<Type, Entity, Allocator>>;
};
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
* @brief Helper type.
* @tparam Args Arguments to forward.
*/
template<typename... Args>
using handle_view = basic_handle<registry, Args...>;
using storage_type_t = typename storage_type<Args...>::type;
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
* Type-to-storage conversion utility that preserves constness.
* @tparam Type Storage value type, eventually const.
* @tparam Entity A valid entity type.
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Type, typename Entity = entity, typename Allocator = std::allocator<std::remove_const_t<Type>>>
struct storage_for {
/*! @brief Type-to-storage conversion result. */
using type = constness_as_t<storage_type_t<std::remove_const_t<Type>, Entity, Allocator>, Type>;
};
/**
* @brief Helper type.
* @tparam Args Arguments to forward.
*/
template<typename... Args>
using const_handle_view = basic_handle<const registry, Args...>;
/*! @brief Alias declaration for the most common use case. */
using snapshot = basic_snapshot<registry>;
/*! @brief Alias declaration for the most common use case. */
using snapshot_loader = basic_snapshot_loader<registry>;
/*! @brief Alias declaration for the most common use case. */
using continuous_loader = basic_continuous_loader<registry>;
using storage_for_t = typename storage_for<Args...>::type;
/**
* @brief Alias declaration for the most common use case.
@@ -239,12 +252,6 @@ using continuous_loader = basic_continuous_loader<registry>;
template<typename Get, typename Exclude = exclude_t<>>
using view = basic_view<type_list_transform_t<Get, storage_for>, type_list_transform_t<Exclude, storage_for>>;
/*! @brief Alias declaration for the most common use case. */
using runtime_view = basic_runtime_view<sparse_set>;
/*! @brief Alias declaration for the most common use case. */
using const_runtime_view = basic_runtime_view<const sparse_set>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Owned Types of storage _owned_ by the group.

View File

@@ -22,18 +22,23 @@ namespace entt {
*
* This applies to all signals made available.
*
* @tparam Type The type of the underlying storage.
* @tparam Type Underlying storage type.
* @tparam Registry Basic registry type.
*/
template<typename Type>
class sigh_mixin final: public Type {
template<typename Type, typename Registry>
class basic_sigh_mixin final: public Type {
using underlying_type = Type;
using owner_type = Registry;
using basic_registry_type = basic_registry<typename underlying_type::entity_type, typename underlying_type::base_type::allocator_type>;
using sigh_type = sigh<void(basic_registry_type &, const typename underlying_type::entity_type), typename underlying_type::allocator_type>;
using sigh_type = sigh<void(owner_type &, const typename underlying_type::entity_type), typename underlying_type::allocator_type>;
using underlying_iterator = typename underlying_type::base_type::basic_iterator;
basic_registry_type &owner_or_assert() const noexcept {
static_assert(std::is_base_of_v<basic_registry_type, owner_type>, "Invalid registry type");
owner_type &owner_or_assert() const noexcept {
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
return *owner;
return static_cast<owner_type &>(*owner);
}
void pop(underlying_iterator first, underlying_iterator last) final {
@@ -85,17 +90,17 @@ public:
/*! @brief Underlying entity identifier. */
using entity_type = typename underlying_type::entity_type;
/*! @brief Expected registry type. */
using registry_type = basic_registry_type;
using registry_type = owner_type;
/*! @brief Default constructor. */
sigh_mixin()
: sigh_mixin{allocator_type{}} {}
basic_sigh_mixin()
: basic_sigh_mixin{allocator_type{}} {}
/**
* @brief Constructs an empty storage with a given allocator.
* @param allocator The allocator to use.
*/
explicit sigh_mixin(const allocator_type &allocator)
explicit basic_sigh_mixin(const allocator_type &allocator)
: underlying_type{allocator},
owner{},
construction{allocator},
@@ -106,7 +111,7 @@ public:
* @brief Move constructor.
* @param other The instance to move from.
*/
sigh_mixin(sigh_mixin &&other) noexcept
basic_sigh_mixin(basic_sigh_mixin &&other) noexcept
: underlying_type{std::move(other)},
owner{other.owner},
construction{std::move(other.construction)},
@@ -118,7 +123,7 @@ public:
* @param other The instance to move from.
* @param allocator The allocator to use.
*/
sigh_mixin(sigh_mixin &&other, const allocator_type &allocator) noexcept
basic_sigh_mixin(basic_sigh_mixin &&other, const allocator_type &allocator) noexcept
: underlying_type{std::move(other), allocator},
owner{other.owner},
construction{std::move(other.construction), allocator},
@@ -130,7 +135,7 @@ public:
* @param other The instance to move from.
* @return This storage.
*/
sigh_mixin &operator=(sigh_mixin &&other) noexcept {
basic_sigh_mixin &operator=(basic_sigh_mixin &&other) noexcept {
underlying_type::operator=(std::move(other));
owner = other.owner;
construction = std::move(other.construction);
@@ -143,7 +148,7 @@ public:
* @brief Exchanges the contents with those of a given storage.
* @param other Storage to exchange the content with.
*/
void swap(sigh_mixin &other) {
void swap(basic_sigh_mixin &other) {
using std::swap;
underlying_type::swap(other);
swap(owner, other.owner);

View File

@@ -10,6 +10,7 @@
#include <entt/entity/mixin.hpp>
#include <entt/entity/registry.hpp>
#include <entt/entity/storage.hpp>
#include "../common/custom_entity.h"
#include "../common/non_default_constructible.h"
#include "../common/pointer_stable.h"
#include "../common/throwing_allocator.hpp"
@@ -20,6 +21,13 @@ void listener(std::size_t &counter, Registry &, typename Registry::entity_type)
++counter;
}
struct custom_registry: entt::basic_registry<test::custom_entity> {};
template<typename Component>
struct entt::storage_type<Component, test::custom_entity> {
using type = entt::basic_sigh_mixin<entt::basic_storage<Component, test::custom_entity>, custom_registry>;
};
template<typename Type>
struct SighMixin: testing::Test {
using type = Type;
@@ -414,6 +422,30 @@ TYPED_TEST(SighMixin, Swap) {
ASSERT_EQ(on_destroy, 3u);
}
TYPED_TEST(SighMixin, CustomRegistry) {
using value_type = typename TestFixture::type;
entt::basic_sigh_mixin<entt::basic_storage<value_type, test::custom_entity>, custom_registry> pool;
custom_registry registry;
std::size_t on_construct{};
std::size_t on_destroy{};
pool.bind(entt::forward_as_any(static_cast<entt::basic_registry<test::custom_entity> &>(registry)));
pool.on_construct().template connect<&listener<custom_registry>>(on_construct);
pool.on_destroy().template connect<&listener<custom_registry>>(on_destroy);
pool.emplace(test::custom_entity{3});
pool.emplace(test::custom_entity{42});
ASSERT_EQ(on_construct, 2u);
ASSERT_EQ(on_destroy, 0u);
pool.clear();
ASSERT_EQ(on_construct, 2u);
ASSERT_EQ(on_destroy, 2u);
}
TYPED_TEST(SighMixin, CustomAllocator) {
using value_type = typename TestFixture::type;
test::throwing_allocator<entt::entity> allocator{};