Просмотр исходного кода

delegate/sink: pointer payload

Michele Caini 6 лет назад
Родитель
Сommit
54f18f3f0d
5 измененных файлов с 146 добавлено и 31 удалено
  1. 0 1
      TODO
  2. 64 14
      src/entt/signal/delegate.hpp
  3. 68 2
      src/entt/signal/sigh.hpp
  4. 6 6
      test/entt/signal/delegate.cpp
  5. 8 8
      test/entt/signal/sigh.cpp

+ 0 - 1
TODO

@@ -33,4 +33,3 @@
   - auto foo(It first, It last = entity_type{null})
   - auto foo(It first, It last = entity_type{null})
 * range based registry::remove and some others?
 * range based registry::remove and some others?
 * nested groups: AB/ABC/ABCD/... (hints: sort, check functions)
 * nested groups: AB/ABC/ABCD/... (hints: sort, check functions)
-* pointer payload optimization for sigh

+ 64 - 14
src/entt/signal/delegate.hpp

@@ -27,8 +27,8 @@ template<typename Ret, typename... Args>
 auto to_function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);
 auto to_function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);
 
 
 
 
-template<typename Ret, typename... Args, typename Type, typename Payload, typename = std::enable_if_t<std::is_convertible_v<const Payload &, const Type &>>>
-auto to_function_pointer(Ret(*)(Type &, Args...), const Payload &) -> Ret(*)(Args...);
+template<typename Ret, typename... Args, typename Type, typename Payload, typename = std::enable_if_t<std::is_convertible_v<const Payload *, const Type *>>>
+auto to_function_pointer(Ret(*)(Type &, Args...), const Payload *) -> Ret(*)(Args...);
 
 
 
 
 template<typename Ret, typename... Args, typename Type, typename Payload, typename = std::enable_if_t<std::is_convertible_v<const Payload *, const Type *>>>
 template<typename Ret, typename... Args, typename Type, typename Payload, typename = std::enable_if_t<std::is_convertible_v<const Payload *, const Type *>>>
