added dispatch::discard to clear pools of events (close #312)
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user