|
|
@@ -16,7 +16,7 @@ namespace entt {
|
|
|
|
|
|
|
|
|
/**
|
|
|
- * @brief Sink implementation.
|
|
|
+ * @brief Sink class.
|
|
|
*
|
|
|
* Primary template isn't defined on purpose. All the specializations give a
|
|
|
* compile-time error unless the template parameter is a function type.
|
|
|
@@ -28,7 +28,7 @@ struct sink;
|
|
|
|
|
|
|
|
|
/**
|
|
|
- * @brief Unmanaged signal handler declaration.
|
|
|
+ * @brief Unmanaged signal handler.
|
|
|
*
|
|
|
* Primary template isn't defined on purpose. All the specializations give a
|
|
|
* compile-time error unless the template parameter is a function type.
|
|
|
@@ -40,11 +40,11 @@ class sigh;
|
|
|
|
|
|
|
|
|
/**
|
|
|
- * @brief Unmanaged signal handler definition.
|
|
|
+ * @brief Unmanaged signal handler.
|
|
|
*
|
|
|
- * Unmanaged signal handler. It works directly with naked pointers to classes
|
|
|
- * and pointers to member functions as well as pointers to free functions. Users
|
|
|
- * of this class are in charge of disconnecting instances before deleting them.
|
|
|
+ * It works directly with naked pointers to classes and pointers to member
|
|
|
+ * functions as well as pointers to free functions. Users of this class are in
|
|
|
+ * charge of disconnecting instances before deleting them.
|
|
|
*
|
|
|
* This class serves mainly two purposes:
|
|
|
*
|
|
|
@@ -154,21 +154,74 @@ private:
|
|
|
|
|
|
|
|
|
/**
|
|
|
- * @brief Sink implementation.
|
|
|
+ * @brief Connection class.
|
|
|
*
|
|
|
- * A sink is an opaque object used to connect listeners to signals.<br/>
|
|
|
+ * Opaque object the aim of which is to allow users to release an already
|
|
|
+ * estabilished connection without having to keep a reference to the signal or
|
|
|
+ * the sink that generated it.
|
|
|
+ */
|
|
|
+class connection {
|
|
|
+ /*! @brief A sink is allowed to create connection objects. */
|
|
|
+ template<typename>
|
|
|
+ friend struct sink;
|
|
|
+
|
|
|
+public:
|
|
|
+ /*! @brief Breaks the connection. */
|
|
|
+ void release() {
|
|
|
+ disconnect(parent, value_or_instance);
|
|
|
+ }
|
|
|
+
|
|
|
+private:
|
|
|
+ void(* disconnect)(void *, const void *){};
|
|
|
+ const void *value_or_instance{};
|
|
|
+ void *parent{};
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * @brief Scoped connection class.
|
|
|
+ *
|
|
|
+ * Opaque object the aim of which is to allow users to release an already
|
|
|
+ * estabilished connection without having to keep a reference to the signal or
|
|
|
+ * the sink that generated it.<br/>
|
|
|
+ * A scoped connection automatically breaks the link between the two objects
|
|
|
+ * when it goes out of scope.
|
|
|
+ */
|
|
|
+struct scoped_connection: private connection {
|
|
|
+ /**
|
|
|
+ * @brief Constructs a scoped connection from a basic connection.
|
|
|
+ * @param conn A valid connection object.
|
|
|
+ */
|
|
|
+ scoped_connection(const connection &conn)
|
|
|
+ : connection{conn}
|
|
|
+ {}
|
|
|
+
|
|
|
+ /*! @brief Automatically breaks the link on destruction. */
|
|
|
+ ~scoped_connection() {
|
|
|
+ connection::release();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * @brief Sink class.
|
|
|
+ *
|
|
|
+ * A sink is used to connect listeners to signals and to disconnect them.<br/>
|
|
|
* The function type for a listener is the one of the signal to which it
|
|
|
* belongs.
|
|
|
*
|
|
|
* The clear separation between a signal and a sink permits to store the former
|
|
|
* as private data member without exposing the publish functionality to the
|
|
|
- * users of a class.
|
|
|
+ * users of the class.
|
|
|
*
|
|
|
* @tparam Ret Return type of a function type.
|
|
|
* @tparam Args Types of arguments of a function type.
|
|
|
*/
|
|
|
template<typename Ret, typename... Args>
|
|
|
struct sink<Ret(Args...)> {
|
|
|
+ /*! @brief Signal type. */
|
|
|
+ using signal_type = sigh<Ret(Args...)>;
|
|
|
+
|
|
|
/**
|
|
|
* @brief Constructs a sink that is allowed to modify a given signal.
|
|
|
* @param ref A valid reference to a signal object.
|
|
|
@@ -192,13 +245,24 @@ struct sink<Ret(Args...)> {
|
|
|
* functions.
|
|
|
*
|
|
|
* @tparam Function A valid free function pointer.
|
|
|
+ * @return A properly initialized connection object.
|
|
|
*/
|
|
|
template<auto Function>
|
|
|
- void connect() {
|
|
|
+ connection connect() {
|
|
|
disconnect<Function>();
|
|
|
+
|
|
|
delegate<Ret(Args...)> delegate{};
|
|
|
delegate.template connect<Function>();
|
|
|
parent->calls.emplace_back(std::move(delegate));
|
|
|
+
|
|
|
+ connection conn;
|
|
|
+ conn.parent = parent;
|
|
|
+ conn.value_or_instance = nullptr;
|
|
|
+ conn.disconnect = [](void *parent, const void *) {
|
|
|
+ sink{*static_cast<signal_type *>(parent)}.disconnect<Function>();
|
|
|
+ };
|
|
|
+
|
|
|
+ return conn;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -216,13 +280,32 @@ struct sink<Ret(Args...)> {
|
|
|
* @tparam Candidate Member or free function to connect to the signal.
|
|
|
* @tparam Type Type of class or type of payload.
|
|
|
* @param value_or_instance A valid pointer that fits the purpose.
|
|
|
+ * @return A properly initialized connection object.
|
|
|
*/
|
|
|
template<auto Candidate, typename Type>
|
|
|
- void connect(Type *value_or_instance) {
|
|
|
+ connection connect(Type *value_or_instance) {
|
|
|
disconnect<Candidate>(value_or_instance);
|
|
|
+
|
|
|
delegate<Ret(Args...)> delegate{};
|
|
|
delegate.template connect<Candidate>(value_or_instance);
|
|
|
parent->calls.emplace_back(std::move(delegate));
|
|
|
+
|
|
|
+ connection conn;
|
|
|
+ conn.parent = parent;
|
|
|
+ conn.value_or_instance = value_or_instance;
|
|
|
+ conn.disconnect = [](void *parent, const void *value_or_instance) {
|
|
|
+ Type *curr = nullptr;
|
|
|
+
|
|
|
+ if constexpr(std::is_const_v<Type>) {
|
|
|
+ curr = static_cast<Type *>(value_or_instance);
|
|
|
+ } else {
|
|
|
+ curr = static_cast<Type *>(const_cast<void *>(value_or_instance));
|
|
|
+ }
|
|
|
+
|
|
|
+ sink{*static_cast<signal_type *>(parent)}.disconnect<Candidate>(curr);
|
|
|
+ };
|
|
|
+
|
|
|
+ return conn;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -272,7 +355,7 @@ struct sink<Ret(Args...)> {
|
|
|
}
|
|
|
|
|
|
private:
|
|
|
- sigh<Ret(Args...)> *parent;
|
|
|
+ signal_type *parent;
|
|
|
};
|
|
|
|
|
|
|