template <typename... T_arg>
struct Slot;
- /**
- * @brief Class representing signal connection
- */
- template <typename... T_arg>
- class SignalConnection;
-
/**
* @brief Base class for all signal connections.
*/
class SignalBaseConnection;
- typedef std::unique_ptr<SignalBaseConnection> Connection;
+ typedef std::shared_ptr<SignalBaseConnection> Connection;
/**
- * @brief Call context
+ * @brief Slot definition
*/
template <typename... T_arg>
struct Slot<void(T_arg...)>
{
- Slot(std::function<void(T_arg...)> f) : func(f), delete_me(false) {}
+ /**
+ * @brief Construct slot object
+ *
+ * @param[in] f callback
+ * @param[in] ptr shared pointer to connection data
+ */
+ Slot(std::function<void(T_arg...)> f, std::shared_ptr<SignalBaseConnection> ptr)
+ : func(f), conn(ptr) {}
/** @brief Function to call */
std::function<void(T_arg...)> func;
- /** @brief slot has been marked for deletion */
- bool delete_me;
+ /** @brief connection to slot */
+ std::weak_ptr<SignalBaseConnection> conn;
};
/**
recursive_count_++;
auto it = slots_.begin();
while (it != slots_.end()) {
- if (!it->delete_me) it->func(a...);
+ if (auto ref = it->conn.lock())
+ if (ref->IsConnected()) it->func(a...);
if (on_delete_) return;
++it;
}
*/
Connection Connect(std::function<void(T_arg...)> f)
{
- Slot<void(T_arg...)> slot(f);
+ auto conn = std::make_shared<SignalBaseConnection>();
+ Slot<void(T_arg...)> slot(f, conn);
slots_.push_back(slot);
- auto ptr = new SignalConnection<void(T_arg...)>(&slots_.back());
- return std::unique_ptr<SignalBaseConnection>(ptr);
+ return conn;
}
/**
*/
~Signal()
{
+ auto it = slots_.begin();
+ while (it != slots_.end()) {
+ if (auto ref = it->conn.lock())
+ ref->Disconnect();
+ ++it;
+ }
on_delete_ = true;
slots_.clear();
}
protected:
/**
- * @brief Clear-up deleted slots
+ * @brief Clean-up disconnected slots
*/
void clean_slots()
{
auto it = slots_.begin();
while (it != slots_.end()) {
- if (it->delete_me)
+ auto ref = it->conn.lock();
+ if (!ref || (ref && !ref->IsConnected()))
it = slots_.erase(it);
else
++it;
/** @brief generic storage for slots */
std::list<Slot<void(T_arg...)>> slots_;
+ /** Flag for handling destruction while calling slots functions */
bool on_delete_;
+ /** Count of recursion calls */
int recursive_count_;
};
class SignalBaseConnection
{
public:
- SignalBaseConnection() {}
- /** @brief Disconnects registered function from signal. */
- virtual void Disconnect() {}
- virtual ~SignalBaseConnection() {}
- };
+ SignalBaseConnection() : connected_(true) {}
- /**
- * @brief Specialized template for signal connections with functions of type
- * void (*)(T_arg...)
- */
- template <typename... T_arg>
- class SignalConnection<void(T_arg...)> : public SignalBaseConnection
- {
- public:
- /**
- * @brief Constructor
- *
- * @param[in] it iterator to list element
- */
- SignalConnection(Slot<void(T_arg...)> *slot) : slot_(slot) {}
-
- ~SignalConnection() { Disconnect(); }
-
- void Disconnect() override
- {
- if (slot_) {
- slot_->delete_me = true;
- slot_ = nullptr;
+ /** @brief Disconnects registered function from signal. */
+ void Disconnect()
+ {
+ connected_ = false;
}
- }
- bool IsConnected() const
- {
- return slot_ != nullptr;
- }
-
- /**
- * @brief R-Value constructor
- */
- SignalConnection(SignalConnection&& ref)
- {
- slot_ = ref.slot_;
- ref.slot_ = nullptr;
- }
-
- /**
- * @brief Delete copy constructor
- */
- SignalConnection(const SignalConnection& ln) = delete;
-
- /**
- * @brief Delete assign operator
- */
- SignalConnection<T_arg...> operator=(const SignalConnection& ln) = delete;
+ /** @brief Returns connection status */
+ bool IsConnected()
+ {
+ return connected_;
+ }
+ ~SignalBaseConnection()
+ {
+ Disconnect();
+ }
private:
- Slot<void(T_arg...)> *slot_;
+ bool connected_;
};
-
}; /* utils */
#endif