Selaa lähdekoodia

emitter works across boundaries now

Michele Caini 7 vuotta sitten
vanhempi
commit
770e57c361
5 muutettua tiedostoa jossa 65 lisäystä ja 44 poistoa
  1. 1 2
      TODO
  2. 1 13
      docs/lib.md
  3. 7 7
      src/entt/signal/dispatcher.hpp
  4. 51 22
      src/entt/signal/emitter.hpp
  5. 5 0
      test/entt/signal/emitter.cpp

+ 1 - 2
TODO

@@ -23,5 +23,4 @@
 * cleanup - see https://github.com/skypjack/entt/commit/ad5cedc08c83e8cbcc8aaeac9634d44624ffe35a#commitcomment-32380903
 * cleanup - see https://github.com/skypjack/entt/commit/ad5cedc08c83e8cbcc8aaeac9634d44624ffe35a#commitcomment-32380903
 
 
 ==> can we do more for shared libraries? who knows... see #144
 ==> can we do more for shared libraries? who knows... see #144
-* to be updated: emitter
-* to be updated: doc
+* test across boundaries dispatcher and emitter

+ 1 - 13
docs/lib.md

@@ -11,7 +11,6 @@
 * [Macros, macros everywhere](#macros-macros-everywhere)
 * [Macros, macros everywhere](#macros-macros-everywhere)
   * [Conflicts](#conflict)
   * [Conflicts](#conflict)
 * [Allocations: the dark side of the force](#allocations-the-dark-side-of-the-force)
 * [Allocations: the dark side of the force](#allocations-the-dark-side-of-the-force)
-* [Note](#note)
 <!--
 <!--
 @endcond TURN_OFF_DOXYGEN
 @endcond TURN_OFF_DOXYGEN
 -->
 -->
@@ -126,7 +125,7 @@ hashing strings during compilation. Therefore, conflicts are rare but still
 possible. In case of conflicts, everything simply will get broken at runtime and
 possible. In case of conflicts, everything simply will get broken at runtime and
 the strangest things will probably take place.<br/>
 the strangest things will probably take place.<br/>
 Unfortunately, there is no safe way to prevent it. If this happens, it will be
 Unfortunately, there is no safe way to prevent it. If this happens, it will be
-enough to give a different name to one of the conflicting types to solve the
+enough to give a different value to one of the conflicting types to solve the
 problem. To do this, users can either assign a different name to the class or
 problem. To do this, users can either assign a different name to the class or
 directly define a specialization for the `shared_traits` class template.
 directly define a specialization for the `shared_traits` class template.
 
 
@@ -154,14 +153,3 @@ enough).
 Maybe one day some dedicated methods will be added that do nothing but create a
 Maybe one day some dedicated methods will be added that do nothing but create a
 pool for a given type. Until now it has been preferred to keep the API cleaner
 pool for a given type. Until now it has been preferred to keep the API cleaner
 as they are not strictly necessary.
 as they are not strictly necessary.
-
-# Note
-
-I'm still working hard to make everything work across boundaries.<br/>
-The classes affected by the problem were `registry`, `dispatcher` and `emitter`.
-Currently, only `registry` and `dispatcher` fully support _shared types_. Using
-`emitter` across boundaries isn't allowed yet and can result in unexpected
-behavior on Windows in general and on GNU/Linux when default visibility is set
-to _hidden_.
-
-Stay tuned for future updates.

+ 7 - 7
src/entt/signal/dispatcher.hpp

@@ -91,7 +91,7 @@ class dispatcher {
     }
     }
 
 
     template<typename Event>
     template<typename Event>
-    signal_wrapper<Event> & wrapper() {
+    signal_wrapper<Event> & assure() {
         const auto wtype = type<Event>();
         const auto wtype = type<Event>();
         wrapper_data *wdata = nullptr;
         wrapper_data *wdata = nullptr;
 
 
@@ -147,7 +147,7 @@ public:
      */
      */
     template<typename Event>
     template<typename Event>
     inline sink_type<Event> sink() ENTT_NOEXCEPT {
     inline sink_type<Event> sink() ENTT_NOEXCEPT {
-        return wrapper<Event>().sink();
+        return assure<Event>().sink();
     }
     }
 
 
     /**
     /**
@@ -162,7 +162,7 @@ public:
      */
      */
     template<typename Event>
     template<typename Event>
     inline void trigger(Event &&event, Args... args) {
     inline void trigger(Event &&event, Args... args) {
-        wrapper<std::decay_t<Event>>().trigger(std::forward<Event>(event), args...);
+        assure<std::decay_t<Event>>().trigger(std::forward<Event>(event), args...);
     }
     }
 
 
     /**
     /**
@@ -176,7 +176,7 @@ public:
      */
      */
     template<typename Event>
     template<typename Event>
     inline void trigger(Args... args) {
     inline void trigger(Args... args) {
-        wrapper<std::decay_t<Event>>().trigger(Event{}, args...);
+        assure<std::decay_t<Event>>().trigger(Event{}, args...);
     }
     }
 
 
     /**
     /**
@@ -191,7 +191,7 @@ public:
      */
      */
     template<typename Event, typename... Params>
     template<typename Event, typename... Params>
     inline void enqueue(Params &&... params) {
     inline void enqueue(Params &&... params) {
-        wrapper<Event>().enqueue(std::forward<Params>(params)...);
+        assure<Event>().enqueue(std::forward<Params>(params)...);
     }
     }
 
 
     /**
     /**
@@ -205,7 +205,7 @@ public:
      */
      */
     template<typename Event>
     template<typename Event>
     inline void enqueue(Event &&event) {
     inline void enqueue(Event &&event) {
-        wrapper<std::decay_t<Event>>().enqueue(std::forward<Event>(event));
+        assure<std::decay_t<Event>>().enqueue(std::forward<Event>(event));
     }
     }
 
 
     /**
     /**
@@ -220,7 +220,7 @@ public:
      */
      */
     template<typename Event>
     template<typename Event>
     inline void update(Args... args) {
     inline void update(Args... args) {
-        wrapper<Event>().publish(args...);
+        assure<Event>().publish(args...);
     }
     }
 
 
     /**
     /**

+ 51 - 22
src/entt/signal/emitter.hpp

@@ -11,6 +11,7 @@
 #include <list>
 #include <list>
 #include "../config/config.h"
 #include "../config/config.h"
 #include "../core/family.hpp"
 #include "../core/family.hpp"
+#include "../core/type_traits.hpp"
 
 
 
 
 namespace entt {
 namespace entt {
@@ -114,19 +115,51 @@ class emitter {
         container_type on_list{};
         container_type on_list{};
     };
     };
 
 
+    struct handler_data {
+        std::unique_ptr<base_handler> handler;
+        ENTT_ID_TYPE runtime_type;
+    };
+
+    template<typename Event>
+    static auto type() ENTT_NOEXCEPT {
+        if constexpr(is_shared_v<Event>) {
+            return shared_traits<Event>::value;
+        } else {
+            return handler_family::type<Event>;
+        }
+    }
+
     template<typename Event>
     template<typename Event>
-    event_handler<Event> & handler() ENTT_NOEXCEPT {
-        const auto family = handler_family::type<Event>;
+    event_handler<Event> * assure() const ENTT_NOEXCEPT {
+        const auto htype = type<Event>();
+        handler_data *hdata = nullptr;
+
+        if constexpr(is_shared_v<Event>) {
+            const auto it = std::find_if(handlers.begin(), handlers.end(), [htype](const auto &hdata) {
+                return hdata.handler && hdata.runtime_type == htype;
+            });
+
+            hdata = (it == handlers.cend() ? &handlers.emplace_back() : &(*it));
+        } else {
+            if(!(htype < handlers.size())) {
+                handlers.resize(htype+1);
+            }
+
+            hdata = &handlers[htype];
 
 
-        if(!(family < handlers.size())) {
-            handlers.resize(family+1);
+            if(hdata->handler && hdata->runtime_type != htype) {
+                handlers.emplace_back();
+                std::swap(handlers[htype], handlers.back());
+                hdata = &handlers[htype];
+            }
         }
         }
 
 
-        if(!handlers[family]) {
-            handlers[family] = std::make_unique<event_handler<Event>>();
+        if(!hdata->handler) {
+            hdata->handler = std::make_unique<event_handler<Event>>();
+            hdata->runtime_type = htype;
         }
         }
 
 
-        return static_cast<event_handler<Event> &>(*handlers[family]);
+        return static_cast<event_handler<Event> *>(hdata->handler.get());
     }
     }
 
 
 public:
 public:
@@ -191,7 +224,7 @@ public:
      */
      */
     template<typename Event, typename... Args>
     template<typename Event, typename... Args>
     void publish(Args &&... args) {
     void publish(Args &&... args) {
-        handler<Event>().publish({ std::forward<Args>(args)... }, *static_cast<Derived *>(this));
+        assure<Event>()->publish({ std::forward<Args>(args)... }, *static_cast<Derived *>(this));
     }
     }
 
 
     /**
     /**
@@ -216,7 +249,7 @@ public:
      */
      */
     template<typename Event>
     template<typename Event>
     connection<Event> on(listener<Event> listener) {
     connection<Event> on(listener<Event> listener) {
-        return handler<Event>().on(std::move(listener));
+        return assure<Event>()->on(std::move(listener));
     }
     }
 
 
     /**
     /**
@@ -241,7 +274,7 @@ public:
      */
      */
     template<typename Event>
     template<typename Event>
     connection<Event> once(listener<Event> listener) {
     connection<Event> once(listener<Event> listener) {
-        return handler<Event>().once(std::move(listener));
+        return assure<Event>()->once(std::move(listener));
     }
     }
 
 
     /**
     /**
@@ -255,7 +288,7 @@ public:
      */
      */
     template<typename Event>
     template<typename Event>
     void erase(connection<Event> conn) ENTT_NOEXCEPT {
     void erase(connection<Event> conn) ENTT_NOEXCEPT {
-        handler<Event>().erase(std::move(conn));
+        assure<Event>()->erase(std::move(conn));
     }
     }
 
 
     /**
     /**
@@ -268,7 +301,7 @@ public:
      */
      */
     template<typename Event>
     template<typename Event>
     void clear() ENTT_NOEXCEPT {
     void clear() ENTT_NOEXCEPT {
-        handler<Event>().clear();
+        assure<Event>()->clear();
     }
     }
 
 
     /**
     /**
@@ -278,8 +311,8 @@ public:
      * results in undefined behavior.
      * results in undefined behavior.
      */
      */
     void clear() ENTT_NOEXCEPT {
     void clear() ENTT_NOEXCEPT {
-        std::for_each(handlers.begin(), handlers.end(), [](auto &&handler) {
-            return handler ? handler->clear() : void();
+        std::for_each(handlers.begin(), handlers.end(), [](auto &&hdata) {
+            return hdata.handler ? hdata.handler->clear() : void();
         });
         });
     }
     }
 
 
@@ -290,11 +323,7 @@ public:
      */
      */
     template<typename Event>
     template<typename Event>
     bool empty() const ENTT_NOEXCEPT {
     bool empty() const ENTT_NOEXCEPT {
-        const auto family = handler_family::type<Event>;
-
-        return (!(family < handlers.size()) ||
-                !handlers[family] ||
-                static_cast<event_handler<Event> &>(*handlers[family]).empty());
+        return assure<Event>()->empty();
     }
     }
 
 
     /**
     /**
@@ -302,13 +331,13 @@ public:
      * @return True if there are no listeners registered, false otherwise.
      * @return True if there are no listeners registered, false otherwise.
      */
      */
     bool empty() const ENTT_NOEXCEPT {
     bool empty() const ENTT_NOEXCEPT {
-        return std::all_of(handlers.cbegin(), handlers.cend(), [](auto &&handler) {
-            return !handler || handler->empty();
+        return std::all_of(handlers.cbegin(), handlers.cend(), [](auto &&hdata) {
+            return !hdata.handler || hdata.handler->empty();
         });
         });
     }
     }
 
 
 private:
 private:
-    std::vector<std::unique_ptr<base_handler>> handlers{};
+    mutable std::vector<handler_data> handlers{};
 };
 };
 
 
 
 

+ 5 - 0
test/entt/signal/emitter.cpp

@@ -1,15 +1,20 @@
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
+#include <entt/entity/entt_traits.hpp>
 #include <entt/signal/emitter.hpp>
 #include <entt/signal/emitter.hpp>
 
 
 struct test_emitter: entt::emitter<test_emitter> {};
 struct test_emitter: entt::emitter<test_emitter> {};
 
 
 struct foo_event { int i; char c; };
 struct foo_event { int i; char c; };
 struct bar_event {};
 struct bar_event {};
+struct quux_event {};
+
+ENTT_SHARED_TYPE(foo_event)
 
 
 TEST(Emitter, Clear) {
 TEST(Emitter, Clear) {
     test_emitter emitter;
     test_emitter emitter;
 
 
     ASSERT_TRUE(emitter.empty());
     ASSERT_TRUE(emitter.empty());
+    ASSERT_TRUE(emitter.empty<quux_event>());
 
 
     emitter.on<foo_event>([](const auto &, const auto &){});
     emitter.on<foo_event>([](const auto &, const auto &){});