@@ -36,15 +36,15 @@ auto to_function_pointer(Ret(*)(Type *, Args...), const Payload *) -> Ret(*)(Arg
 
 
 
 
 template<typename Class, typename Ret, typename... Args>
 template<typename Class, typename Ret, typename... Args>
-auto to_function_pointer(Ret(Class:: *)(Args...), const Class &) -> Ret(*)(Args...);
+auto to_function_pointer(Ret(Class:: *)(Args...), const Class *) -> Ret(*)(Args...);
 
 
 
 
 template<typename Class, typename Ret, typename... Args>
 template<typename Class, typename Ret, typename... Args>
-auto to_function_pointer(Ret(Class:: *)(Args...) const, const Class &) -> Ret(*)(Args...);
+auto to_function_pointer(Ret(Class:: *)(Args...) const, const Class *) -> Ret(*)(Args...);
 
 
 
 
 template<typename Class, typename Type>
 template<typename Class, typename Type>
-auto to_function_pointer(Type Class:: *, const Class &) -> Type(*)();
+auto to_function_pointer(Type Class:: *, const Class *) -> Type(*)();
 
 
 
 
 template<typename... Type>
 template<typename... Type>
@@ -171,13 +171,27 @@ public:
      * or a free function with payload.
      * or a free function with payload.
      * @tparam Candidate Member or free function to connect to the delegate.
      * @tparam Candidate Member or free function to connect to the delegate.
      * @tparam Type Type of class or type of payload.
      * @tparam Type Type of class or type of payload.
-     * @param value_or_instance A valid object that fits the purpose.
+     * @param value_or_instance A valid reference that fits the purpose.
      */
      */
     template<auto Candidate, typename Type>
     template<auto Candidate, typename Type>
-    delegate(connect_arg_t<Candidate>, Type &&value_or_instance) ENTT_NOEXCEPT
+    delegate(connect_arg_t<Candidate>, Type &value_or_instance) ENTT_NOEXCEPT
         : delegate{}
         : delegate{}
     {
     {
-        connect<Candidate>(std::forward<Type>(value_or_instance));
+        connect<Candidate>(value_or_instance);
+    }
+
+    /**
+     * @brief Constructs a delegate and connects a member for a given instance
+     * or a free function with payload.
+     * @tparam Candidate Member or free function to connect to the delegate.
+     * @tparam Type Type of class or type of payload.
+     * @param value_or_instance A valid pointer that fits the purpose.
+     */
+    template<auto Candidate, typename Type>
+    delegate(connect_arg_t<Candidate>, Type *value_or_instance) ENTT_NOEXCEPT
+        : delegate{}
+    {
+        connect<Candidate>(value_or_instance);
     }
     }
 
 
     /**
     /**
@@ -203,12 +217,33 @@ public:
      *
      *
      * @tparam Candidate Member or free function to connect to the delegate.
      * @tparam Candidate Member or free function to connect to the delegate.
      * @tparam Type Type of class or type of payload.
      * @tparam Type Type of class or type of payload.
-     * @param value_or_instance A valid object that fits the purpose.
+     * @param value_or_instance A valid reference that fits the purpose.
      */
      */
     template<auto Candidate, typename Type>
     template<auto Candidate, typename Type>
-    void connect(Type &&value_or_instance) ENTT_NOEXCEPT {
-        constexpr auto extent = internal::function_extent_v<internal::to_function_pointer_t<decltype(Candidate), Type>>;
-        connect<Candidate>(std::forward<Type>(std::forward<Type>(value_or_instance)), std::make_index_sequence<extent>{});
+    void connect(Type &value_or_instance) ENTT_NOEXCEPT {
+        constexpr auto extent = internal::function_extent_v<internal::to_function_pointer_t<decltype(Candidate), Type *>>;
+        connect<Candidate>(value_or_instance, std::make_index_sequence<extent>{});
+    }
+
+    /**
+     * @brief Connects a member function for a given instance or a free function
+     * with payload to a delegate.
+     *
+     * The delegate isn't responsible for the connected object or the payload.
+     * Users must always guarantee that the lifetime of the instance overcomes
+     * the one  of the delegate.<br/>
+     * When used to connect a free function with payload, its signature must be
+     * such that the instance is the first argument before the ones used to
+     * define the delegate itself.
+     *
+     * @tparam Candidate Member or free function to connect to the delegate.
+     * @tparam Type Type of class or type of payload.
+     * @param value_or_instance A valid pointer that fits the purpose.
+     */
+    template<auto Candidate, typename Type>
+    void connect(Type *value_or_instance) ENTT_NOEXCEPT {
+        constexpr auto extent = internal::function_extent_v<internal::to_function_pointer_t<decltype(Candidate), Type *>>;
+        connect<Candidate>(value_or_instance, std::make_index_sequence<extent>{});
     }
     }
 
 
     /**
     /**
@@ -310,8 +345,23 @@ delegate(connect_arg_t<Function>) ENTT_NOEXCEPT
  * @tparam Type Type of class or type of payload.
  * @tparam Type Type of class or type of payload.
  */
  */
 template<auto Candidate, typename Type>
 template<auto Candidate, typename Type>
-delegate(connect_arg_t<Candidate>, Type &&value_or_instance) ENTT_NOEXCEPT
--> delegate<std::remove_pointer_t<internal::to_function_pointer_t<decltype(Candidate), Type>>>;
+delegate(connect_arg_t<Candidate>, Type &value_or_instance) ENTT_NOEXCEPT
+-> delegate<std::remove_pointer_t<internal::to_function_pointer_t<decltype(Candidate), Type *>>>;
+
+
+/**
+ * @brief Deduction guide.
+ *
+ * It allows to deduce the function type of the delegate directly from a member
+ * or a free function with payload provided to the constructor.
+ *
+ * @param value_or_instance A valid pointer that fits the purpose.
+ * @tparam Candidate Member or free function to connect to the delegate.
+ * @tparam Type Type of class or type of payload.
+ */
+template<auto Candidate, typename Type>
+delegate(connect_arg_t<Candidate>, Type *value_or_instance) ENTT_NOEXCEPT
+-> delegate<std::remove_pointer_t<internal::to_function_pointer_t<decltype(Candidate), Type *>>>;
 
 
 
 
 }
 }

