From d80a00701d2c0bbf01e9586e1caf78fc21ee8a3b Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Sun, 24 Feb 2019 23:37:08 +0100 Subject: [PATCH] dispatcher works across boundaries now --- TODO | 1 - docs/lib.md | 8 ++--- src/entt/signal/dispatcher.hpp | 53 ++++++++++++++++++++++++++------- test/entt/signal/dispatcher.cpp | 9 ++++++ 4 files changed, 56 insertions(+), 15 deletions(-) diff --git a/TODO b/TODO index 7c09ac633..d8d9dc5fd 100644 --- a/TODO +++ b/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 diff --git a/docs/lib.md b/docs/lib.md index 2474743bc..3ff134830 100644 --- a/docs/lib.md +++ b/docs/lib.md @@ -159,9 +159,9 @@ as they are not strictly necessary. I'm still working hard to make everything work across boundaries.
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. diff --git a/src/entt/signal/dispatcher.hpp b/src/entt/signal/dispatcher.hpp index c385dd4af..749ef3b51 100644 --- a/src/entt/signal/dispatcher.hpp +++ b/src/entt/signal/dispatcher.hpp @@ -8,6 +8,7 @@ #include #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 wrapper; + ENTT_ID_TYPE runtime_type; + }; + + template + static auto type() ENTT_NOEXCEPT { + if constexpr(is_shared_v) { + return shared_traits::value; + } else { + return event_family::type; + } + } + template signal_wrapper & wrapper() { - const auto type = event_family::type; + const auto wtype = type(); + wrapper_data *wdata = nullptr; - if(!(type < wrappers.size())) { - wrappers.resize(type + 1); + if constexpr(is_shared_v) { + 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); + } + + 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>(); + if(!wdata->wrapper) { + wdata->wrapper = std::make_unique>(); + wdata->runtime_type = wtype; } - return static_cast &>(*wrappers[type]); + return static_cast &>(*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> wrappers; + std::vector wrappers; }; diff --git a/test/entt/signal/dispatcher.cpp b/test/entt/signal/dispatcher.cpp index 0965d716f..58a65a95a 100644 --- a/test/entt/signal/dispatcher.cpp +++ b/test/entt/signal/dispatcher.cpp @@ -1,9 +1,13 @@ #include #include +#include #include 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 dispatcher; receiver receiver; + dispatcher.trigger(1); + dispatcher.enqueue(); + dispatcher.update(1); + dispatcher.sink().connect<&receiver::receive>(&receiver); dispatcher.trigger(1); dispatcher.enqueue(); + dispatcher.enqueue(); dispatcher.update(1);