diff --git a/src/entt/signal/sigh.hpp b/src/entt/signal/sigh.hpp index e012e6dce..6e3801c0d 100644 --- a/src/entt/signal/sigh.hpp +++ b/src/entt/signal/sigh.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -301,6 +302,7 @@ struct scoped_connection: private connection { template class sink { using signal_type = sigh; + using difference_type = typename std::iterator_traits::difference_type; template static void release(Type &value_or_instance, void *signal) { @@ -318,7 +320,8 @@ public: * @param ref A valid reference to a signal object. */ sink(sigh &ref) ENTT_NOEXCEPT - : signal{&ref} + : offset{}, + signal{&ref} {} /** @@ -329,6 +332,79 @@ public: return signal->calls.empty(); } + /** + * @brief Returns a sink that connects before a given function. + * @tparam Function A valid free function pointer. + * @return A properly initialized sink object. + */ + template + sink before() { + sink other{*this}; + auto &calls = signal->calls; + delegate delegate{entt::connect_arg}; + const auto it = std::find(calls.cbegin(), calls.cend(), std::move(delegate)); + other.offset = std::distance(it, calls.cend()); + return other; + } + + /** + * @brief Returns a sink that connects before a given member function or + * free function with payload. + * @tparam Candidate Member or free function to look for. + * @tparam Type Type of class or type of payload. + * @param value_or_instance A valid reference that fits the purpose. + * @return A properly initialized sink object. + */ + template + sink before(Type &value_or_instance) { + sink other{*this}; + auto &calls = signal->calls; + delegate delegate{entt::connect_arg, value_or_instance}; + const auto it = std::find(calls.cbegin(), calls.cend(), std::move(delegate)); + other.offset = std::distance(it, calls.cend()); + return other; + } + + /** + * @brief Returns a sink that connects before a given instance or specific + * payload. + * @tparam Type Type of class or type of payload. + * @param value_or_instance A valid reference that fits the purpose. + * @return A properly initialized sink object. + */ + template + sink before(Type &value_or_instance) { + return before(&value_or_instance); + } + + /** + * @brief Returns a sink that connects before a given opaque instance or + * payload. + * @param value_or_instance An opaque pointer that fits the purpose. + * @return A properly initialized sink object. + */ + sink before(const void *value_or_instance) { + sink other{*this}; + auto &calls = signal->calls; + const auto it = std::find_if(calls.cbegin(), calls.cend(), [value_or_instance](const auto &delegate) { + return delegate.instance() == value_or_instance; + }); + + other.offset = std::distance(it, calls.cend()); + return other; + } + + /** + * @brief Returns a sink that connects before anything else. + * @return A properly initialized sink object. + */ + sink before() { + sink other{*this}; + auto &calls = signal->calls; + other.offset = std::distance(calls.cbegin(), calls.cend()); + return other; + } + /** * @brief Connects a free function to a signal. * @@ -341,10 +417,9 @@ public: template connection connect() { disconnect(); - delegate conn{}; - conn.template connect<&release>(); - signal->calls.emplace_back(delegate{connect_arg}); - return { std::move(conn), signal }; + const auto position = signal->calls.end() - offset; + signal->calls.insert(position, delegate{connect_arg}); + return { delegate{connect_arg<&release>}, signal }; } /** @@ -367,10 +442,9 @@ public: template connection connect(Type &value_or_instance) { disconnect(value_or_instance); - delegate conn{}; - conn.template connect<&sink::release>(value_or_instance); - signal->calls.emplace_back(delegate{connect_arg, value_or_instance}); - return { std::move(conn), signal }; + const auto position = signal->calls.end() - offset; + signal->calls.insert(position, delegate{connect_arg, value_or_instance}); + return { delegate{connect_arg<&sink::release>, value_or_instance}, signal }; } /** @@ -380,9 +454,8 @@ public: template void disconnect() { auto &calls = signal->calls; - delegate delegate{}; - delegate.template connect(); - calls.erase(std::remove(calls.begin(), calls.end(), delegate), calls.end()); + delegate delegate{entt::connect_arg}; + calls.erase(std::remove(calls.begin(), calls.end(), std::move(delegate)), calls.end()); } /** @@ -395,9 +468,8 @@ public: template void disconnect(Type &value_or_instance) { auto &calls = signal->calls; - delegate delegate{}; - delegate.template connect(value_or_instance); - calls.erase(std::remove(calls.begin(), calls.end(), delegate), calls.end()); + delegate delegate{entt::connect_arg, value_or_instance}; + calls.erase(std::remove(calls.begin(), calls.end(), std::move(delegate)), calls.end()); } /** @@ -429,6 +501,7 @@ public: } private: + difference_type offset; signal_type *signal; };