+ 68 - 2
src/entt/signal/sigh.hpp

@@ -305,7 +305,7 @@ class sink<Ret(Args...)> {
     using difference_type = typename std::iterator_traits<typename decltype(signal_type::calls)::iterator>::difference_type;
     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) {
         sink{*static_cast<signal_type *>(signal)}.disconnect<Candidate>(value_or_instance);
         sink{*static_cast<signal_type *>(signal)}.disconnect<Candidate>(value_or_instance);
     }
     }
 
 
@@ -371,6 +371,27 @@ public:
         return other;
         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 pointer that fits the purpose.
+     * @return A properly initialized sink object.
+     */
+    template<auto Candidate, typename Type>
+    sink before(Type *value_or_instance) {
+        delegate<Ret(Args...)> call{};
+        call.template connect<Candidate>(value_or_instance);
+
+        const auto &calls = signal->calls;
+        const auto it = std::find(calls.cbegin(), calls.cend(), std::move(call));
+
+        sink other{*this};
+        other.offset = std::distance(it, calls.cend());
+        return other;
+    }
+
     /**
     /**
      * @brief Returns a sink that connects before a given instance or specific
      * @brief Returns a sink that connects before a given instance or specific
      * payload.
      * payload.
@@ -461,7 +482,37 @@ public:
         signal->calls.insert(signal->calls.end() - offset, std::move(call));
         signal->calls.insert(signal->calls.end() - offset, std::move(call));
 
 
         delegate<void(void *)> conn{};
         delegate<void(void *)> conn{};
-        conn.template connect<&release<Candidate, Type>>(value_or_instance);
+        conn.template connect<&release<Candidate, Type &>>(value_or_instance);
+        return { std::move(conn), signal };
+    }
+
+    /**
+     * @brief Connects a member function or a free function with payload to a
+     * signal.
+     *
+     * The signal isn't responsible for the connected object or the payload.
+     * Users must always guarantee that the lifetime of the instance overcomes
+     * the one  of the delegate. On the other side, the signal handler performs
+     * checks to avoid multiple connections for the same function.<br/>
+     * When used to connect a free function with payload, its signature must be
+     * such that the instance is the first argument before the ones used to
+     * define the delegate itself.
+     *
+     * @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>
+    connection connect(Type *value_or_instance) {
+        disconnect<Candidate>(value_or_instance);
+
+        delegate<Ret(Args...)> call{};
+        call.template connect<Candidate>(value_or_instance);
+        signal->calls.insert(signal->calls.end() - offset, std::move(call));
+
+        delegate<void(void *)> conn{};
+        conn.template connect<&release<Candidate, Type *>>(value_or_instance);
         return { std::move(conn), signal };
         return { std::move(conn), signal };
     }
     }
 
 
@@ -492,6 +543,21 @@ public:
         calls.erase(std::remove(calls.begin(), calls.end(), std::move(call)), calls.end());
         calls.erase(std::remove(calls.begin(), calls.end(), std::move(call)), calls.end());
     }
     }
 
 
+    /**
+     * @brief Disconnects a member function or a free function with payload from
+     * a signal.
+     * @tparam Candidate Member or free function to disconnect from the signal.
+     * @tparam Type Type of class or type of payload.
+     * @param value_or_instance A valid pointer that fits the purpose.
+     */
+    template<auto Candidate, typename Type>
+    void disconnect(Type *value_or_instance) {
+        auto &calls = signal->calls;
+        delegate<Ret(Args...)> call{};
+        call.template connect<Candidate>(value_or_instance);
+        calls.erase(std::remove(calls.begin(), calls.end(), std::move(call)), calls.end());
+    }
+
     /**
     /**
      * @brief Disconnects member functions or free functions based on an
      * @brief Disconnects member functions or free functions based on an
      * instance or specific payload.
      * instance or specific payload.

+ 6 - 6
test/entt/signal/delegate.cpp

@@ -212,13 +212,13 @@ TEST(Delegate, DeductionGuide) {
     entt::delegate curried_func_with_const_ptr{entt::connect_arg<&curried_by_ptr>, &std::as_const(value)};
     entt::delegate curried_func_with_const_ptr{entt::connect_arg<&curried_by_ptr>, &std::as_const(value)};
     entt::delegate member_func_f{entt::connect_arg<&const_nonconst_noexcept::f>, functor};
     entt::delegate member_func_f{entt::connect_arg<&const_nonconst_noexcept::f>, functor};
     entt::delegate member_func_g{entt::connect_arg<&const_nonconst_noexcept::g>, functor};
     entt::delegate member_func_g{entt::connect_arg<&const_nonconst_noexcept::g>, functor};
-    entt::delegate member_func_h{entt::connect_arg<&const_nonconst_noexcept::h>, functor};
-    entt::delegate member_func_h_const{entt::connect_arg<&const_nonconst_noexcept::h>, std::as_const(functor)};
+    entt::delegate member_func_h{entt::connect_arg<&const_nonconst_noexcept::h>, &functor};
+    entt::delegate member_func_h_const{entt::connect_arg<&const_nonconst_noexcept::h>, &std::as_const(functor)};
     entt::delegate member_func_i{entt::connect_arg<&const_nonconst_noexcept::i>, functor};
     entt::delegate member_func_i{entt::connect_arg<&const_nonconst_noexcept::i>, functor};
     entt::delegate member_func_i_const{entt::connect_arg<&const_nonconst_noexcept::i>, std::as_const(functor)};
     entt::delegate member_func_i_const{entt::connect_arg<&const_nonconst_noexcept::i>, std::as_const(functor)};
     entt::delegate data_member_u{entt::connect_arg<&const_nonconst_noexcept::u>, functor};
     entt::delegate data_member_u{entt::connect_arg<&const_nonconst_noexcept::u>, functor};
-    entt::delegate data_member_v{entt::connect_arg<&const_nonconst_noexcept::v>, functor};
-    entt::delegate data_member_v_const{entt::connect_arg<&const_nonconst_noexcept::v>, std::as_const(functor)};
+    entt::delegate data_member_v{entt::connect_arg<&const_nonconst_noexcept::v>, &functor};
+    entt::delegate data_member_v_const{entt::connect_arg<&const_nonconst_noexcept::v>, &std::as_const(functor)};
 
 
     static_assert(std::is_same_v<typename decltype(func)::function_type, int(const int &)>);
     static_assert(std::is_same_v<typename decltype(func)::function_type, int(const int &)>);
     static_assert(std::is_same_v<typename decltype(curried_func_with_ref)::function_type, int(int)>);
     static_assert(std::is_same_v<typename decltype(curried_func_with_ref)::function_type, int(int)>);
@@ -330,8 +330,8 @@ TEST(Delegate, VoidVsNonVoidReturnType) {
     delegate_functor functor;
     delegate_functor functor;
 
 
     entt::delegate<void(int)> func{entt::connect_arg<&delegate_function>};
     entt::delegate<void(int)> func{entt::connect_arg<&delegate_function>};
-    entt::delegate<void(int)> member{entt::connect_arg<&delegate_functor::operator()>, functor};
-    entt::delegate<void(int)> cmember{entt::connect_arg<&delegate_functor::identity>, std::as_const(functor)};
+    entt::delegate<void(int)> member{entt::connect_arg<&delegate_functor::operator()>, &functor};
+    entt::delegate<void(int)> cmember{entt::connect_arg<&delegate_functor::identity>, &std::as_const(functor)};
 
 
     ASSERT_TRUE(func);
     ASSERT_TRUE(func);
     ASSERT_TRUE(member);
     ASSERT_TRUE(member);

+ 8 - 8
test/entt/signal/sigh.cpp

@@ -165,7 +165,7 @@ TEST_F(SigH, Members) {
     ASSERT_TRUE(sigh.empty());
     ASSERT_TRUE(sigh.empty());
     ASSERT_EQ(0u, sigh.size());
     ASSERT_EQ(0u, sigh.size());
 
 
-    sink.connect<&sigh_listener::g>(l1);
+    sink.connect<&sigh_listener::g>(&l1);
     sink.connect<&sigh_listener::h>(l2);
     sink.connect<&sigh_listener::h>(l2);
 
 
     ASSERT_FALSE(sigh.empty());
     ASSERT_FALSE(sigh.empty());
@@ -188,7 +188,7 @@ TEST_F(SigH, Collector) {
     entt::sink sink{sigh};
     entt::sink sink{sigh};
     int cnt = 0;
     int cnt = 0;
 
 
-    sink.connect<&sigh_listener::g>(listener);
+    sink.connect<&sigh_listener::g>(&listener);
     sink.connect<&sigh_listener::h>(listener);
     sink.connect<&sigh_listener::h>(listener);
 
 
     listener.k = true;
     listener.k = true;
@@ -218,7 +218,7 @@ TEST_F(SigH, CollectorVoid) {
     entt::sink sink{sigh};
     entt::sink sink{sigh};
     int cnt = 0;
     int cnt = 0;
 
 
-    sink.connect<&sigh_listener::g>(listener);
+    sink.connect<&sigh_listener::g>(&listener);
     sink.connect<&sigh_listener::h>(listener);
     sink.connect<&sigh_listener::h>(listener);
     sigh.collect([&cnt]() { ++cnt; }, 42);
     sigh.collect([&cnt]() { ++cnt; }, 42);
 
 
@@ -330,18 +330,18 @@ TEST_F(SigH, ConstNonConstNoExcept) {
     const const_nonconst_noexcept cfunctor;
     const const_nonconst_noexcept cfunctor;
 
 
     sink.connect<&const_nonconst_noexcept::f>(functor);
     sink.connect<&const_nonconst_noexcept::f>(functor);
-    sink.connect<&const_nonconst_noexcept::g>(functor);
+    sink.connect<&const_nonconst_noexcept::g>(&functor);
     sink.connect<&const_nonconst_noexcept::h>(cfunctor);
     sink.connect<&const_nonconst_noexcept::h>(cfunctor);
-    sink.connect<&const_nonconst_noexcept::i>(cfunctor);
+    sink.connect<&const_nonconst_noexcept::i>(&cfunctor);
     sigh.publish();
     sigh.publish();
 
 
     ASSERT_EQ(functor.cnt, 2);
     ASSERT_EQ(functor.cnt, 2);
     ASSERT_EQ(cfunctor.cnt, 2);
     ASSERT_EQ(cfunctor.cnt, 2);
 
 
     sink.disconnect<&const_nonconst_noexcept::f>(functor);
     sink.disconnect<&const_nonconst_noexcept::f>(functor);
-    sink.disconnect<&const_nonconst_noexcept::g>(functor);
+    sink.disconnect<&const_nonconst_noexcept::g>(&functor);
     sink.disconnect<&const_nonconst_noexcept::h>(cfunctor);
     sink.disconnect<&const_nonconst_noexcept::h>(cfunctor);
-    sink.disconnect<&const_nonconst_noexcept::i>(cfunctor);
+    sink.disconnect<&const_nonconst_noexcept::i>(&cfunctor);
     sigh.publish();
     sigh.publish();
 
 
     ASSERT_EQ(functor.cnt, 2);
     ASSERT_EQ(functor.cnt, 2);
@@ -444,7 +444,7 @@ TEST_F(SigH, BeforeListenerNotPresent) {
     before_after functor;
     before_after functor;
 
 
     sink.connect<&before_after::mul>(functor);
     sink.connect<&before_after::mul>(functor);
-    sink.before<&before_after::add>(functor).connect<&before_after::add>(functor);
+    sink.before<&before_after::add>(&functor).connect<&before_after::add>(functor);
     sigh.publish(2);
     sigh.publish(2);
 
 
     ASSERT_EQ(functor.value, 2);
     ASSERT_EQ(functor.value, 2);