summaryrefslogtreecommitdiff
path: root/src/core/model
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-01-02 16:20:29 +0100
committerAndreas Stöckel <andreas@somweyr.de>2015-01-02 16:20:29 +0100
commit5fa382a69c069be1b609e3c5c7b21ef747ceedd2 (patch)
tree57ff1447548afc33aedb77d2022e096d4a643283 /src/core/model
parent128ac91adfdab4a21836c4f19d7024dba9790f9e (diff)
Moved Node class to model folder
Diffstat (limited to 'src/core/model')
-rw-r--r--src/core/model/Document.hpp2
-rw-r--r--src/core/model/Domain.hpp2
-rw-r--r--src/core/model/Node.cpp106
-rw-r--r--src/core/model/Node.hpp326
-rw-r--r--src/core/model/Typesystem.hpp3
5 files changed, 436 insertions, 3 deletions
diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp
index 7d24161..2d792c5 100644
--- a/src/core/model/Document.hpp
+++ b/src/core/model/Document.hpp
@@ -69,9 +69,9 @@
#define _OUSIA_MODEL_DOCUMENT_HPP_
#include <core/managed/ManagedContainer.hpp>
-#include <core/Node.hpp>
#include <core/common/Variant.hpp>
+#include "Node.hpp"
#include "Domain.hpp"
#include "Typesystem.hpp"
diff --git a/src/core/model/Domain.hpp b/src/core/model/Domain.hpp
index 31786c1..1ebe5c6 100644
--- a/src/core/model/Domain.hpp
+++ b/src/core/model/Domain.hpp
@@ -83,9 +83,9 @@
#define _OUSIA_MODEL_DOMAIN_HPP_
#include <core/managed/ManagedContainer.hpp>
-#include <core/Node.hpp>
#include <core/RangeSet.hpp>
+#include "Node.hpp"
#include "Typesystem.hpp"
namespace ousia {
diff --git a/src/core/model/Node.cpp b/src/core/model/Node.cpp
new file mode 100644
index 0000000..fa6a3a2
--- /dev/null
+++ b/src/core/model/Node.cpp
@@ -0,0 +1,106 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "Node.hpp"
+
+namespace ousia {
+
+/* Class Node */
+
+void Node::setName(std::string name)
+{
+ // Call the name change event
+ {
+ NameChangeEvent ev{this->name, name};
+ triggerEvent(ev);
+ }
+
+ // Set the new name
+ this->name = std::move(name);
+}
+
+void Node::path(std::vector<std::string> &p) const
+{
+ if (!isRoot()) {
+ parent->path(p);
+ }
+ p.push_back(name);
+}
+
+std::vector<std::string> Node::path() const
+{
+ std::vector<std::string> res;
+ path(res);
+ return res;
+}
+
+void Node::doResolve(std::vector<Rooted<Managed>> &res,
+ const std::vector<std::string> &path, Filter filter,
+ void *filterData, unsigned idx, VisitorSet &visited)
+{
+ // Do nothing in the default implementation
+}
+
+int Node::resolve(std::vector<Rooted<Managed>> &res,
+ const std::vector<std::string> &path, Filter filter,
+ void *filterData, unsigned idx, VisitorSet &visited,
+ const std::string *alias)
+{
+ // Abort if this node was already visited for this path index
+ std::pair<const Node *, int> recKey = std::make_pair(this, idx);
+ if (visited.find(recKey) != visited.end()) {
+ return res.size();
+ }
+ visited.insert(recKey);
+
+ // Check whether the we can continue the path
+ if (path[idx] == name || (alias && *alias == name)) {
+ // If we have reached the end of the path and the node is successfully
+ // tested by the filter function, add it to the result. Otherwise
+ // continue searching along the path
+ if (idx + 1 == path.size()) {
+ if (!filter || filter(this, filterData)) {
+ res.push_back(this);
+ }
+ } else {
+ doResolve(res, path, filter, filterData, idx + 1, visited);
+ }
+ }
+
+ // Restart the search from here in order to find all possible nodes that can
+ // be matched to the given path
+ doResolve(res, path, filter, filterData, 0, visited);
+
+ return res.size();
+}
+
+std::vector<Rooted<Managed>> Node::resolve(const std::vector<std::string> &path,
+ Filter filter = nullptr,
+ void *filterData = nullptr)
+{
+ std::vector<Rooted<Managed>> res;
+ VisitorSet visited;
+ resolve(res, path, filter, filterData, 0, visited, nullptr);
+ return res;
+}
+
+/* RTTI type registrations */
+
+const Rtti<Node> RttiTypes::Node{"Node"};
+
+}
diff --git a/src/core/model/Node.hpp b/src/core/model/Node.hpp
new file mode 100644
index 0000000..cca33f7
--- /dev/null
+++ b/src/core/model/Node.hpp
@@ -0,0 +1,326 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _OUSIA_NODE_HPP_
+#define _OUSIA_NODE_HPP_
+
+#include <functional>
+#include <map>
+#include <string>
+#include <vector>
+#include <unordered_set>
+
+#include <core/common/Rtti.hpp>
+#include <core/managed/Managed.hpp>
+#include <core/managed/ManagedContainer.hpp>
+
+namespace ousia {
+
+/**
+ * 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.)
+ * or a document element. Each node is identified by acharacteristic name and
+ * a parent element. Note that the node name is not required to be unique. Nodes
+ * without parent are considered root nodes.
+ */
+class Node : public Managed {
+public:
+ /**
+ * The Filter function is used when resolving names to Node instances. The
+ * filter tests whether the given node meets the requirements for inclusion
+ * in the result list.
+ *
+ * @param managed is the managed which should be tested.
+ * @param data is user-defined data passed to the filter.
+ * @return true if the node should be included in the result set, false
+ * otherwise.
+ */
+ using Filter = bool (*)(Handle<Managed> managed, void *data);
+
+ /**
+ * Hash functional used to convert pairs of nodes and int to hashes which
+ * can be used within a unordered_set.
+ */
+ struct VisitorHash {
+ size_t operator()(const std::pair<const Node *, int> &p) const
+ {
+ const std::hash<const Node *> nodeHash;
+ const std::hash<int> intHash;
+ return nodeHash(p.first) + 37 * intHash(p.second);
+ }
+ };
+
+ /**
+ * Alias for the VisitorSet class which represents all nodes which have been
+ * visited in the name resolution process. The map stores pairs of node
+ * pointers and integers, indicating for which path start id the node has
+ * already been visited.
+ */
+ using VisitorSet =
+ std::unordered_set<std::pair<const Node *, int>, VisitorHash>;
+
+private:
+ /**
+ * Name of the node. As names are always looked up relative to a node,
+ * names are not required to be unique.
+ */
+ std::string name;
+
+ /**
+ * Reference to a parent node instace.
+ */
+ Owned<Node> parent;
+
+ /**
+ * 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.
+ *
+ * @param p is the list the path should be constructed in.
+ */
+ void path(std::vector<std::string> &p) const;
+
+protected:
+ /**
+ * Function which should be overwritten by derived classes in order to
+ * resolve node names to a list of possible nodes. The implementations of
+ * this function do not need to do anything but call the "resovle" function
+ * of any child instance of NamedNode.
+ *
+ * @param res is the result list containing all possible nodes matching the
+ * name specified in the path.
+ * @param path is a list specifying a path of node names which is meant to
+ * specify a certain named node.
+ * @param idx is the current index in the path.
+ * @param visited is a map which is used to prevent unwanted recursion.
+ * @param filter is a callback function which may check whether a certain
+ * node should be in the result set. If nullptr is given, all nodes matching
+ * the path are included. The filter function can be used to restrict the
+ * type of matched functions.
+ * @param filterData is user-defined data that should be passed to the
+ * filter.
+ */
+ virtual void doResolve(std::vector<Rooted<Managed>> &res,
+ const std::vector<std::string> &path, Filter filter,
+ void *filterData, unsigned idx, VisitorSet &visited);
+
+public:
+ /**
+ * Initializes the node with empty name and parent.
+ *
+ * @param mgr is a reference to the Manager instace the node belongs to.
+ */
+ Node(Manager &mgr, Handle<Node> parent = nullptr)
+ : Managed(mgr), parent(acquire(parent))
+ {
+ }
+
+ /**
+ * Constructs a new node with the given name and the given parent element.
+ *
+ * @param mgr is a reference to the Manager instace the node belongs to.
+ * @param name is the name of the Node.
+ * @param parent is a handle pointing at the parent node.
+ */
+ Node(Manager &mgr, std::string name, Handle<Node> parent = nullptr)
+ : Managed(mgr), name(name), parent(acquire(parent))
+ {
+ }
+
+ /**
+ * Sets the name of the node to the given name. Note: The name set here may
+ * be invalid (contain spaces, colons or other special characters). However,
+ * in this case the node will not be reachable as reference from a input
+ * document. This behaviour allows for gracefully degradation in error
+ * cases.
+ *
+ * @param name is the name that should be assigned to the node.
+ */
+ void setName(std::string name);
+
+ /**
+ * Returns the name of the node.
+ */
+ std::string getName() const { return name; }
+
+ /**
+ * Returns a reference to the name of the node.
+ */
+ const std::string &getNameRef() const { return name; }
+
+ /**
+ * Specifies whether the node has a name, e.g. whether the current name is
+ * not empty.
+ *
+ * @return true if the name of this node is not empty, false otherwise.
+ */
+ bool hasName() const { return !name.empty(); }
+
+ /**
+ * Sets the parent node.
+ *
+ * @param parent is a Handle to the parent node.
+ */
+ void setParent(Handle<Node> parent) { this->parent = acquire(parent); }
+
+ /**
+ * Returns a handle to the parent node of the Node instance.
+ *
+ * @return a handle to the root node.
+ */
+ Rooted<Managed> getParent() const { return parent; }
+
+ /**
+ * Returns true, if the node does not have a parent. Root nodes may either
+ * be the root element of the complete DOM tree
+ *
+ * @return true if the node is a root node (has no parent) or false if the
+ * node is no root node (has a parent).
+ */
+ bool isRoot() const { return parent.isNull(); }
+
+ /**
+ * Returns the vector containing the complete path to this node (including
+ * the name of the parent nodes).
+ *
+ * @return a vector containing the path (starting with the root node) to
+ * this node as a list of names.
+ */
+ std::vector<std::string> path() const;
+
+ /**
+ * Function which resolves a name path to a list of possible nodes.
+ *
+ * @param res is the result list containing all possible nodes matching the
+ * name specified in the path.
+ * @param path is a list specifying a path of node names which is meant to
+ * specify a certain named node.
+ * @param filter is a callback function which may check whether a certain
+ * node should be in the result set. If nullptr is given, all nodes matching
+ * the path are included. The filter function can be used to restrict the
+ * type of matched functions.
+ * @param filterData is user-defined data that should be passed to the
+ * filter.
+ * @param idx is the current index in the path.
+ * @param visited is a map which is used to prevent unwanted recursion.
+ * @param alias is a pointer at a string which contains an alternative name
+ * for this node. If nullptr is given, not such alternative name is
+ * provided.
+ * @return the number of elements in the result list.
+ */
+ int resolve(std::vector<Rooted<Managed>> &res,
+ const std::vector<std::string> &path, Filter filter,
+ void *filterData, unsigned idx, VisitorSet &visited,
+ const std::string *alias);
+
+ /**
+ * Function which resolves a name path to a list of possible nodes starting
+ * from this node.
+ *
+ * @param path is a list specifying a path of node names meant to specify a
+ * certain named node.
+ * @param filter is a callback function which may check whether a certain
+ * node should be in the result set. If nullptr is given, all nodes matching
+ * the path are included. The filter function can e.g. be used to restrict
+ * the type of matched functions.
+ * @param filterData is user-defined data that should be passed to the
+ * filter.
+ * @return a vector containing all found node references.
+ */
+ std::vector<Rooted<Managed>> resolve(const std::vector<std::string> &path,
+ Filter filter, void *filterData);
+
+ /**
+ * Function which resolves a name path to a list of possible nodes starting
+ * from this node.
+ *
+ * @param path is a list specifying a path of node names meant to specify a
+ * certain named node.
+ * @return a vector containing all found node references.
+ */
+ std::vector<Rooted<Managed>> resolve(const std::vector<std::string> &path)
+ {
+ return resolve(path, nullptr, nullptr);
+ }
+
+ /**
+ * Function which resolves a single name to a list of possible nodes
+ * starting from this node.
+ *
+ * @param name is the name which should be resolved.
+ * @param filter is a callback function which may check whether a certain
+ * node should be in the result set. If nullptr is given, all nodes matching
+ * the path are included. The filter function can e.g. be used to restrict
+ * the type of matched functions.
+ * @param filterData is user-defined data that should be passed to the
+ * filter.
+ * @return a vector containing all found node references.
+ */
+ std::vector<Rooted<Managed>> resolve(const char *, Filter filter,
+ void *filterData)
+ {
+ return resolve(std::vector<std::string>{name}, filter, filterData);
+ }
+
+ /**
+ * Function which resolves a single name to a list of possible nodes
+ * starting from this node.
+ *
+ * @param name is the name which should be resolved.
+ * @return a vector containing all found node references.
+ */
+ std::vector<Rooted<Managed>> resolve(const std::string &name)
+ {
+ return resolve(std::vector<std::string>{name}, nullptr, nullptr);
+ }
+};
+
+// TODO: Use a different listener here for updating name maps
+
+template <class T, class Listener = DefaultListener<Handle<T>>>
+class NodeVector
+ : public ManagedGenericList<T, std::vector<Handle<T>>,
+ ListAccessor<Handle<T>>, Listener> {
+public:
+ using Base = ManagedGenericList<T, std::vector<Handle<T>>,
+ ListAccessor<Handle<T>>, Listener>;
+ using Base::ManagedGenericList;
+};
+
+template <class K, class T,
+ class Listener = DefaultListener<std::pair<K, Handle<T>>>>
+class NodeMap
+ : public ManagedGenericMap<K, T, std::map<K, Handle<T>>,
+ MapAccessor<std::pair<K, Handle<T>>>, Listener> {
+public:
+ using Base =
+ ManagedGenericMap<K, T, std::map<K, Handle<T>>,
+ MapAccessor<std::pair<K, Handle<T>>>, Listener>;
+ using Base::ManagedGenericMap;
+};
+
+namespace RttiTypes {
+/**
+ * Typeinformation for the base "Node" class.
+ */
+extern const Rtti<Node> Node;
+}
+}
+
+#endif /* _OUSIA_NODE_HPP_ */
+
diff --git a/src/core/model/Typesystem.hpp b/src/core/model/Typesystem.hpp
index 3a91895..a4322c4 100644
--- a/src/core/model/Typesystem.hpp
+++ b/src/core/model/Typesystem.hpp
@@ -32,12 +32,13 @@
#include <map>
#include <vector>
-#include <core/Node.hpp>
#include <core/common/Exceptions.hpp>
#include <core/common/Logger.hpp>
#include <core/common/Rtti.hpp>
#include <core/common/Variant.hpp>
+#include "Node.hpp"
+
namespace ousia {
namespace model {