diff --git a/src/entt/signal/sigh.hpp b/src/entt/signal/sigh.hpp index 6688aa64f..fd1951af5 100644 --- a/src/entt/signal/sigh.hpp +++ b/src/entt/signal/sigh.hpp @@ -160,19 +160,55 @@ class connection { {} public: + /*! Default constructor. */ + connection() = default; + /*! @brief Default copy constructor. */ connection(const connection &) = default; - /*! @brief Default move constructor. */ - connection(connection &&) = default; + + /** + * @brief Default move constructor. + * @param other The instance to move from. + */ + connection(connection &&other) + : connection{} + { + std::swap(disconnect, other.disconnect); + std::swap(signal, other.signal); + } /*! @brief Default copy assignment operator. @return This connection. */ connection & operator=(const connection &) = default; - /*! @brief Default move assignment operator. @return This connection. */ - connection & operator=(connection &&) = default; + + /** + * @brief Default move assignment operator. + * @param other The instance to move from. + * @return This connection. + */ + connection & operator=(connection &&other) { + if(this != &other) { + auto tmp{std::move(other)}; + disconnect = tmp.disconnect; + signal = tmp.signal; + } + + return *this; + } + + /** + * @brief Checks whether a connection is properly initialized. + * @return True if the connection is properly initialized, false otherwise. + */ + explicit operator bool() const ENTT_NOEXCEPT { + return static_cast(disconnect); + } /*! @brief Breaks the connection. */ void release() { - disconnect(signal); + if(disconnect) { + disconnect(signal); + disconnect.reset(); + } } private: @@ -191,6 +227,9 @@ private: * when it goes out of scope. */ struct scoped_connection: private connection { + /*! Default constructor. */ + scoped_connection() = default; + /** * @brief Constructs a scoped connection from a basic connection. * @param conn A valid connection object. @@ -199,10 +238,51 @@ struct scoped_connection: private connection { : connection{conn} {} + /*! @brief Default copy constructor, deleted on purpose. */ + scoped_connection(const scoped_connection &) = delete; + + /*! @brief Default move constructor. */ + scoped_connection(scoped_connection &&) = default; + /*! @brief Automatically breaks the link on destruction. */ ~scoped_connection() { connection::release(); } + + /** + * @brief Default copy assignment operator, deleted on purpose. + * @return This scoped connection. + */ + scoped_connection & operator=(const scoped_connection &) = delete; + + /** + * @brief Default move assignment operator. + * @return This scoped connection. + */ + scoped_connection & operator=(scoped_connection &&) = default; + + /** + * @brief Copies a connection. + * @param other The connection object to copy. + * @return This scoped connection. + */ + scoped_connection & operator=(const connection &other) { + static_cast(*this) = other; + return *this; + } + + /** + * @brief Moves a connection. + * @param other The connection object to move. + * @return This scoped connection. + */ + scoped_connection & operator=(connection &&other) { + static_cast(*this) = std::move(other); + return *this; + } + + using connection::operator bool; + using connection::release; }; diff --git a/test/entt/signal/sigh.cpp b/test/entt/signal/sigh.cpp index 44762c219..93443024b 100644 --- a/test/entt/signal/sigh.cpp +++ b/test/entt/signal/sigh.cpp @@ -199,6 +199,7 @@ TEST(SigH, Connection) { sigh.publish(v); ASSERT_FALSE(sigh.empty()); + ASSERT_TRUE(conn); ASSERT_EQ(42, v); v = 0; @@ -206,6 +207,7 @@ TEST(SigH, Connection) { sigh.publish(v); ASSERT_TRUE(sigh.empty()); + ASSERT_FALSE(conn); ASSERT_EQ(0, v); } @@ -222,6 +224,7 @@ TEST(SigH, ScopedConnection) { ASSERT_FALSE(sigh.empty()); ASSERT_TRUE(listener.k); + ASSERT_TRUE(conn); } sigh.publish(42); @@ -230,6 +233,39 @@ TEST(SigH, ScopedConnection) { ASSERT_TRUE(listener.k); } +TEST(SigH, ScopedConnectionConstructorsAndOperators) { + sigh_listener listener; + entt::sigh sigh; + entt::sink sink{sigh}; + entt::scoped_connection conn; + + { + ASSERT_FALSE(listener.k); + ASSERT_FALSE(conn); + + auto basic = sink.connect<&sigh_listener::g>(&listener); + entt::scoped_connection inner = std::move(basic); + sigh.publish(42); + + ASSERT_FALSE(sigh.empty()); + ASSERT_TRUE(listener.k); + ASSERT_TRUE(inner); + + conn = std::move(inner); + + ASSERT_FALSE(inner); + ASSERT_TRUE(conn); + } + + ASSERT_TRUE(conn); + + conn.release(); + sigh.publish(42); + + ASSERT_TRUE(sigh.empty()); + ASSERT_TRUE(listener.k); +} + TEST(SigH, ConstNonConstNoExcept) { entt::sigh sigh; entt::sink sink{sigh};