summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-01-02 16:00:01 +0100
committerAndreas Stöckel <andreas@somweyr.de>2015-01-02 16:00:01 +0100
commit128ac91adfdab4a21836c4f19d7024dba9790f9e (patch)
tree20ae14f5c9e2cbd1e2ae6ce37f4fb575c5ea237a /src/core
parentdd3fccac307527d3b1285f6ac7966b6d527627cb (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.cpp48
-rw-r--r--src/core/Node.hpp228
-rw-r--r--src/core/managed/Managed.cpp16
-rw-r--r--src/core/managed/Managed.hpp34
-rw-r--r--src/core/managed/Manager.cpp64
-rw-r--r--src/core/managed/Manager.hpp50
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);
};
}