added support for extra arguments to dispatcher
This commit is contained in:
12
TODO
12
TODO
@@ -8,7 +8,6 @@
|
||||
* define systems as composable mixins (initializazion, reactive, update, whatever) with flexible auto-detected arguments (registry, views, etc)
|
||||
* runner proposal: https://en.wikipedia.org/wiki/Fork%E2%80%93join_model https://slide-rs.github.io/specs/03_dispatcher.html
|
||||
* is it possible to iterate all the components assigned to an entity through a common base class?
|
||||
* can we do more for shared libraries? who knows... see #144
|
||||
* work stealing job system (see #100)
|
||||
* meta: sort of meta view based on meta stuff to iterate entities, void * and meta info objects
|
||||
* meta: move-to-head optimization when searching by name on parts (data, func, etc)
|
||||
@@ -16,10 +15,17 @@
|
||||
* destroy overload that accepts a couple of iterators (see create)
|
||||
* allow for built-in parallel each if possible
|
||||
* add on-the-fly sort functionality (is it possible?)
|
||||
* write/show how to create an archetype based model on top of EnTT
|
||||
* write/show how to create prefabs on top of EnTT (that's easy!!)
|
||||
* mention hunter in the readme file, section packaging tools
|
||||
* travis + windows is now available, try it
|
||||
* events on replace, so that one can track updated components? indagate impact
|
||||
* optimize for empty component - maybe it's possible with a raw-less view that uses fake iterators (with correct size (correct size, same component)
|
||||
* tags revenge: if it's possible, reintroduce them but without a link to entities (see #169 for more details)
|
||||
|
||||
Required test:
|
||||
* can we do more for shared libraries? who knows... see #144
|
||||
* type_info::hash_code can be used in place of family when it comes to working with dlls
|
||||
|
||||
Ready to go:
|
||||
* stealing archetype-like model on top of EnTT (design completed, wip dev)
|
||||
* write/show how to create an archetype based model on top of EnTT
|
||||
* do not include it in EnTT, it breaks the pay-for-what-you-use principle all the ways
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
#include "../core/family.hpp"
|
||||
@@ -22,13 +21,17 @@ namespace entt {
|
||||
* events to be published all together once per tick.<br/>
|
||||
* Listeners are provided in the form of member functions. For each event of
|
||||
* type `Event`, listeners are such that they can be invoked with an argument of
|
||||
* type `const Event &`, no matter what the return type is.
|
||||
* type `const Event &` plus an extra list of arguments to forward with the
|
||||
* event itself, no matter what the return type is.
|
||||
*
|
||||
* Member functions named `receive` are automatically detected and registered or
|
||||
* unregistered by the dispatcher. The type of the instances is `Class *` (a
|
||||
* naked pointer). It means that users must guarantee that the lifetimes of the
|
||||
* instances overcome the one of the dispatcher itself to avoid crashes.
|
||||
*
|
||||
* @tparam Args Types of arguments to forward along with an event.
|
||||
*/
|
||||
template<typename... Args>
|
||||
class dispatcher final {
|
||||
using event_family = family<struct internal_dispatcher_event_family>;
|
||||
|
||||
@@ -37,36 +40,38 @@ class dispatcher final {
|
||||
|
||||
struct base_wrapper {
|
||||
virtual ~base_wrapper() = default;
|
||||
virtual void publish() = 0;
|
||||
virtual void publish(Args...) = 0;
|
||||
};
|
||||
|
||||
template<typename Event>
|
||||
struct signal_wrapper final: base_wrapper {
|
||||
using sink_type = typename sigh<void(const Event &)>::sink_type;
|
||||
using signal_type = sigh<void(const Event &, Args...)>;
|
||||
using sink_type = typename signal_type::sink_type;
|
||||
|
||||
void publish() override {
|
||||
const auto &curr = current++;
|
||||
current %= std::extent<decltype(events)>::value;
|
||||
std::for_each(events[curr].cbegin(), events[curr].cend(), [this](const auto &event) { signal.publish(event); });
|
||||
events[curr].clear();
|
||||
void publish(Args... args) override {
|
||||
for(const auto &event: events[current]) {
|
||||
signal.publish(event, args...);
|
||||
}
|
||||
|
||||
events[current].clear();
|
||||
current = (current + 1) % std::extent<decltype(events)>::value;
|
||||
}
|
||||
|
||||
inline sink_type sink() ENTT_NOEXCEPT {
|
||||
return signal.sink();
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void trigger(Args &&... args) {
|
||||
signal.publish({ std::forward<Args>(args)... });
|
||||
inline void trigger(const Event &event, Args... args) {
|
||||
signal.publish(event, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void enqueue(Args &&... args) {
|
||||
events[current].push_back({ std::forward<Args>(args)... });
|
||||
template<typename... Params>
|
||||
inline void enqueue(Params &&... params) {
|
||||
events[current].emplace_back(std::forward<Params>(params)...);
|
||||
}
|
||||
|
||||
private:
|
||||
sigh<void(const Event &)> signal{};
|
||||
signal_type signal{};
|
||||
std::vector<Event> events[2];
|
||||
int current{};
|
||||
};
|
||||
@@ -120,12 +125,12 @@ public:
|
||||
* The event is discarded after the execution.
|
||||
*
|
||||
* @tparam Event Type of event to trigger.
|
||||
* @tparam Args Types of arguments to use to construct the event.
|
||||
* @param args Arguments to use to construct the event.
|
||||
* @param event An instance of the given type of event.
|
||||
* @param args Arguments to forward along with the event.
|
||||
*/
|
||||
template<typename Event, typename... Args>
|
||||
inline void trigger(Args &&... args) {
|
||||
wrapper<Event>().trigger(std::forward<Args>(args)...);
|
||||
template<typename Event>
|
||||
inline void trigger(Event &&event, Args... args) {
|
||||
wrapper<std::decay_t<Event>>().trigger(std::forward<Event>(event), args...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,11 +140,11 @@ public:
|
||||
* The event is discarded after the execution.
|
||||
*
|
||||
* @tparam Event Type of event to trigger.
|
||||
* @param event An instance of the given type of event.
|
||||
* @param args Arguments to forward along with the event.
|
||||
*/
|
||||
template<typename Event>
|
||||
inline void trigger(Event &&event) {
|
||||
wrapper<std::decay_t<Event>>().trigger(std::forward<Event>(event));
|
||||
inline void trigger(Args... args) {
|
||||
wrapper<std::decay_t<Event>>().trigger(Event{}, args...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,12 +154,12 @@ public:
|
||||
* `update` member function to notify listeners when ready.
|
||||
*
|
||||
* @tparam Event Type of event to enqueue.
|
||||
* @tparam Args Types of arguments to use to construct the event.
|
||||
* @param args Arguments to use to construct the event.
|
||||
* @tparam Params Types of arguments to use to construct the event.
|
||||
* @param params Arguments to use to construct the event.
|
||||
*/
|
||||
template<typename Event, typename... Args>
|
||||
inline void enqueue(Args &&... args) {
|
||||
wrapper<Event>().enqueue(std::forward<Args>(args)...);
|
||||
template<typename Event, typename... Params>
|
||||
inline void enqueue(Params &&... params) {
|
||||
wrapper<Event>().enqueue(std::forward<Params>(params)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,10 +184,11 @@ public:
|
||||
* to reduce at a minimum the time spent in the bodies of the listeners.
|
||||
*
|
||||
* @tparam Event Type of events to send.
|
||||
* @param args Arguments to forward along with the event.
|
||||
*/
|
||||
template<typename Event>
|
||||
inline void update() {
|
||||
wrapper<Event>().publish();
|
||||
inline void update(Args... args) {
|
||||
wrapper<Event>().publish(args...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,13 +197,15 @@ public:
|
||||
* This method is blocking and it doesn't return until all the events are
|
||||
* delivered to the registered listeners. It's responsibility of the users
|
||||
* to reduce at a minimum the time spent in the bodies of the listeners.
|
||||
*
|
||||
* @param args Arguments to forward along with the event.
|
||||
*/
|
||||
inline void update() const {
|
||||
inline void update(Args... args) const {
|
||||
for(auto pos = wrappers.size(); pos; --pos) {
|
||||
auto &wrapper = wrappers[pos-1];
|
||||
|
||||
if(wrapper) {
|
||||
wrapper->publish();
|
||||
wrapper->publish(args...);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,27 +6,27 @@ struct an_event {};
|
||||
struct another_event {};
|
||||
|
||||
struct receiver {
|
||||
void receive(const an_event &) { ++cnt; }
|
||||
void receive(const an_event &, int value) { cnt += value; }
|
||||
void reset() { cnt = 0; }
|
||||
int cnt{0};
|
||||
};
|
||||
|
||||
TEST(Dispatcher, Functionalities) {
|
||||
entt::dispatcher dispatcher;
|
||||
entt::dispatcher<int> dispatcher;
|
||||
receiver receiver;
|
||||
|
||||
dispatcher.sink<an_event>().connect(&receiver);
|
||||
dispatcher.trigger<an_event>();
|
||||
dispatcher.trigger<an_event>(1);
|
||||
dispatcher.enqueue<an_event>();
|
||||
dispatcher.enqueue<another_event>();
|
||||
dispatcher.update<another_event>();
|
||||
dispatcher.update<another_event>(1);
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 1);
|
||||
|
||||
dispatcher.update<an_event>();
|
||||
dispatcher.trigger<an_event>();
|
||||
dispatcher.update<an_event>(2);
|
||||
dispatcher.trigger<an_event>(1);
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 3);
|
||||
ASSERT_EQ(receiver.cnt, 4);
|
||||
|
||||
receiver.reset();
|
||||
|
||||
@@ -34,10 +34,10 @@ TEST(Dispatcher, Functionalities) {
|
||||
const an_event &cevent = event;
|
||||
|
||||
dispatcher.sink<an_event>().disconnect(&receiver);
|
||||
dispatcher.trigger(an_event{});
|
||||
dispatcher.trigger(an_event{}, 1);
|
||||
dispatcher.enqueue(event);
|
||||
dispatcher.update();
|
||||
dispatcher.trigger(cevent);
|
||||
dispatcher.update(1);
|
||||
dispatcher.trigger(cevent, 1);
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user