Skip to content

Commit

Permalink
directly uses ConnectionHandle& to enable more direct and efficient m…
Browse files Browse the repository at this point in the history
…anagement of connections within slots
  • Loading branch information
phyBrackets authored and LeonMatthesKDAB committed Jul 3, 2024
1 parent 45bb355 commit 487a842
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 21 deletions.
32 changes: 16 additions & 16 deletions src/kdbindings/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,34 +272,34 @@ class Signal
}

/**
* Establishes a connection between a signal and a slot, allowing the slot to access its own connection handle.
* This method is particularly useful for creating connections that can manage themselves, such as disconnecting
* Establishes a connection between a signal and a slot, allowing the slot to access and manage its own connection handle.
* This method is particularly useful for creating connections that can autonomously manage themselves, such as disconnecting
* after being triggered a certain number of times or under specific conditions. It wraps the given slot function
* to include a shared pointer to the ConnectionHandle as the first parameter, enabling the slot to interact with
* to include a reference to the ConnectionHandle as the first parameter, enabling the slot to interact with
* its own connection state directly.
*
* @param slot A std::function that takes a shared_ptr<ConnectionHandle> followed by the signal's parameter types.
* @return A shared_ptr to the ConnectionHandle associated with this connection, allowing for advanced connection management.
* @param slot A std::function that takes a ConnectionHandle reference followed by the signal's parameter types.
* @return A ConnectionHandle to the newly established connection, allowing for advanced connection management.
*/
std::shared_ptr<ConnectionHandle> connectReflective(std::function<void(std::shared_ptr<ConnectionHandle>, Args...)> const &slot)
ConnectionHandle connectReflective(std::function<void(ConnectionHandle &, Args...)> const &slot)
{
ensureImpl();

// Create a placeholder handle (with no ID yet)
// Create a new ConnectionHandle with no ID initially. This handle will be used to manage the connection lifecycle.
auto handle = ConnectionHandle::create(m_impl, std::nullopt);

auto wrappedSlot = [this, slot, weakHandle = std::weak_ptr<ConnectionHandle>(handle)](Args... args) {
if (auto handle = weakHandle.lock()) { // Ensure the handle is still valid
slot(handle, args...);
}
// Prepare the lambda that matches the signature expected by m_impl->connect
auto wrappedSlot = [this, handle, slot](Args... args) mutable {
// Directly invoke the user-provided slot with the handle and args
slot(*handle, args...);
};

// Connect the wrapped slot
auto id = m_impl->connect(wrappedSlot);
// Connect the wrapped slot to the signal implementation.
// The handle ID is set after successful connection to manage this connection specifically.
handle->setId(m_impl->connect(wrappedSlot));

// Assign the ID to the handle now that it's known
handle->setId(id);
return handle;
// Return the ConnectionHandle, allowing the caller to manage the connection directly.
return *handle;
}

/**
Expand Down
12 changes: 7 additions & 5 deletions tests/signal/tst_signal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,19 +267,21 @@ TEST_CASE("Signal connections")
int val = 5;

// Connect a reflective slot to the signal
auto handle = mySignal.connectReflective([&val](std::shared_ptr<ConnectionHandle> selfHandle, int value) {
auto handle = mySignal.connectReflective([&val](ConnectionHandle &selfHandle, int value) {
val += value;

// Disconnect after handling the signal once
selfHandle->disconnect();
selfHandle.disconnect();
});

mySignal.emit(5); // This should trigger the slot and then disconnect it
REQUIRE(!handle->isActive());

mySignal.emit(5); // Signal Already disconnected
REQUIRE(!handle.isActive());

REQUIRE(val == 10);
mySignal.emit(5); // Since the slot is disconnected, this should not affect 'val'

// Check if the value remains unchanged after the second emit
REQUIRE(val == 10); // 'val' was incremented once to 10 by the first emit and should remain at 10
}

SUBCASE("A signal with arguments can be connected to a lambda and invoked with l-value args")
Expand Down

0 comments on commit 487a842

Please sign in to comment.