diff options
author | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2015-01-02 16:00:01 +0100 |
---|---|---|
committer | Andreas Stöckel <andreas@somweyr.de> | 2015-01-02 16:00:01 +0100 |
commit | 128ac91adfdab4a21836c4f19d7024dba9790f9e (patch) | |
tree | 20ae14f5c9e2cbd1e2ae6ce37f4fb575c5ea237a /src | |
parent | dd3fccac307527d3b1285f6ac7966b6d527627cb (diff) |
Moved event system from the Node class to the Managed class (with zero overhead if is not used)
Diffstat (limited to 'src')
-rw-r--r-- | src/core/Node.cpp | 48 | ||||
-rw-r--r-- | src/core/Node.hpp | 228 | ||||
-rw-r--r-- | src/core/managed/Managed.cpp | 16 | ||||
-rw-r--r-- | src/core/managed/Managed.hpp | 34 | ||||
-rw-r--r-- | src/core/managed/Manager.cpp | 64 | ||||
-rw-r--r-- | src/core/managed/Manager.hpp | 50 |
6 files changed, 165 insertions, 275 deletions
diff --git a/src/core/Node.cpp b/src/core/Node.cpp index 665430c..fa6a3a2 100644 --- a/src/core/Node.cpp +++ b/src/core/Node.cpp @@ -25,8 +25,10 @@ namespace ousia { void Node::setName(std::string name) { // Call the name change event - NameChangeEvent ev{this->name, name}; - triggerEvent(ev); + { + NameChangeEvent ev{this->name, name}; + triggerEvent(ev); + } // Set the new name this->name = std::move(name); @@ -97,48 +99,6 @@ std::vector<Rooted<Managed>> Node::resolve(const std::vector<std::string> &path, return res; } -int Node::registerEventHandler(EventType type, EventHandler handler, - Handle<Managed> owner, - bool includeChildren) -{ - const int id = handlerIdCounter++; - handlers.insert(std::make_pair( - type, - EventHandlerDescriptor{id, handler, owner, this, includeChildren})); - return id; -} - -bool Node::unregisterEventHandler(int id) { - for (auto it = handlers.begin(); it != handlers.end(); it++) { - if (it->second.id == id) { - handlers.erase(it); - return true; - } - } - return false; -} - -bool Node::triggerEvent(Event &event, bool fromChild) { - bool res = false; - // Iterate over all event handlers - const auto range = handlers.equal_range(event.type); - for (auto it = range.first; it != range.second; it++) { - // Fetch a reference to the descriptor, check whether it should be - // called for bubbled events - EventHandlerDescriptor descr = it->second; - if (!fromChild || descr.includeChildren) { - descr.handler(event, descr.owner); - res = true; - } - } - - // If possible, let the event bubble up to the parent node - if (event.canBubble() && !parent.isNull()) { - res = parent->triggerEvent(event, true) | res; - } - return res; -} - /* RTTI type registrations */ const Rtti<Node> RttiTypes::Node{"Node"}; diff --git a/src/core/Node.hpp b/src/core/Node.hpp index 50f9a96..cca33f7 100644 --- a/src/core/Node.hpp +++ b/src/core/Node.hpp @@ -31,189 +31,6 @@ namespace ousia { -/* Forward declarations */ -class Node; -class Event; - -/** - * EventType is an enum containing all possible node events. New event types - * should be added here. - */ -enum class EventType : int { - /** - * Generic update event which may be triggered if some important property - * of the node is changed. - */ - UPDATE, - - /** - * The NAME_CHANGE event is used to inform listeners that the name of the - * node has changed. - */ - NAME_CHANGE, - - /** - * The ADD_CHILD event is used to inform listeners that the node got a new - * child in any of its child node lists. - */ - ADD_CHILD, - - /** - * The DELETE_CHILD event is used to inform listeners that the node got a - * new child in any of its child node lists. - */ - DELETE_CHILD -}; - -/** - * Definition of the EventHandler function. - * - * @param event is a reference to the object holding the event data. - * @param owner is a reference to the managed object that was given in the - * registerEventHandler function. - */ -using EventHandler = void (*)(const Event &event, Handle<Managed> owner); - -/** - * The Event class and its child classes are responsible for containing the - * actual event data which further describes the event to the event handlers. - * Instances of this class and its children must be declared on the stack or as - * a temporary. - */ -class Event { -private: - /** - * True as long as the event can bubble up the node hirarchy. - */ - mutable bool bubble; - -public: - /** - * Contains the actual event type of this class. - */ - const EventType type; - - /** - * Node on which the event was triggered. - */ - Rooted<Node> sender; - - /** - * Constructor of the Event class. - * - * @param type is an element from the EventType enum. - * @param bubble if set to true, the event can bubble up the node hirarchy. - */ - Event(EventType type, bool bubble = true) : bubble(bubble), type(type){}; - - /** - * Delete the copy constructor. - */ - Event(const Event &) = delete; - - /** - * Delete the assignment operator. - */ - Event &operator=(const Event &) = delete; - - /** - * Stops the propagation of this event to the parent element. - */ - void stopPropagation() const { bubble = false; } - - /** - * Returns true if the event can still bubble. - */ - bool canBubble() const { return bubble; } -}; - -/** - * Event used when the name of a node has changed. - */ -class NameChangeEvent : public Event { -public: - /** - * Reference to a string containing the old name of the node. - */ - const std::string &oldName; - - /** - * Reference to a string containing the new name of the node. - */ - const std::string &newName; - - /** - * Constructor of the NameChangeEvent class. - * - * @param oldName is a reference to a string containing the old name of the - * node. - * @param newName is a reference to a string containing the new name of the - * node. - * @param bubble if set to true, the event can bubble up the node hirarchy. - */ - NameChangeEvent(const std::string &oldName, const std::string &newName, - bool bubble = true) - : Event(EventType::NAME_CHANGE, bubble), - oldName(oldName), - newName(newName) - { - } -}; - -/** - * Struct containing the data which describes a single registered event handler. - * Note that the event type (e.g. which type of event this element was - * registered for) is stored outside the EventHandlerDescriptor (in the map - * storing the registered event handlers). - */ -struct EventHandlerDescriptor { - /** - * Unique id of the event handler. - */ - const int id; - - /** - * Reference to the event handler containing the events. - */ - const EventHandler handler; - - /** - * Reference to the managed element which owns the event handler. The object - * which owns the Owned handler is given in the constructor. - */ - const Owned<Managed> owner; - - /** - * Set to true, if this event handler listens to bubbled events comming from - * child nodes. - */ - const bool includeChildren; - - /** - * Constructor of the EventHandlerDescriptor struct. - * - * @param id is the node-unique id of the EventHandlerDescriptor. - * @param handler is the function pointer which is going to be called once - * the associated event handler has fired. - * @param owner is a user-specified object which owns the method that is - * going to be called. This can be used to make sure that the method which - * handles the events has access to its owned object as long as the event - * handler lives. - * @param parent is the parent element this descriptor belongs to. The - * a handle to the "owner" object will be created on behalf of the parent. - * @param includeChildren is set to true if the event handler should handle - * events comming from child elements. - */ - EventHandlerDescriptor(int id, EventHandler handler, Handle<Managed> owner, - Managed *parent, bool includeChildren) - : id(id), - handler(handler), - owner(owner, parent), - includeChildren(includeChildren) - { - } -}; - /** * The Node class builds the base class for any Node within the DOM graph. A * node may either be a descriptive node (such as a domain description etc.) @@ -270,17 +87,6 @@ private: Owned<Node> parent; /** - * Current id counter. The id counter may be used to create ids which are - * unique inside the realm of this manager instance. - */ - int handlerIdCounter = 0; - - /** - * Multimap containing all registered event handlers for this node. - */ - std::multimap<EventType, EventHandlerDescriptor> handlers; - - /** * Private version of the "path" function used to construct the path. Calls * the path function of the parent node and adds the own name to the given * vector. @@ -482,40 +288,6 @@ public: { return resolve(std::vector<std::string>{name}, nullptr, nullptr); } - - /** - * Registers a new event handler for listening to the given event type. - * - * @param type is the event type the handler should listen to. - * @param handler is the handler that should be called. - * @param owner is an object the handler belongs to. May be nullptr. - * @param includeChildren if set to true, the event handler is also called - * if the same event is triggered on one of the child nodes. - * @return a unique event handler. - */ - int registerEventHandler(EventType type, EventHandler handler, - Handle<Managed> owner = nullptr, - bool includeChildren = false); - - /** - * Unregisters the given event handler from the node. Note that removing an - * event handler has linear time. - * - * @param id is the unique event handler id. - * @return true if the given event handler was successfully unregistered. - */ - bool unregisterEventHandler(int id); - - /** - * Triggers an event on this node. - * - * @param event is a pointer at the event that should be triggered. The - * calling function has ownership over the given event. - * @param fromChild is set to true if the triggerEvent function is called - * from a child node. - * @return true if any event handler was found. - */ - bool triggerEvent(Event &event, bool fromChild = false); }; // TODO: Use a different listener here for updating name maps diff --git a/src/core/managed/Managed.cpp b/src/core/managed/Managed.cpp index dc3731f..d9db0e0 100644 --- a/src/core/managed/Managed.cpp +++ b/src/core/managed/Managed.cpp @@ -54,6 +54,22 @@ bool Managed::deleteData(const std::string &key) { return mgr.deleteData(this, key); } +EventId Managed::registerEvent(EventType type, EventHandler handler, + Handle<Managed> owner) +{ + return mgr.registerEvent(this, type, handler, owner.get()); +} + +bool Managed::unregisterEvent(EventId id) +{ + return mgr.unregisterEvent(this, id); +} + +bool Managed::triggerEvent(Event &data) +{ + return mgr.triggerEvent(this, data); +} + const RttiBase &Managed::type() const { return typeOf(*this); diff --git a/src/core/managed/Managed.hpp b/src/core/managed/Managed.hpp index 5daa667..4a38dbd 100644 --- a/src/core/managed/Managed.hpp +++ b/src/core/managed/Managed.hpp @@ -135,6 +135,40 @@ public: bool deleteData(const std::string &key); + /* Event handling methods */ + + /** + * Registers an event handler for an event of the given type. + * + * @param type is the event type that should be registered. + * @param handler is the callback function. + * @param owner is a managed object that owns the event handler. A reference + * from the the reference object to the owner is added. The argument may be + * nullptr in which case no reference is added. The owner is passed to the + * event handler as second parameter. + * @return a numeric event id, which is unique for the given reference + * object. The event id must be used when unregistering event handlers. + */ + EventId registerEvent(EventType type, EventHandler handler, + Handle<Managed> owner); + + /** + * Unregisters the event with the given event id. + * + * @param id is the event that should be unregistered as returned by the + * registerEvent function. + * @return true if the operation was successful, false if either the + * reference object or the event id do not exist. + */ + bool unregisterEvent(EventId id); + + /** + * Triggers the event of the given type for the reference object. + * + * @param data is the event data that should be passed to the handlers. + */ + bool triggerEvent(Event &data); + /* RTTI methods */ /** diff --git a/src/core/managed/Manager.cpp b/src/core/managed/Manager.cpp index fbf1bd3..94eb1b1 100644 --- a/src/core/managed/Manager.cpp +++ b/src/core/managed/Manager.cpp @@ -256,8 +256,9 @@ void Manager::deleteObject(Managed *o, ObjectDescriptor *descr) deleteRef(descr->refOut.begin()->first, o, true); } - // Remove the data store entry + // Remove the data store and the event store entry store.erase(o); + events.erase(o); // Remove the Managed from the "marked" set marked.erase(o); @@ -442,5 +443,66 @@ bool Manager::deleteData(Managed *ref, const std::string &key) } return false; } + +/* Class Manager: Event handling */ + +EventId Manager::registerEvent(Managed *ref, EventType type, + EventHandler handler, Managed *owner) +{ + // Add a reference from the reference object to the owner object + if (owner) { + addRef(owner, ref); + } + + // Create a event handler descriptor and store it along with the + auto &vec = events.emplace(ref, std::vector<EventHandlerDescriptor>{}) + .first->second; + const EventHandlerDescriptor descr(type, handler, owner); + for (size_t i = 0; i < vec.size(); i++) { + if (!vec[i].handler) { + vec[i] = descr; + return i; + } + } + vec.push_back(descr); + return vec.size() - 1; +} + +bool Manager::unregisterEvent(Managed *ref, EventId id) +{ + auto eventsIt = events.find(ref); + if (eventsIt != events.end()) { + auto &vec = eventsIt->second; + if (id < vec.size() && vec[id].handler) { + // Delete the reference from the reference object to the handler + EventHandlerDescriptor &descr = vec[id]; + if (descr.owner) { + deleteRef(descr.owner, ref); + } + + // Remove the handler from the list by resetting handler and owner + // to nullptr + descr.handler = nullptr; + descr.owner = nullptr; + return true; + } + } + return false; +} + +bool Manager::triggerEvent(Managed *ref, Event &data) +{ + bool hasHandler = false; + auto eventsIt = events.find(ref); + if (eventsIt != events.end()) { + for (EventHandlerDescriptor &descr : eventsIt->second) { + if (descr.type == data.type && descr.handler) { + descr.handler(data, descr.owner); + hasHandler = true; + } + } + } + return hasHandler; +} } diff --git a/src/core/managed/Manager.hpp b/src/core/managed/Manager.hpp index 303e591..0e9d519 100644 --- a/src/core/managed/Manager.hpp +++ b/src/core/managed/Manager.hpp @@ -35,6 +35,8 @@ #include <vector> #include <queue> +#include "Events.hpp" + namespace ousia { // Forward declaration @@ -166,9 +168,9 @@ private: std::unordered_map<Managed *, std::map<std::string, Managed *>> store; /** - * Map for storing the tagged memory regions. + * Map storing any attached events. */ - std::map<uintptr_t, std::pair<uintptr_t, void *>> tags; + std::unordered_map<Managed *, std::vector<EventHandlerDescriptor>> events; /** * Recursion depth while performing deletion. This variable is needed @@ -225,6 +227,8 @@ public: */ ~Manager(); + /* Reference management and garbage collection */ + /** * Registers an object for being managed by the Manager. The Manager now has * the sole responsibility for freeing the managed object. Under no @@ -266,6 +270,8 @@ public: */ void sweep(); + /* Data storage */ + /** * Registers some arbitrary data (in form of a Managed object) for the * given reference Managed object under a certain (string) key. Overrides @@ -304,6 +310,46 @@ public: * @return true if data for this key was deleted, false otherwise. */ bool deleteData(Managed *ref, const std::string &key); + + /* Events */ + + /** + * Registers an event handler for an event of the given type for the object + * referenced by ref. + * + * @param ref is the reference object for which the event should be + * registered. + * @param type is the event type that should be registered. + * @param handler is the callback function. + * @param owner is a managed object that owns the event handler. A reference + * from the the reference object to the owner is added. The argument may be + * nullptr in which case no reference is added. The owner is passed to the + * event handler as second parameter. + * @return a numeric event id, which is unique for the given reference + * object. The event id must be used when unregistering event handlers. + */ + EventId registerEvent(Managed *ref, EventType type, EventHandler handler, + Managed *owner); + + /** + * Unregisters the event with the given event id from the given reference + * object. + * + * @param ref is the reference object from which the event should be + * removed. + * @param id is the event that should be unregistered. + * @return true if the operation was successful, false if either the + * reference object or the event id do not exist. + */ + bool unregisterEvent(Managed *ref, EventId id); + + /** + * Triggers the event of the given type for the reference object. + * + * @param ref is the object for which the given event should be triggered. + * @param data is the event data that should be passed to the handlers. + */ + bool triggerEvent(Managed *ref, Event &data); }; } |