Procházet zdrojové kódy

dispatcher works across boundaries now

Michele Caini před 7 roky
rodič
revize
d80a00701d
4 změnil soubory, kde provedl 56 přidání a 15 odebrání
  1. 0 1
      TODO
  2. 4 4
      docs/lib.md
  3. 43 10
      src/entt/signal/dispatcher.hpp
  4. 9 0
      test/entt/signal/dispatcher.cpp

+ 0 - 1
TODO

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

+ 4 - 4
docs/lib.md

@@ -159,9 +159,9 @@ as they are not strictly necessary.
 
 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 the `registry` class fully support _shared types_. Using
-`dispatcher` and `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_.
+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.

+ 43 - 10
src/entt/signal/dispatcher.hpp

@@ -8,6 +8,7 @@
 #include <type_traits>
 #include "../config/config.h"
 #include "../core/family.hpp"
+#include "../core/type_traits.hpp"
 #include "sigh.hpp"
 
 
@@ -75,19 +76,51 @@ class dispatcher {
         int current{};
     };
 
+    struct wrapper_data {
+        std::unique_ptr<base_wrapper> wrapper;
+        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 event_family::type<Event>;
+        }
+    }
+
     template<typename Event>
     signal_wrapper<Event> & wrapper() {
-        const auto type = event_family::type<Event>;
+        const auto wtype = type<Event>();
+        wrapper_data *wdata = nullptr;
+
+        if constexpr(is_shared_v<Event>) {
+            const auto it = std::find_if(wrappers.begin(), wrappers.end(), [wtype](const auto &wdata) {
+                return wdata.wrapper && wdata.runtime_type == wtype;
+            });
+
+            wdata = (it == wrappers.cend() ? &wrappers.emplace_back() : &(*it));
+        } else {
+            if(!(wtype < wrappers.size())) {
+                wrappers.resize(wtype+1);
+            }
 
-        if(!(type < wrappers.size())) {
-            wrappers.resize(type + 1);
+            wdata = &wrappers[wtype];
+
+            if(wdata->wrapper && wdata->runtime_type != wtype) {
+                wrappers.emplace_back();
+                std::swap(wrappers[wtype], wrappers.back());
+                wdata = &wrappers[wtype];
+            }
         }
 
-        if(!wrappers[type]) {
-            wrappers[type] = std::make_unique<signal_wrapper<Event>>();
+        if(!wdata->wrapper) {
+            wdata->wrapper = std::make_unique<signal_wrapper<Event>>();
+            wdata->runtime_type = wtype;
         }
 
-        return static_cast<signal_wrapper<Event> &>(*wrappers[type]);
+        return static_cast<signal_wrapper<Event> &>(*wdata->wrapper);
     }
 
 public:
@@ -201,16 +234,16 @@ public:
      */
     inline void update(Args... args) const {
         for(auto pos = wrappers.size(); pos; --pos) {
-            auto &wrapper = wrappers[pos-1];
+            auto &wdata = wrappers[pos-1];
 
-            if(wrapper) {
-                wrapper->publish(args...);
+            if(wdata.wrapper) {
+                wdata.wrapper->publish(args...);
             }
         }
     }
 
 private:
-    std::vector<std::unique_ptr<base_wrapper>> wrappers;
+    std::vector<wrapper_data> wrappers;
 };
 
 

+ 9 - 0
test/entt/signal/dispatcher.cpp

@@ -1,9 +1,13 @@
 #include <memory>
 #include <gtest/gtest.h>
+#include <entt/entity/entt_traits.hpp>
 #include <entt/signal/dispatcher.hpp>
 
 struct an_event {};
 struct another_event {};
+struct one_more_event {};
+
+ENTT_SHARED_TYPE(an_event)
 
 struct receiver {
     void receive(const an_event &, int value) { cnt += value; }
@@ -15,9 +19,14 @@ TEST(Dispatcher, Functionalities) {
     entt::dispatcher<int> dispatcher;
     receiver receiver;
 
+    dispatcher.trigger<one_more_event>(1);
+    dispatcher.enqueue<one_more_event>();
+    dispatcher.update<one_more_event>(1);
+
     dispatcher.sink<an_event>().connect<&receiver::receive>(&receiver);
     dispatcher.trigger<an_event>(1);
     dispatcher.enqueue<an_event>();
+
     dispatcher.enqueue<another_event>();
     dispatcher.update<another_event>(1);