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/core | |
| 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/core')
| -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);  };  } | 
