Class basic_dispatcher

Synopsis

#include <src/entt/signal/dispatcher.hpp>

template<typename Allocator>
class basic_dispatcher

Description

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.
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.

Template Parameters

Allocator - Type of allocator used to manage memory and elements.

Methods

basic_dispatcher overloadDefault constructor.
basic_dispatcher overloadConstructs a dispatcher with a given allocator.
basic_dispatcher overloadMove constructor.
basic_dispatcher overloadAllocator-extended move constructor.
clear overloadDiscards all the events stored so far in a given queue.
clear overloadDiscards all the events queued so far.
disconnect overloadUtility function to disconnect everything related to a given value or instance from a dispatcher.
enqueue overloadEnqueues an event of the given type.
enqueue_hint overloadEnqueues an event of the given type.
get_allocatorReturns the associated allocator.
operator=Move assignment operator.
sinkReturns a sink object for the given event and queue.
size overloadReturns the number of pending events for a given type.
size overloadReturns the total number of pending events.
swapExchanges the contents with those of a given dispatcher.
trigger overloadTriggers an immediate event of a given type.
trigger overloadTriggers an immediate event on a queue of a given type.
update overloadDelivers all the pending events of a given queue.
update overloadDelivers all the pending events.

Source

Lines 117-386 in src/entt/signal/dispatcher.hpp.

template<typename Allocator>
class basic_dispatcher {
    template<typename Event>
    using handler_type = internal::dispatcher_handler<Event, Allocator>;

    using key_type = id_type;
    // std::shared_ptr because of its type erased allocator which is pretty useful here
    using mapped_type = std::shared_ptr<internal::basic_dispatcher_handler>;

    using alloc_traits = std::allocator_traits<Allocator>;
    using container_allocator = typename alloc_traits::template rebind_alloc<std::pair<const key_type, mapped_type>>;
    using container_type = dense_map<id_type, mapped_type, identity, std::equal_to<id_type>, container_allocator>;

    template<typename Event>
    [[nodiscard]] handler_type<Event> &assure(const id_type id) {
        auto &&ptr = pools.first()[id];

        if(!ptr) {
            const auto &allocator = pools.second();
            ptr = std::allocate_shared<handler_type<Event>>(allocator, allocator);
        }

        return static_cast<handler_type<Event> &>(*ptr);
    }

    template<typename Event>
    [[nodiscard]] const handler_type<Event> *assure(const id_type id) const {
        auto &container = pools.first();

        if(const auto it = container.find(id); it != container.end()) {
            return static_cast<const handler_type<Event> *>(it->second.get());
        }

        return nullptr;
    }

public:
    /*! @brief Allocator type. */
    using allocator_type = Allocator;
    /*! @brief Unsigned integer type. */
    using size_type = std::size_t;

    /*! @brief Default constructor. */
    basic_dispatcher()
        : basic_dispatcher{allocator_type{}} {}

    /**
     * @brief Constructs a dispatcher with a given allocator.
     * @param allocator The allocator to use.
     */
    explicit basic_dispatcher(const allocator_type &allocator)
        : pools{allocator, allocator} {}

    /**
     * @brief Move constructor.
     * @param other The instance to move from.
     */
    basic_dispatcher(basic_dispatcher &&other) ENTT_NOEXCEPT
        : pools{std::move(other.pools)} {}

    /**
     * @brief Allocator-extended move constructor.
     * @param other The instance to move from.
     * @param allocator The allocator to use.
     */
    basic_dispatcher(basic_dispatcher &&other, const allocator_type &allocator) ENTT_NOEXCEPT
        : pools{container_type{std::move(other.pools.first()), allocator}, allocator} {}

    /**
     * @brief Move assignment operator.
     * @param other The instance to move from.
     * @return This dispatcher.
     */
    basic_dispatcher &operator=(basic_dispatcher &&other) ENTT_NOEXCEPT {
        pools = std::move(other.pools);
        return *this;
    }

    /**
     * @brief Exchanges the contents with those of a given dispatcher.
     * @param other Dispatcher to exchange the content with.
     */
    void swap(basic_dispatcher &other) {
        using std::swap;
        swap(pools, other.pools);
    }

    /**
     * @brief Returns the associated allocator.
     * @return The associated allocator.
     */
    [[nodiscard]] constexpr allocator_type get_allocator() const ENTT_NOEXCEPT {
        return pools.second();
    }

