Skip to content

Commit

Permalink
sigh: support uninitialized sink objects
Browse files Browse the repository at this point in the history
  • Loading branch information
skypjack committed Jan 16, 2025
1 parent 073bd70 commit 3c5e77e
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 7 deletions.
33 changes: 26 additions & 7 deletions src/entt/signal/sigh.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,15 +374,26 @@ class sink<sigh<Ret(Args...), Allocator>> {

template<typename Func>
void disconnect_if(Func callback) {
for(auto pos = signal->calls.size(); pos; --pos) {
if(auto &elem = signal->calls[pos - 1u]; callback(elem)) {
elem = std::move(signal->calls.back());
signal->calls.pop_back();
auto &ref = signal_or_assert();

for(auto pos = ref.calls.size(); pos; --pos) {
if(auto &elem = ref.calls[pos - 1u]; callback(elem)) {
elem = std::move(ref.calls.back());
ref.calls.pop_back();
}
}
}

[[nodiscard]] auto &signal_or_assert() const noexcept {
ENTT_ASSERT(signal != nullptr, "Invalid pointer to signal");
return *signal;
}

public:
/*! @brief Constructs an invalid sink. */
sink() noexcept
: signal{} {}

/**
* @brief Constructs a sink that is allowed to modify a given signal.
* @param ref A valid reference to a signal object.
Expand All @@ -395,7 +406,7 @@ class sink<sigh<Ret(Args...), Allocator>> {
* @return True if the sink has no listeners connected, false otherwise.
*/
[[nodiscard]] bool empty() const noexcept {
return signal->calls.empty();
return signal_or_assert().calls.empty();
}

/**
Expand All @@ -412,7 +423,7 @@ class sink<sigh<Ret(Args...), Allocator>> {

delegate_type call{};
call.template connect<Candidate>(value_or_instance...);
signal->calls.push_back(std::move(call));
signal_or_assert().calls.push_back(std::move(call));

delegate<void(void *)> conn{};
conn.template connect<&release<Candidate, Type...>>(value_or_instance...);
Expand Down Expand Up @@ -445,7 +456,15 @@ class sink<sigh<Ret(Args...), Allocator>> {

/*! @brief Disconnects all the listeners from a signal. */
void disconnect() {
signal->calls.clear();
signal_or_assert().calls.clear();
}

/**
* @brief Returns true if a sink is correctly initialized, false otherwise.
* @return True if a sink is correctly initialized, false otherwise.
*/
[[nodiscard]] explicit operator bool() const noexcept {
return signal != nullptr;
}

private:
Expand Down
20 changes: 20 additions & 0 deletions test/entt/signal/sigh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <utility>
#include <gtest/gtest.h>
#include <entt/signal/sigh.hpp>
#include "../../common/config.h"
#include "../../common/linter.hpp"

struct sigh_listener {
Expand Down Expand Up @@ -52,6 +53,25 @@ void connect_and_auto_disconnect(entt::sigh<void(int &)> &sigh, const int &) {
sink.disconnect<&connect_and_auto_disconnect>(sigh);
}

ENTT_DEBUG_TEST(SinkDeathTest, Invalid) {
sigh_listener listener;
entt::sigh<void(int &)> sigh;
entt::sink<entt::sigh<void(int &)>> sink{};

ASSERT_FALSE(sink);

ASSERT_DEATH([[maybe_unused]] bool empty = sink.empty(), "");
ASSERT_DEATH(sink.connect<&sigh_listener::f>(), "");
ASSERT_DEATH(sink.disconnect<&sigh_listener::f>(), "");
ASSERT_DEATH(sink.disconnect(&listener), "");
ASSERT_DEATH(sink.disconnect(), "");

sink = entt::sink{sigh};

ASSERT_TRUE(sink);
ASSERT_TRUE(sink.empty());
}

TEST(SigH, Lifetime) {
using signal = entt::sigh<void(void)>;

Expand Down

0 comments on commit 3c5e77e

Please sign in to comment.