Skip to content

Commit

Permalink
reactive mixin: auto disconnection support
Browse files Browse the repository at this point in the history
  • Loading branch information
skypjack committed Nov 15, 2024
1 parent a3d6e70 commit 575f06b
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 17 deletions.
1 change: 1 addition & 0 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ TODO:
* dtor, traits and custom should be part of meta descriptor maybe (?)
* allow attaching const values of non-Type type to meta types
* built-in no-pagination storage - no_pagination page size as limits::max
* avoid specializations of sigh_type in basic_sigh_mixin due to alloc type
43 changes: 26 additions & 17 deletions src/entt/entity/mixin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,9 @@ class basic_reactive_mixin final: public Type {
using underlying_type = Type;
using owner_type = Registry;

using alloc_traits = std::allocator_traits<typename underlying_type::allocator_type>;
using basic_registry_type = basic_registry<typename owner_type::entity_type, typename owner_type::allocator_type>;
using container_type = std::vector<connection, typename alloc_traits::template rebind_alloc<connection>>;

static_assert(std::is_base_of_v<basic_registry_type, owner_type>, "Invalid registry type");

Expand Down Expand Up @@ -429,7 +431,8 @@ class basic_reactive_mixin final: public Type {
*/
explicit basic_reactive_mixin(const allocator_type &allocator)
: underlying_type{allocator},
owner{} {
owner{},
conn{allocator} {
}

/*! @brief Default copy constructor, deleted on purpose. */
Expand All @@ -441,7 +444,9 @@ class basic_reactive_mixin final: public Type {
*/
basic_reactive_mixin(basic_reactive_mixin &&other) noexcept
: underlying_type{std::move(other)},
owner{other.owner} {}
owner{other.owner},
conn{} {
}

/**
* @brief Allocator-extended move constructor.
Expand All @@ -450,7 +455,9 @@ class basic_reactive_mixin final: public Type {
*/
basic_reactive_mixin(basic_reactive_mixin &&other, const allocator_type &allocator)
: underlying_type{std::move(other), allocator},
owner{other.owner} {}
owner{other.owner},
conn{allocator} {
}

/*! @brief Default destructor. */
~basic_reactive_mixin() override = default;
Expand All @@ -467,18 +474,8 @@ class basic_reactive_mixin final: public Type {
* @return This mixin.
*/
basic_reactive_mixin &operator=(basic_reactive_mixin &&other) noexcept {
swap(other);
return *this;
}

/**
* @brief Exchanges the contents with those of a given storage.
* @param other Storage to exchange the content with.
*/
void swap(basic_reactive_mixin &other) noexcept {
using std::swap;
swap(owner, other.owner);
underlying_type::swap(other);
return *this;
}

/**
Expand All @@ -490,7 +487,8 @@ class basic_reactive_mixin final: public Type {
*/
template<typename Clazz, auto Candidate = &basic_reactive_mixin::emplace_element>
basic_reactive_mixin &on_construct(const id_type id = type_hash<Clazz>::value()) {
owner_or_assert().template storage<Clazz>(id).on_construct().template connect<Candidate>(*this);
auto curr = owner_or_assert().template storage<Clazz>(id).on_construct().template connect<Candidate>(*this);
conn.push_back(std::move(curr));
return *this;
}

Expand All @@ -503,7 +501,8 @@ class basic_reactive_mixin final: public Type {
*/
template<typename Clazz, auto Candidate = &basic_reactive_mixin::emplace_element>
basic_reactive_mixin &on_update(const id_type id = type_hash<Clazz>::value()) {
owner_or_assert().template storage<Clazz>(id).on_update().template connect<Candidate>(*this);
auto curr = owner_or_assert().template storage<Clazz>(id).on_update().template connect<Candidate>(*this);
conn.push_back(std::move(curr));
return *this;
}

Expand All @@ -516,7 +515,8 @@ class basic_reactive_mixin final: public Type {
*/
template<typename Clazz, auto Candidate = &basic_reactive_mixin::emplace_element>
basic_reactive_mixin &on_destroy(const id_type id = type_hash<Clazz>::value()) {
owner_or_assert().template storage<Clazz>(id).on_destroy().template connect<Candidate>(*this);
auto curr = owner_or_assert().template storage<Clazz>(id).on_destroy().template connect<Candidate>(*this);
conn.push_back(std::move(curr));
return *this;
}

Expand Down Expand Up @@ -564,8 +564,17 @@ class basic_reactive_mixin final: public Type {
return {*this, parent.template storage<std::remove_const_t<Get>>()..., parent.template storage<std::remove_const_t<Exclude>>()...};
}

void reset() {
for(auto &&curr: conn) {
curr.release();
}

conn.clear();
}

private:
basic_registry_type *owner;
container_type conn;
};

} // namespace entt
Expand Down
34 changes: 34 additions & 0 deletions test/entt/entity/reactive_mixin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,40 @@ ENTT_DEBUG_TYPED_TEST(ReactiveMixinDeathTest, View) {
ASSERT_DEATH([[maybe_unused]] const auto cview = std::as_const(pool).view(), "");
}

TYPED_TEST(ReactiveMixin, AutoDisconnection) {
using value_type = typename TestFixture::type;

entt::registry registry;
entt::reactive_mixin<entt::storage<value_type>> pool;
const std::array entity{registry.create(), registry.create(), registry.create()};

ASSERT_TRUE(pool.empty());

ASSERT_TRUE(registry.on_construct<test::empty>().empty());
ASSERT_TRUE(registry.on_update<test::empty>().empty());
ASSERT_TRUE(registry.on_destroy<test::empty>().empty());

pool.bind(registry);
pool.template on_construct<test::empty>();
pool.template on_update<test::empty>();
pool.template on_destroy<test::empty>();
registry.emplace<test::empty>(entity[0u]);

ASSERT_FALSE(pool.empty());

ASSERT_FALSE(registry.on_construct<test::empty>().empty());
ASSERT_FALSE(registry.on_update<test::empty>().empty());
ASSERT_FALSE(registry.on_destroy<test::empty>().empty());

pool.reset();

ASSERT_FALSE(pool.empty());

ASSERT_TRUE(registry.on_construct<test::empty>().empty());
ASSERT_TRUE(registry.on_update<test::empty>().empty());
ASSERT_TRUE(registry.on_destroy<test::empty>().empty());
}

TYPED_TEST(ReactiveMixin, CustomAllocator) {
using value_type = typename TestFixture::type;
using storage_type = entt::reactive_mixin<entt::basic_storage<value_type, entt::entity, test::throwing_allocator<value_type>>>;
Expand Down

0 comments on commit 575f06b

Please sign in to comment.