    /**
     * @brief Returns the number of pending events for a given type.
     * @tparam Event Type of event for which to return the count.
     * @param id Name used to map the event queue within the dispatcher.
     * @return The number of pending events for the given type.
     */
    template<typename Event>
    size_type size(const id_type id = type_hash<Event>::value()) const ENTT_NOEXCEPT {
        const auto *cpool = assure<Event>(id);
        return cpool ? cpool->size() : 0u;
    }

    /**
     * @brief Returns the total number of pending events.
     * @return The total number of pending events.
     */
    size_type size() const ENTT_NOEXCEPT {
        size_type count{};

        for(auto &&cpool: pools.first()) {
            count += cpool.second->size();
        }

        return count;
    }

    /**
     * @brief Returns a sink object for the given event and queue.
     *
     * 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.
     * @param id Name used to map the event queue within the dispatcher.
     * @return A temporary sink object.
     */
    template<typename Event>
    [[nodiscard]] auto sink(const id_type id = type_hash<Event>::value()) {
        return assure<Event>(id).bucket();
    }

    /**
     * @brief Triggers an immediate event of a given type.
     * @tparam Event Type of event to trigger.
     * @param event An instance of the given type of event.
     */
    template<typename Event>
    void trigger(Event &&event = {}) {
        trigger(type_hash<std::decay_t<Event>>::value(), std::forward<Event>(event));
    }

    /**
     * @brief Triggers an immediate event on a queue of a given type.
     * @tparam Event Type of event to trigger.
     * @param event An instance of the given type of event.
     * @param id Name used to map the event queue within the dispatcher.
     */
    template<typename Event>
    void trigger(const id_type id, Event &&event = {}) {
        assure<std::decay_t<Event>>(id).trigger(std::forward<Event>(event));
    }

    /**
     * @brief Enqueues an event of the given type.
     * @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) {
        enqueue_hint<Event>(type_hash<Event>::value(), std::forward<Args>(args)...);
    }

    /**
     * @brief Enqueues an event of the given type.
     * @tparam Event Type of event to enqueue.
     * @param event An instance of the given type of event.
     */
    template<typename Event>
    void enqueue(Event &&event) {
        enqueue_hint(type_hash<std::decay_t<Event>>::value(), std::forward<Event>(event));
    }

    /**
     * @brief Enqueues an event of the given type.
     * @tparam Event Type of event to enqueue.
     * @tparam Args Types of arguments to use to construct the event.
     * @param id Name used to map the event queue within the dispatcher.
     * @param args Arguments to use to construct the event.
     */
    template<typename Event, typename... Args>
    void enqueue_hint(const id_type id, Args &&...args) {
        assure<Event>(id).enqueue(std::forward<Args>(args)...);
    }

    /**
     * @brief Enqueues an event of the given type.
     * @tparam Event Type of event to enqueue.
     * @param id Name used to map the event queue within the dispatcher.
     * @param event An instance of the given type of event.
     */
    template<typename Event>
    void enqueue_hint(const id_type id, Event &&event) {
        assure<std::decay_t<Event>>(id).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.first()) {
            cpool.second->disconnect(value_or_instance);
        }
    }

    /**
     * @brief Discards all the events stored so far in a given queue.
     * @tparam Event Type of event to discard.
     * @param id Name used to map the event queue within the dispatcher.
     */
    template<typename Event>
    void clear(const id_type id = type_hash<Event>::value()) {
        assure<Event>(id).clear();
    }

    /*! @brief Discards all the events queued so far. */
    void clear() ENTT_NOEXCEPT {
        for(auto &&cpool: pools.first()) {
            cpool.second->clear();
        }
    }

    /**
     * @brief Delivers all the pending events of a given queue.
     * @tparam Event Type of event to send.
     * @param id Name used to map the event queue within the dispatcher.
     */
    template<typename Event>
    void update(const id_type id = type_hash<Event>::value()) {
        assure<Event>(id).publish();
    }

    /*! @brief Delivers all the pending events. */
    void update() const {
        for(auto &&cpool: pools.first()) {
            cpool.second->publish();
        }
    }

private:
    compressed_pair<container_type, allocator_type> pools;
};





Add Discussion

Log in to comment