mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-04-11 08:07:33 +02:00
btcsignals: use a single shared_ptr for liveness and callback
This simplifies the implementation and eliminates an unnecessary shared_ptr.
Suggested by Marco Falke.
<Co-authored-by: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>
This commit is contained in:
@@ -56,23 +56,28 @@ class connection
|
||||
{
|
||||
template <typename Signature, typename Combiner>
|
||||
friend class signal;
|
||||
|
||||
/*
|
||||
* Tag for the constructor used by signal.
|
||||
/**
|
||||
* Track liveness. Also serves as a tag for the constructor used by signal.
|
||||
*/
|
||||
struct enabled_tag_type {
|
||||
class liveness
|
||||
{
|
||||
friend class connection;
|
||||
std::atomic_bool m_connected{true};
|
||||
|
||||
void disconnect() { m_connected.store(false); }
|
||||
public:
|
||||
bool connected() const { return m_connected.load(); }
|
||||
};
|
||||
static constexpr enabled_tag_type enabled_tag{};
|
||||
|
||||
/**
|
||||
* connections have shared_ptr-like copy and move semantics.
|
||||
*/
|
||||
std::shared_ptr<std::atomic_bool> m_connected{};
|
||||
std::shared_ptr<liveness> m_state{};
|
||||
|
||||
/**
|
||||
* Only a signal can create an enabled connection.
|
||||
*/
|
||||
explicit connection(enabled_tag_type /*unused*/) : m_connected{std::make_shared<std::atomic_bool>(true)} {}
|
||||
explicit connection(std::shared_ptr<liveness>&& state) : m_state{std::move(state)}{}
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -92,8 +97,8 @@ public:
|
||||
*/
|
||||
void disconnect()
|
||||
{
|
||||
if (m_connected) {
|
||||
m_connected->store(false);
|
||||
if (m_state) {
|
||||
m_state->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +108,7 @@ public:
|
||||
*/
|
||||
bool connected() const
|
||||
{
|
||||
return m_connected && m_connected->load();
|
||||
return m_state && m_state->connected();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -148,23 +153,19 @@ class signal
|
||||
static_assert(std::is_same_v<Combiner, optional_last_value<typename function_type::result_type>>, "only the optional_last_value combiner is supported");
|
||||
|
||||
/*
|
||||
* Helper struct for maintaining a callback and its associated connection
|
||||
* Helper struct for maintaining a callback and its associated connection liveness
|
||||
*/
|
||||
struct connection_holder {
|
||||
struct connection_holder : connection::liveness {
|
||||
template <typename Callable>
|
||||
connection_holder(Callable&& callback) : m_callback{std::forward<Callable>(callback)}
|
||||
{
|
||||
}
|
||||
|
||||
connection m_connection{connection::enabled_tag};
|
||||
function_type m_callback;
|
||||
const function_type m_callback;
|
||||
};
|
||||
|
||||
mutable Mutex m_mutex;
|
||||
|
||||
/* Store connection_holders as shared_ptrs to avoid having to copy them by
|
||||
* value in operator().
|
||||
*/
|
||||
std::vector<std::shared_ptr<connection_holder>> m_connections GUARDED_BY(m_mutex){};
|
||||
|
||||
public:
|
||||
@@ -208,14 +209,14 @@ public:
|
||||
}
|
||||
if constexpr (std::is_void_v<result_type>) {
|
||||
for (const auto& connection : connections) {
|
||||
if (connection->m_connection.connected()) {
|
||||
if (connection->connected()) {
|
||||
connection->m_callback(args...);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result_type ret{std::nullopt};
|
||||
for (const auto& connection : connections) {
|
||||
if (connection->m_connection.connected()) {
|
||||
if (connection->connected()) {
|
||||
ret.emplace(connection->m_callback(args...));
|
||||
}
|
||||
}
|
||||
@@ -233,10 +234,10 @@ public:
|
||||
LOCK(m_mutex);
|
||||
|
||||
// Garbage-collect disconnected connections to prevent unbounded growth
|
||||
std::erase_if(m_connections, [](const auto& holder) { return !holder->m_connection.connected(); });
|
||||
std::erase_if(m_connections, [](const auto& holder) { return !holder->connected(); });
|
||||
|
||||
const auto& connection = m_connections.emplace_back(std::make_shared<connection_holder>(std::forward<Callable>(func)));
|
||||
return connection->m_connection;
|
||||
const auto& entry = m_connections.emplace_back(std::make_shared<connection_holder>(std::forward<Callable>(func)));
|
||||
return connection(entry);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -246,7 +247,7 @@ public:
|
||||
{
|
||||
LOCK(m_mutex);
|
||||
return std::ranges::none_of(m_connections, [](const auto& holder) {
|
||||
return holder->m_connection.connected();
|
||||
return holder->connected();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user