Class Emitter

Synopsis

#include <src/uvw/emitter.h>

template<typename T>
class Emitter

Description

Event emitter base class.

Almost everything in uvw is an event emitter.
This is the base class from which resources and loops inherit.

Inheritance

Decsendents: Resource

Structures

ConnectionConnection type for a given event type.

Methods

~Emitter
clear overloadDisconnects all the listeners for the given event type.
clear overloadDisconnects all the listeners.
empty overloadChecks if there are listeners registered for the specific event.
empty overloadChecks if there are listeners registered with the event emitter.
eraseDisconnects a listener from the event emitter.
onRegisters a long-lived listener with the event emitter.
onceRegisters a short-lived listener with the event emitter.
publish

Source

Lines 85-314 in src/uvw/emitter.h.

template<typename T>
class Emitter {
    struct BaseHandler {
        virtual ~BaseHandler() noexcept = default;
        virtual bool empty() const noexcept = 0;
        virtual void clear() noexcept = 0;
    };

    template<typename E>
    struct Handler final: BaseHandler {
        using Listener = std::function<void(E &, T &)>;
        using Element = std::pair<bool, Listener>;
        using ListenerList = std::list<Element>;
        using Connection = typename ListenerList::iterator;

        bool empty() const noexcept override {
            auto pred = [](auto &&element){ return element.first; };

            return std::all_of(onceL.cbegin(), onceL.cend(), pred) &&
                    std::all_of(onL.cbegin(), onL.cend(), pred);
        }

        void clear() noexcept override {
            if(publishing) {
                auto func = [](auto &&element){ element.first = true; };
                std::for_each(onceL.begin(), onceL.end(), func);
                std::for_each(onL.begin(), onL.end(), func);
            } else {
                onceL.clear();
                onL.clear();
            }
        }

        Connection once(Listener f) {
            return onceL.emplace(onceL.cend(), false, std::move(f));
        }

        Connection on(Listener f) {
            return onL.emplace(onL.cend(), false, std::move(f));
        }

        void erase(Connection conn) noexcept {
            conn->first = true;

            if(!publishing) {
                auto pred = [](auto &&element){ return element.first; };
                onceL.remove_if(pred);
                onL.remove_if(pred);
            }
        }

        void publish(E event, T &ref) {
            ListenerList currentL;
            onceL.swap(currentL);

            auto func = [&event, &ref](auto &&element) {
                return element.first ? void() : element.second(event, ref);
            };

            publishing = true;

            std::for_each(onL.rbegin(), onL.rend(), func);
            std::for_each(currentL.rbegin(), currentL.rend(), func);

            publishing = false;

            onL.remove_if([](auto &&element){ return element.first; });
        }

    private:
        bool publishing{false};
        ListenerList onceL{};
        ListenerList onL{};
    };

    static std::size_t next_type() noexcept {
        static std::size_t counter = 0;
        return counter++;
    }

    template<typename>
    static std::size_t event_type() noexcept {
        static std::size_t value = next_type();
        return value;
    }

    template<typename E>
    Handler<E> & handler() noexcept {
        std::size_t type = event_type<E>();

        if(!(type < handlers.size())) {
            handlers.resize(type+1);
        }

        if(!handlers[type]) {
           handlers[type] = std::make_unique<Handler<E>>();
        }

        return static_cast<Handler<E>&>(*handlers[type]);
    }

protected:
    template<typename E>
    void publish(E event) {
        handler<E>().publish(std::move(event), *static_cast<T*>(this));
    }

public:
    template<typename E>
    using Listener = typename Handler<E>::Listener;

    /**
     * @brief Connection type for a given event type.
     *
     * Given an event type `E`, `Connection<E>` is the type of the connection
     * object returned by the event emitter whenever a listener for the given
     * type is registered.
     */
    template<typename E>
    struct Connection: private Handler<E>::Connection {
        template<typename> friend class Emitter;

        Connection() = default;
        Connection(const Connection &) = default;
        Connection(Connection &&) = default;

        Connection(typename Handler<E>::Connection conn)
            : Handler<E>::Connection{std::move(conn)}
        {}

        Connection & operator=(const Connection &) = default;
        Connection & operator=(Connection &&) = default;
    };

    virtual ~Emitter() noexcept {
        static_assert(std::is_base_of_v<Emitter<T>, T>);
    }

    /**
     * @brief Registers a long-lived listener with the event emitter.
     *
     * This method can be used to register a listener that is meant to be
     * invoked more than once for the given event type.<br/>
     * The Connection object returned by the method can be freely discarded. It
     * can be used later to disconnect the listener, if needed.
     *
     * Listener is usually defined as a callable object assignable to a
     * `std::function<void(const E &, T &)`, where `E` is the type of the event
     * and `T` is the type of the resource.
     *
     * @param f A valid listener to be registered.
     * @return Connection object to be used later to disconnect the listener.
     */
    template<typename E>
    Connection<E> on(Listener<E> f) {
        return handler<E>().on(std::move(f));
    }

    /**
     * @brief Registers a short-lived listener with the event emitter.
     *
     * This method can be used to register a listener that is meant to be
     * invoked only once for the given event type.<br/>
     * The Connection object returned by the method can be freely discarded. It
     * can be used later to disconnect the listener, if needed.
     *
     * Listener is usually defined as a callable object assignable to a
     * `std::function<void(const E &, T &)`, where `E` is the type of the event
     * and `T` is the type of the resource.
     *
     * @param f A valid listener to be registered.
     * @return Connection object to be used later to disconnect the listener.
     */
    template<typename E>
    Connection<E> once(Listener<E> f) {
        return handler<E>().once(std::move(f));
    }

    /**
     * @brief Disconnects a listener from the event emitter.
     * @param conn A valid Connection object
     */
    template<typename E>
    void erase(Connection<E> conn) noexcept {
        handler<E>().erase(std::move(conn));
    }

    /**
     * @brief Disconnects all the listeners for the given event type.
     */
    template<typename E>
    void clear() noexcept {
        handler<E>().clear();
    }

    /**
     * @brief Disconnects all the listeners.
     */
    void clear() noexcept {
        std::for_each(handlers.begin(), handlers.end(),
                      [](auto &&hdlr){ if(hdlr) { hdlr->clear(); } });
    }

    /**
     * @brief Checks if there are listeners registered for the specific event.
     * @return True if there are no listeners registered for the specific event,
     * false otherwise.
     */
    template<typename E>
    bool empty() const noexcept {
        std::size_t type = event_type<E>();

        return (!(type < handlers.size()) ||
                !handlers[type] ||
                static_cast<Handler<E>&>(*handlers[type]).empty());
    }

    /**
     * @brief Checks if there are listeners registered with the event emitter.
     * @return True if there are no listeners registered with the event emitter,
     * false otherwise.
     */
    bool empty() const noexcept {
        return std::all_of(handlers.cbegin(), handlers.cend(),
                           [](auto &&hdlr){ return !hdlr || hdlr->empty(); });
    }

private:
    std::vector<std::unique_ptr<BaseHandler>> handlers{};
};





Add Discussion as Guest

Log in