mirror of
https://github.com/quizhizhe/LiteLoaderBDS-1.16.40.git
synced 2025-06-06 12:03:39 +00:00
278 lines
8.1 KiB
C++
278 lines
8.1 KiB
C++
#ifndef ENTT_SIGNAL_DISPATCHER_HPP
|
|
#define ENTT_SIGNAL_DISPATCHER_HPP
|
|
|
|
|
|
#include <cstddef>
|
|
#include <memory>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
#include <vector>
|
|
#include "../config/config.h"
|
|
#include "../core/fwd.hpp"
|
|
#include "../core/type_info.hpp"
|
|
#include "sigh.hpp"
|
|
|
|
|
|
namespace entt {
|
|
|
|
|
|
/**
|
|
* @brief Basic dispatcher implementation.
|
|
*
|
|
* A dispatcher can be used either to trigger an immediate event or to enqueue
|
|
* 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 `Event &`, no matter what the return type is.
|
|
*
|
|
* The dispatcher creates instances of the `sigh` class internally. Refer to the
|
|
* documentation of the latter for more details.
|
|
*/
|
|
class dispatcher {
|
|
struct basic_pool {
|
|
virtual ~basic_pool() = default;
|
|
virtual void publish() = 0;
|
|
virtual void disconnect(void *) = 0;
|
|
virtual void clear() ENTT_NOEXCEPT = 0;
|
|
};
|
|
|
|
template<typename Event>
|
|
struct pool_handler final: basic_pool {
|
|
static_assert(std::is_same_v<Event, std::decay_t<Event>>, "Invalid event type");
|
|
|
|
using signal_type = sigh<void(Event &)>;
|
|
using sink_type = typename signal_type::sink_type;
|
|
|
|
void publish() override {
|
|
const auto length = events.size();
|
|
|
|
for(std::size_t pos{}; pos < length; ++pos) {
|
|
signal.publish(events[pos]);
|
|
}
|
|
|
|
events.erase(events.cbegin(), events.cbegin()+length);
|
|
}
|
|
|
|
void disconnect(void *instance) override {
|
|
sink().disconnect(instance);
|
|
}
|
|
|
|
void clear() ENTT_NOEXCEPT override {
|
|
events.clear();
|
|
}
|
|
|
|
[[nodiscard]] sink_type sink() ENTT_NOEXCEPT {
|
|
return entt::sink{signal};
|
|
}
|
|
|
|
template<typename... Args>
|
|
void trigger(Args &&... args) {
|
|
Event instance{std::forward<Args>(args)...};
|
|
signal.publish(instance);
|
|
}
|
|
|
|
template<typename... Args>
|
|
void enqueue(Args &&... args) {
|
|
if constexpr(std::is_aggregate_v<Event>) {
|
|
events.push_back(Event{std::forward<Args>(args)...});
|
|
} else {
|
|
events.emplace_back(std::forward<Args>(args)...);
|
|
}
|
|
}
|
|
|
|
private:
|
|
signal_type signal{};
|
|
std::vector<Event> events;
|
|
};
|
|
|
|
template<typename Event>
|
|
[[nodiscard]] pool_handler<Event> & assure() {
|
|
const auto index = type_seq<Event>::value();
|
|
|
|
if(!(index < pools.size())) {
|
|
pools.resize(std::size_t(index)+1u);
|
|
}
|
|
|
|
if(!pools[index]) {
|
|
pools[index].reset(new pool_handler<Event>{});
|
|
}
|
|
|
|
return static_cast<pool_handler<Event> &>(*pools[index]);
|
|
}
|
|
|
|
public:
|
|
/*! @brief Default constructor. */
|
|
dispatcher() = default;
|
|
|
|
/*! @brief Default move constructor. */
|
|
dispatcher(dispatcher &&) = default;
|
|
|
|
/*! @brief Default move assignment operator. @return This dispatcher. */
|
|
dispatcher & operator=(dispatcher &&) = default;
|
|
|
|
/**
|
|
* @brief Returns a sink object for the given event.
|
|
*
|
|
* A sink is an opaque object used to connect listeners to events.
|
|
*
|
|
* The function type for a listener is _compatible_ with:
|
|
* @code{.cpp}
|
|
* void(Event &);
|
|
* @endcode
|
|
*
|
|
* The order of invocation of the listeners isn't guaranteed.
|
|
*
|
|
* @sa sink
|
|
*
|
|
* @tparam Event Type of event of which to get the sink.
|
|
* @return A temporary sink object.
|
|
*/
|
|
template<typename Event>
|
|
[[nodiscard]] auto sink() {
|
|
return assure<Event>().sink();
|
|
}
|
|
|
|
/**
|
|
* @brief Triggers an immediate event of the given type.
|
|
*
|
|
* All the listeners registered for the given type are immediately notified.
|
|
* 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.
|
|
*/
|
|
template<typename Event, typename... Args>
|
|
void trigger(Args &&... args) {
|
|
assure<Event>().trigger(std::forward<Args>(args)...);
|
|
}
|
|
|
|
/**
|
|
* @brief Triggers an immediate event of the given type.
|
|
*
|
|
* All the listeners registered for the given type are immediately notified.
|
|
* The event is discarded after the execution.
|
|
*
|
|
* @tparam Event Type of event to trigger.
|
|
* @param event An instance of the given type of event.
|
|
*/
|
|
template<typename Event>
|
|
void trigger(Event &&event) {
|
|
assure<std::decay_t<Event>>().trigger(std::forward<Event>(event));
|
|
}
|
|
|
|
/**
|
|
* @brief Enqueues an event of the given type.
|
|
*
|
|
* An event of the given type is queued. No listener is invoked. Use the
|
|
* `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.
|
|
*/
|
|
template<typename Event, typename... Args>
|
|
void enqueue(Args &&... args) {
|
|
assure<Event>().enqueue(std::forward<Args>(args)...);
|
|
}
|
|
|
|
/**
|
|
* @brief Enqueues an event of the given type.
|
|
*
|
|
* An event of the given type is queued. No listener is invoked. Use the
|
|
* `update` member function to notify listeners when ready.
|
|
*
|
|
* @tparam Event Type of event to enqueue.
|
|
* @param event An instance of the given type of event.
|
|
*/
|
|
template<typename Event>
|
|
void enqueue(Event &&event) {
|
|
assure<std::decay_t<Event>>().enqueue(std::forward<Event>(event));
|
|
}
|
|
|
|
/**
|
|
* @brief Utility function to disconnect everything related to a given value
|
|
* or instance from a dispatcher.
|
|
* @tparam Type Type of class or type of payload.
|
|
* @param value_or_instance A valid object that fits the purpose.
|
|
*/
|
|
template<typename Type>
|
|
void disconnect(Type &value_or_instance) {
|
|
disconnect(&value_or_instance);
|
|
}
|
|
|
|
/**
|
|
* @brief Utility function to disconnect everything related to a given value
|
|
* or instance from a dispatcher.
|
|
* @tparam Type Type of class or type of payload.
|
|
* @param value_or_instance A valid object that fits the purpose.
|
|
*/
|
|
template<typename Type>
|
|
void disconnect(Type *value_or_instance) {
|
|
for(auto &&cpool: pools) {
|
|
if(cpool) {
|
|
cpool->disconnect(value_or_instance);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @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 clear() {
|
|
if constexpr(sizeof...(Event) == 0) {
|
|
for(auto &&cpool: pools) {
|
|
if(cpool) {
|
|
cpool->clear();
|
|
}
|
|
}
|
|
} else {
|
|
(assure<Event>().clear(), ...);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Delivers all the pending events of the given type.
|
|
*
|
|
* 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.
|
|
*
|
|
* @tparam Event Type of events to send.
|
|
*/
|
|
template<typename Event>
|
|
void update() {
|
|
assure<Event>().publish();
|
|
}
|
|
|
|
/**
|
|
* @brief Delivers all the pending events.
|
|
*
|
|
* 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.
|
|
*/
|
|
void update() const {
|
|
for(auto pos = pools.size(); pos; --pos) {
|
|
if(auto &&cpool = pools[pos-1]; cpool) {
|
|
cpool->publish();
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::vector<std::unique_ptr<basic_pool>> pools;
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|