Browse Source

sink::before (overloaded function)

Michele Caini 6 years ago
parent
commit
bfc2eca041
1 changed files with 88 additions and 15 deletions
  1. 88 15
      src/entt/signal/sigh.hpp

+ 88 - 15
src/entt/signal/sigh.hpp

@@ -4,6 +4,7 @@
 
 
 #include <vector>
 #include <vector>
 #include <utility>
 #include <utility>
+#include <iterator>
 #include <algorithm>
 #include <algorithm>
 #include <functional>
 #include <functional>
 #include <type_traits>
 #include <type_traits>
@@ -301,6 +302,7 @@ struct scoped_connection: private connection {
 template<typename Ret, typename... Args>
 template<typename Ret, typename... Args>
 class sink<Ret(Args...)> {
 class sink<Ret(Args...)> {
     using signal_type = sigh<Ret(Args...)>;
     using signal_type = sigh<Ret(Args...)>;
+    using difference_type = typename std::iterator_traits<typename decltype(signal_type::calls)::iterator>::difference_type;
 
 
     template<auto Candidate, typename Type>
     template<auto Candidate, typename Type>
     static void release(Type &value_or_instance, void *signal) {
     static void release(Type &value_or_instance, void *signal) {
@@ -318,7 +320,8 @@ public:
      * @param ref A valid reference to a signal object.
      * @param ref A valid reference to a signal object.
      */
      */
     sink(sigh<Ret(Args...)> &ref) ENTT_NOEXCEPT
     sink(sigh<Ret(Args...)> &ref) ENTT_NOEXCEPT
-        : signal{&ref}
+        : offset{},
+          signal{&ref}
     {}
     {}
 
 
     /**
     /**
@@ -329,6 +332,79 @@ public:
         return signal->calls.empty();
         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<auto Function>
+    sink before() {
+        sink other{*this};
+        auto &calls = signal->calls;
+        delegate<Ret(Args...)> delegate{entt::connect_arg<Function>};
+        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<auto Candidate, typename Type>
+    sink before(Type &value_or_instance) {
+        sink other{*this};
+        auto &calls = signal->calls;
+        delegate<Ret(Args...)> delegate{entt::connect_arg<Candidate>, 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<typename Type>
+    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.
      * @brief Connects a free function to a signal.
      *
      *
@@ -341,10 +417,9 @@ public:
     template<auto Function>
     template<auto Function>
     connection connect() {
     connection connect() {
         disconnect<Function>();
         disconnect<Function>();
-        delegate<void(void *)> conn{};
-        conn.template connect<&release<Function>>();
-        signal->calls.emplace_back(delegate<Ret(Args...)>{connect_arg<Function>});
-        return { std::move(conn), signal };
+        const auto position = signal->calls.end() - offset;
+        signal->calls.insert(position, delegate<Ret(Args...)>{connect_arg<Function>});
+        return { delegate<void(void *)>{connect_arg<&release<Function>>}, signal };
     }
     }
 
 
     /**
     /**
@@ -367,10 +442,9 @@ public:
     template<auto Candidate, typename Type>
     template<auto Candidate, typename Type>
     connection connect(Type &value_or_instance) {
     connection connect(Type &value_or_instance) {
         disconnect<Candidate>(value_or_instance);
         disconnect<Candidate>(value_or_instance);
-        delegate<void(void *)> conn{};
-        conn.template connect<&sink::release<Candidate, Type>>(value_or_instance);
-        signal->calls.emplace_back(delegate<Ret(Args...)>{connect_arg<Candidate>, value_or_instance});
-        return { std::move(conn), signal };
+        const auto position = signal->calls.end() - offset;
+        signal->calls.insert(position, delegate<Ret(Args...)>{connect_arg<Candidate>, value_or_instance});
+        return { delegate<void(void *)>{connect_arg<&sink::release<Candidate, Type>>, value_or_instance}, signal };
     }
     }
 
 
     /**
     /**
@@ -380,9 +454,8 @@ public:
     template<auto Function>
     template<auto Function>
     void disconnect() {
     void disconnect() {
         auto &calls = signal->calls;
         auto &calls = signal->calls;
-        delegate<Ret(Args...)> delegate{};
-        delegate.template connect<Function>();
-        calls.erase(std::remove(calls.begin(), calls.end(), delegate), calls.end());
+        delegate<Ret(Args...)> delegate{entt::connect_arg<Function>};
+        calls.erase(std::remove(calls.begin(), calls.end(), std::move(delegate)), calls.end());
     }
     }
 
 
     /**
     /**
@@ -395,9 +468,8 @@ public:
     template<auto Candidate, typename Type>
     template<auto Candidate, typename Type>
     void disconnect(Type &value_or_instance) {
     void disconnect(Type &value_or_instance) {
         auto &calls = signal->calls;
         auto &calls = signal->calls;
-        delegate<Ret(Args...)> delegate{};
-        delegate.template connect<Candidate>(value_or_instance);
-        calls.erase(std::remove(calls.begin(), calls.end(), delegate), calls.end());
+        delegate<Ret(Args...)> delegate{entt::connect_arg<Candidate>, value_or_instance};
+        calls.erase(std::remove(calls.begin(), calls.end(), std::move(delegate)), calls.end());
     }
     }
 
 
     /**
     /**
@@ -429,6 +501,7 @@ public:
     }
     }
 
 
 private:
 private:
+    difference_type offset;
     signal_type *signal;
     signal_type *signal;
 };
 };