Przeglądaj źródła

added dispatch::discard to clear pools of events (close #312)

Michele Caini 6 lat temu
rodzic
commit
b2fad7a567
2 zmienionych plików z 68 dodań i 10 usunięć
  1. 36 10
      src/entt/signal/dispatcher.hpp
  2. 32 0
      test/entt/signal/dispatcher.cpp

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

@@ -4,7 +4,9 @@
 
 #include <vector>
 #include <memory>
+#include <cstddef>
 #include <utility>
+#include <algorithm>
 #include <type_traits>
 #include "../config/config.h"
 #include "../core/family.hpp"
@@ -37,6 +39,7 @@ class dispatcher {
     struct base_wrapper {
         virtual ~base_wrapper() = default;
         virtual void publish() = 0;
+        virtual void clear() = 0;
     };
 
     template<typename Event>
@@ -45,12 +48,17 @@ class dispatcher {
         using sink_type = typename signal_type::sink_type;
 
         void publish() override {
-            for(const auto &event: events[current]) {
-                signal.publish(event);
+            const auto length = events.size();
+
+            for(std::size_t pos{}; pos < length; ++pos) {
+                signal.publish(events[pos]);
             }
 
-            events[current++].clear();
-            current %= std::extent<decltype(events)>::value;
+            events.erase(events.cbegin(), events.cbegin()+length);
+        }
+
+        void clear() override {
+            events.clear();
         }
 
         sink_type sink() ENTT_NOEXCEPT {
@@ -64,13 +72,12 @@ class dispatcher {
 
         template<typename... Args>
         void enqueue(Args &&... args) {
-            events[current].emplace_back(std::forward<Args>(args)...);
+            events.emplace_back(std::forward<Args>(args)...);
         }
 
     private:
         signal_type signal{};
-        std::vector<Event> events[2];
-        int current{};
+        std::vector<Event> events;
     };
 
     struct wrapper_data {
@@ -205,6 +212,27 @@ public:
         assure<std::decay_t<Event>>().enqueue(std::forward<Event>(event));
     }
 
+    /**
+     * @brief Discards all the events queued so far.
+     *
+     * If no types are provided, the dispatcher will clear all the existing
+     * pools.
+     *
+     * @tparam Event Type of events to discard.
+     */
+    template<typename... Event>
+    void discard() {
+        if constexpr(sizeof...(Event) == 0) {
+            std::for_each(wrappers.begin(), wrappers.end(), [](auto &&wdata) {
+                if(wdata.wrapper) {
+                    wdata.wrapper->clear();
+                }
+            });
+        } else {
+            (assure<std::decay_t<Event>>().clear(), ...);
+        }
+    }
+
     /**
      * @brief Delivers all the pending events of the given type.
      *
@@ -228,9 +256,7 @@ public:
      */
     void update() const {
         for(auto pos = wrappers.size(); pos; --pos) {
-            auto &wdata = wrappers[pos-1];
-
-            if(wdata.wrapper) {
+            if(auto &wdata = wrappers[pos-1]; wdata.wrapper) {
                 wdata.wrapper->publish();
             }
         }

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

@@ -10,6 +10,10 @@ struct one_more_event {};
 ENTT_NAMED_TYPE(an_event)
 
 struct receiver {
+    static void forward(entt::dispatcher &dispatcher, const an_event &event) {
+        dispatcher.enqueue(event);
+    }
+
     void receive(const an_event &) { ++cnt; }
     void reset() { cnt = 0; }
     int cnt{0};
@@ -39,6 +43,16 @@ TEST(Dispatcher, Functionalities) {
 
     ASSERT_EQ(receiver.cnt, 3);
 
+    dispatcher.enqueue<an_event>();
+    dispatcher.discard<an_event>();
+    dispatcher.update();
+
+    dispatcher.enqueue<an_event>();
+    dispatcher.discard();
+    dispatcher.update();
+
+    ASSERT_EQ(receiver.cnt, 3);
+
     receiver.reset();
 
     an_event event{};
@@ -51,3 +65,21 @@ TEST(Dispatcher, Functionalities) {
 
     ASSERT_EQ(receiver.cnt, 0);
 }
+
+TEST(Dispatcher, StopAndGo) {
+    entt::dispatcher dispatcher;
+    receiver receiver;
+
+    dispatcher.sink<an_event>().connect<&receiver::forward>(dispatcher);
+    dispatcher.sink<an_event>().connect<&receiver::receive>(receiver);
+
+    dispatcher.enqueue<an_event>();
+    dispatcher.update();
+
+    ASSERT_EQ(receiver.cnt, 1);
+
+    dispatcher.sink<an_event>().disconnect<&receiver::forward>(dispatcher);
+    dispatcher.update();
+
+    ASSERT_EQ(receiver.cnt, 2);
+}