summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/common/Rtti.hpp182
-rw-r--r--src/core/model/Document.cpp34
-rw-r--r--src/core/model/Domain.cpp81
-rw-r--r--src/core/model/Domain.hpp17
-rw-r--r--src/core/model/Node.cpp265
-rw-r--r--src/core/model/Node.hpp351
-rw-r--r--src/core/model/Typesystem.cpp67
-rw-r--r--src/core/model/Typesystem.hpp34
-rw-r--r--test/core/managed/ManagerTest.cpp3
-rw-r--r--test/core/model/DomainTest.cpp72
-rw-r--r--test/core/model/NodeTest.cpp42
11 files changed, 776 insertions, 372 deletions
diff --git a/src/core/common/Rtti.hpp b/src/core/common/Rtti.hpp
index 237c60f..9d0cdab 100644
--- a/src/core/common/Rtti.hpp
+++ b/src/core/common/Rtti.hpp
@@ -105,6 +105,152 @@ public:
};
/**
+ * The RttiBuilder class is used to conveniently build new instances of the Rtti
+ * or the RttiBase class. It follows the "Builder" pattern and allows to create
+ * the properties of the RttiBase class by chaining method calls. The RttiBase
+ * and Rtti class can be constructed from the RttiBuilder instance.
+ */
+class RttiBuilder {
+public:
+ /**
+ * Type describing a set of RttiBase pointers.
+ */
+ using RttiBaseSet = std::unordered_set<const RttiBase *>;
+
+ /**
+ * Contains the human readable name of the type for which the type
+ * information is being built.
+ */
+ std::string currentName;
+
+ /**
+ * Set containing references to all parent types.
+ */
+ RttiBaseSet parentTypes;
+
+ /**
+ * Set containing references to all composite types.
+ */
+ RttiBaseSet compositeTypes;
+
+ /**
+ * Default constructor, initializes the name of the type described by the
+ * RttiBaseSet with "unknown".
+ */
+ RttiBuilder() : currentName("unknown"){};
+
+ /**
+ * Default constructor, initializes the name of the type described by the
+ * RttiBaseSet with the given name.
+ *
+ * @param name is the initial name of the type described by the type
+ * builder.
+ */
+ RttiBuilder(std::string name) : currentName(std::move(name)){};
+
+ /**
+ * Sets the human readable name of the type information being built to the
+ * given string.
+ *
+ * @param s is the name to which the name should be set.
+ * @return a reference to the current RttiBuilder reference to allow method
+ * chaining.
+ */
+ RttiBuilder &name(const std::string &s)
+ {
+ currentName = s;
+ return *this;
+ }
+
+ /**
+ * Adds the given type descriptor as "parent" of the type information that
+ * is being built by this RttiBuilder instance.
+ *
+ * @param p is the pointer to the type descriptor that should be added.
+ * @return a reference to the current RttiBuilder reference to allow method
+ * chaining.
+ */
+ RttiBuilder &parent(const RttiBase *p)
+ {
+ parentTypes.insert(p);
+ return *this;
+ }
+
+ /**
+ * Adds the given type descriptor as "parent" of the type information that
+ * is being built by this RttiBuilder instance.
+ *
+ * @param p is the pointer to the type descriptor that should be added.
+ * @return a reference to the current RttiBuilder reference to allow method
+ * chaining.
+ */
+ RttiBuilder &parent(const RttiBase &p)
+ {
+ parentTypes.insert(&p);
+ return *this;
+ }
+
+ /**
+ * Adds the given type descriptors as "parent" of the type information that
+ * is being built by this RttiBuilder instance.
+ *
+ * @param p is a
+ * @return a reference to the current RttiBuilder reference to allow method
+ * chaining.
+ */
+ RttiBuilder &parent(const RttiBaseSet &p)
+ {
+ parentTypes.insert(p.begin(), p.end());
+ return *this;
+ }
+
+ /**
+ * Marks the current type being built by this RttiBuilder instance as being
+ * a composition of the given other type.
+ *
+ * @param p is the pointer to the type descriptor that should be added as
+ * composition type.
+ * @return a reference to the current RttiBuilder reference to allow method
+ * chaining.
+ */
+ RttiBuilder &composedOf(const RttiBase *p)
+ {
+ compositeTypes.insert(p);
+ return *this;
+ }
+
+ /**
+ * Marks the current type being built by this RttiBuilder instance as being
+ * a composition of the given other type.
+ *
+ * @param p is the pointer to the type descriptor that should be added as
+ * composition type.
+ * @return a reference to the current RttiBuilder reference to allow method
+ * chaining.
+ */
+ RttiBuilder &composedOf(const RttiBase &p)
+ {
+ compositeTypes.insert(&p);
+ return *this;
+ }
+
+ /**
+ * Marks the current type being built by this RttiBuilder instance as being
+ * a composition of the given other types.
+ *
+ * @param p is the pointer to the type descriptor that should be added as
+ * composition type.
+ * @return a reference to the current RttiBuilder reference to allow method
+ * chaining.
+ */
+ RttiBuilder &composedOf(const RttiBaseSet &p)
+ {
+ compositeTypes.insert(p.begin(), p.end());
+ return *this;
+ }
+};
+
+/**
* The Rtti class allows for attaching data to native types that can be accessed
* at runtime. This type information can e.g. be retrieved using the "type"
* method of the Managed class. This system is used for attaching human readable
@@ -151,13 +297,15 @@ public:
/**
* Creates a new RttiBase instance and registers it in the global type
- * table. Use the Rtti class for more convinient registration of type
- * information.
+ * table. Use the Rtti and the RttiBuilder class for more convenient
+ * registration of type information.
*
* @param name is the name of the type.
* @param native is a reference at the native type information provided by
* the compiler.
* @param parents is a list of parent types.
+ * @param compositeTypes is a list of types of which instances of this type
+ * are composited (consist of).
*/
RttiBase(std::string name, const std::type_info &native,
std::unordered_set<const RttiBase *> parents =
@@ -173,6 +321,22 @@ public:
}
/**
+ * Creates a new RttiBase instance and registers it in the global type
+ * table. Use the Rtti class for more convenient registration of type
+ * information.
+ *
+ * @param builder is the builder instance containing the Rtti data.
+ */
+ RttiBase(const std::type_info &native, const RttiBuilder &builder)
+ : initialized(false),
+ parents(builder.parentTypes),
+ compositeTypes(builder.compositeTypes),
+ name(builder.currentName)
+ {
+ RttiStore::store(native, this);
+ }
+
+ /**
* Returns true if this Rtti instance is the given type or has the
* given type as one of its parents.
*
@@ -204,11 +368,12 @@ template <class T>
class Rtti : public RttiBase {
public:
/**
- * Creates a new RttiBase instance and registers it in the global type
- * table.
+ * Creates a new Rtti instance and registers it in the global type table.
*
* @param name is the name of the type.
* @param parents is a list of parent types.
+ * @param compositeTypes is a list of types of which instances of this type
+ * are composited (consist of).
*/
Rtti(std::string name, const std::unordered_set<const RttiBase *> &parents =
std::unordered_set<const RttiBase *>{},
@@ -218,6 +383,15 @@ public:
std::move(compositeTypes))
{
}
+
+ /**
+ * Creates a new Rtti instance from the data stored in the given builder
+ * instance and registers it in the global type table.
+ *
+ * @param builder is the RttiBuilder instance containing the data from which
+ * the Rtti information should be copied.
+ */
+ Rtti(const RttiBuilder &builder) : RttiBase(typeid(T), builder){};
};
/**
diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp
index c653fe3..945fb3e 100644
--- a/src/core/model/Document.cpp
+++ b/src/core/model/Document.cpp
@@ -93,16 +93,14 @@ static Rooted<StructuredClass> resolveDescriptor(
// iterate over all domains.
for (auto &d : domains) {
// use the actual resolve method.
- std::vector<Rooted<Managed>> resolved = d->resolve(className);
+ std::vector<ResolutionResult> resolved = d->resolve(className, typeOf<StructuredClass>());
// if we don't find anything, continue.
if (resolved.size() == 0) {
continue;
}
// Otherwise take the first valid result.
for (auto &r : resolved) {
- if (r->isa(typeOf<StructuredClass>())) {
- return r.cast<StructuredClass>();
- }
+ return r.node.cast<StructuredClass>();
}
}
return {nullptr};
@@ -239,19 +237,21 @@ Rooted<AnnotationEntity> AnnotationEntity::buildEntity(
}
namespace RttiTypes {
-const Rtti<model::Document> Document{
- "Document", {&Node}, {&AnnotationEntity, &StructuredEntity}};
-const Rtti<model::DocumentEntity> DocumentEntity{"DocumentEntity", {&Node}};
-const Rtti<model::AnnotationEntity> AnnotationEntity{
- "AnnotationEntity", {&DocumentEntity}, {&StructuredEntity}};
-const Rtti<model::StructuredEntity> StructuredEntity{
- "StructuredEntity",
- {&DocumentEntity},
- {&StructuredEntity, &Anchor, &DocumentPrimitive}};
-const Rtti<model::DocumentPrimitive> DocumentPrimitive{"DocumentPrimitive",
- {&StructuredEntity}};
-const Rtti<model::AnnotationEntity::Anchor> Anchor{"Anchor",
- {&StructuredEntity}};
+const Rtti<model::DocumentEntity> DocumentEntity =
+ RttiBuilder("DocumentEntity").parent(&Node);
+const Rtti<model::Document> Document =
+ RttiBuilder("Document").parent(&Node).composedOf(
+ {&AnnotationEntity, &StructuredEntity});
+const Rtti<model::AnnotationEntity> AnnotationEntity =
+ RttiBuilder("AnnotationEntity").parent(&DocumentEntity).composedOf(
+ &StructuredEntity);
+const Rtti<model::StructuredEntity> StructuredEntity =
+ RttiBuilder("StructuredEntity").parent(&DocumentEntity).composedOf(
+ {&StructuredEntity, &Anchor, &DocumentPrimitive});
+const Rtti<model::DocumentPrimitive> DocumentPrimitive =
+ RttiBuilder("DocumentPrimitive").parent(&StructuredEntity);
+const Rtti<model::AnnotationEntity::Anchor> Anchor =
+ RttiBuilder("Anchor").parent(&StructuredEntity);
}
}
diff --git a/src/core/model/Domain.cpp b/src/core/model/Domain.cpp
index 49a3200..f03bd7a 100644
--- a/src/core/model/Domain.cpp
+++ b/src/core/model/Domain.cpp
@@ -23,73 +23,46 @@
namespace ousia {
namespace model {
-void FieldDescriptor::doResolve(std::vector<Rooted<Managed>> &res,
- const std::vector<std::string> &path,
- Filter filter, void *filterData, unsigned idx,
- VisitorSet &visited)
-{
- // We call resolve for the children, but give them the field name as
- // alias.
- for (auto &c : children) {
- c->resolve(res, path, filter, filterData, idx, visited, &getNameRef());
- }
-}
+/* Class FieldDescriptor */
-// TODO: better alias?
-static std::string DESCRIPTOR_ATTRIBUTES_ALIAS{"attributes"};
+/* Class Descriptor */
-void Descriptor::doResolve(std::vector<Rooted<Managed>> &res,
- const std::vector<std::string> &path, Filter filter,
- void *filterData, unsigned idx, VisitorSet &visited)
+void Descriptor::continueResolve(ResolutionState &state)
{
- // TODO: This could be a problem, because the name of the field might be
- // needed in the path.
- for (auto &fd : fieldDescriptors) {
- fd->resolve(res, path, filter, filterData, idx, visited, nullptr);
- }
- // TODO: This throws a SEGFAULT for some reason.
- // attributesDescriptor->resolve(res, path, filter, filterData, idx,
- // visited,
- // &DESCRIPTOR_ATTRIBUTES_ALIAS);
+ const NodeVector<Attribute> &attributes =
+ attributesDescriptor->getAttributes();
+ continueResolveComposita(attributes, attributes.getIndex(), state);
+ continueResolveComposita(fieldDescriptors, fieldDescriptors.getIndex(),
+ state);
}
-//void StructuredClass::doResolve(std::vector<Rooted<Managed>> &res,
-// const std::vector<std::string> &path,
-// Filter filter, void *filterData, unsigned idx,
-// VisitorSet &visited)
-//{
-// Descriptor::doResolve(res, path, filter, filterData, idx, visited);
-// if (!isa.isNull()) {
-// isa->doResolve(res, path, filter, filterData, idx, visited);
-// }
-//}
+/* Class Domain */
-void Domain::doResolve(std::vector<Rooted<Managed>> &res,
- const std::vector<std::string> &path, Filter filter,
- void *filterData, unsigned idx, VisitorSet &visited)
+void Domain::continueResolve(ResolutionState &state)
{
- for (auto &s : structureClasses) {
- s->resolve(res, path, filter, filterData, idx, visited, nullptr);
- }
- for (auto &a : annotationClasses) {
- a->resolve(res, path, filter, filterData, idx, visited, nullptr);
- }
- for (auto &t : typesystems) {
- t->resolve(res, path, filter, filterData, idx, visited, nullptr);
+ if (!continueResolveComposita(structureClasses, structureClasses.getIndex(),
+ state) |
+ continueResolveComposita(annotationClasses,
+ annotationClasses.getIndex(), state)) {
+ continueResolveReferences(typesystems, state);
}
}
}
/* Type registrations */
namespace RttiTypes {
-const Rtti<model::FieldDescriptor> FieldDescriptor{"FieldDescriptor", {&Node}};
-const Rtti<model::Descriptor> Descriptor{"Descriptor", {&Node}};
-const Rtti<model::StructuredClass> StructuredClass{
- "StructuredClass", {&Descriptor}, {&FieldDescriptor}};
-const Rtti<model::AnnotationClass> AnnotationClass{"AnnotationClass",
- {&Descriptor}};
-const Rtti<model::Domain> Domain{
- "Domain", {&Node}, {&StructuredClass, &AnnotationClass}};
+const Rtti<model::FieldDescriptor> FieldDescriptor =
+ RttiBuilder("FieldDescriptor").parent(&Node);
+const Rtti<model::Descriptor> Descriptor =
+ RttiBuilder("Descriptor").parent(&Node);
+const Rtti<model::StructuredClass> StructuredClass =
+ RttiBuilder("StructuredClass").parent(&Descriptor).composedOf(
+ &FieldDescriptor);
+const Rtti<model::AnnotationClass> AnnotationClass =
+ RttiBuilder("AnnotationClass").parent(&Descriptor);
+const Rtti<model::Domain> Domain =
+ RttiBuilder("Domain").parent(&Node).composedOf(
+ {&StructuredClass, &AnnotationClass});
}
}
diff --git a/src/core/model/Domain.hpp b/src/core/model/Domain.hpp
index 027cf88..7412ef4 100644
--- a/src/core/model/Domain.hpp
+++ b/src/core/model/Domain.hpp
@@ -254,12 +254,6 @@ private:
FieldType fieldType;
Owned<Type> primitiveType;
-protected:
- void doResolve(std::vector<Rooted<Managed>> &res,
- const std::vector<std::string> &path, Filter filter,
- void *filterData, unsigned idx,
- VisitorSet &visited) override;
-
public:
const bool optional;
@@ -310,7 +304,6 @@ public:
: Node(mgr, std::move(name), parent),
children(this),
fieldType(fieldType),
- // TODO: What would be a wise initialization of the primitiveType?
optional(optional)
{
}
@@ -360,10 +353,7 @@ private:
NodeVector<FieldDescriptor> fieldDescriptors;
protected:
- void doResolve(std::vector<Rooted<Managed>> &res,
- const std::vector<std::string> &path, Filter filter,
- void *filterData, unsigned idx,
- VisitorSet &visited) override;
+ void continueResolve(ResolutionState &state) override;
public:
Descriptor(Manager &mgr, std::string name, Handle<Domain> domain,
@@ -554,10 +544,7 @@ private:
NodeVector<Typesystem> typesystems;
protected:
- void doResolve(std::vector<Rooted<Managed>> &res,
- const std::vector<std::string> &path, Filter filter,
- void *filterData, unsigned idx,
- VisitorSet &visited) override;
+ void continueResolve(ResolutionState &state) override;
public:
Domain(Manager &mgr, Handle<SystemTypesystem> sys, std::string name)
diff --git a/src/core/model/Node.cpp b/src/core/model/Node.cpp
index e149596..518a74d 100644
--- a/src/core/model/Node.cpp
+++ b/src/core/model/Node.cpp
@@ -16,23 +16,171 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <functional>
+#include <unordered_set>
+
#include <core/common/Exceptions.hpp>
#include "Node.hpp"
namespace ousia {
-/* Class Node */
+/* Class SharedResolutionState */
-void Node::setName(std::string name)
-{
- // Call the name change event
+/**
+ * The SharedResolutionState structure represents the state that is shared
+ * between all resolution paths. A reference to a per-resolution-global
+ * SharedResolutionState instance is stored in the ResolutionState class.
+ */
+class SharedResolutionState {
+
+public:
+ /**
+ * Actual path (name pattern) that was requested for resolution.
+ */
+ const std::vector<std::string> &path;
+
+ /**
+ * Type of the node that was requested for resolution.
+ */
+ const RttiBase &type;
+
+ /**
+ * Tracks all nodes that have already been visited.
+ */
+ std::unordered_set<Node *> visited;
+
+ /**
+ * Current resolution result.
+ */
+ std::vector<ResolutionResult> result;
+
+ static std::vector<int> buildPrefixTable(
+ const std::vector<std::string> &path);
+
+ /**
+ * Constructor of the SharedResolutionState class.
+ *
+ * @param path is a const reference to the actual path that should be
+ * resolved.
+ * @param type is the type of the node that should be resolved.
+ */
+ SharedResolutionState(const std::vector<std::string> &path,
+ const RttiBase &type)
+ : path(path), type(type)
+ {
+ }
+};
+
+/* Class ResolutionState */
+
+/**
+ * The ResolutionState class represents a single resolution path used when
+ * resolving Node instances by name.
+ */
+class ResolutionState {
+
+private:
+ /**
+ * Constructor of the ResolutionState class.
+ *
+ * @param shared is the shared, path independent state.
+ * @param resolutionRoot is the current resolution root node.
+ */
+ ResolutionState(SharedResolutionState &shared,
+ int idx,
+ Node *resolutionRoot)
+ : shared(shared), idx(idx), resolutionRoot(resolutionRoot)
+ {
+ }
+
+public:
+ /**
+ * Constructor of the ResolutionState class.
+ *
+ * @param shared is the shared, path independent state.
+ * @param resolutionRoot is the current resolution root node.
+ */
+ ResolutionState(SharedResolutionState &shared, Node *resolutionRoot = nullptr)
+ : shared(shared), idx(0), resolutionRoot(resolutionRoot)
+ {
+ }
+
+ /**
+ * Reference at the resolution state that is shared between the various
+ * resolution paths.
+ */
+ SharedResolutionState &shared;
+
+ /**
+ * Current index within the given path.
+ */
+ int idx;
+
+ /**
+ * Current resolution root node or nullptr if no resolution root node has
+ * been set yet.
+ */
+ Node *resolutionRoot;
+
+ /**
+ * Adds a node to the result.
+ *
+ * @param node is the node that has been found.
+ */
+ void addToResult(Node *node)
{
- NameChangeEvent ev{this->name, name};
- triggerEvent(ev);
+ shared.result.emplace_back(ResolutionResult{node, resolutionRoot});
}
- // Set the new name
+ /**
+ * Marks the given node as visited. Returns false if the given node has
+ * already been visited.
+ *
+ * @param node is the node that should be marked as visited.
+ */
+ bool markVisited(Node *node)
+ {
+ if (shared.visited.count(node) > 0) {
+ return false;
+ }
+ shared.visited.insert(node);
+ return true;
+ }
+
+ /**
+ * Returns true if the current node matches the search criteria.
+ *
+ * @param type is the type of the current node.
+ * @return true if the state indicates that the path has been completely
+ * matched and that the given type matches the queried type.
+ */
+ bool matches(const RttiBase &type)
+ {
+ return idx == static_cast<int>(shared.path.size()) &&
+ type.isa(shared.type);
+ }
+
+ const std::string &currentName() {
+ return shared.path[idx];
+ }
+
+ ResolutionState advance() {
+ return ResolutionState{shared, idx + 1, resolutionRoot};
+ }
+
+ ResolutionState fork(Node *newResolutionRoot) {
+ return ResolutionState{shared, newResolutionRoot};
+ }
+};
+
+/* Class Node */
+
+void Node::setName(std::string name)
+{
+ // Call the name change event and (afterwards!) set the new name
+ NameChangeEvent ev{this->name, name};
+ triggerEvent(ev);
this->name = std::move(name);
}
@@ -51,57 +199,90 @@ std::vector<std::string> Node::path() const
return res;
}
-void Node::doResolve(std::vector<Rooted<Managed>> &res,
- const std::vector<std::string> &path, Filter filter,
- void *filterData, unsigned idx, VisitorSet &visited)
+bool Node::resolutionAtBeginning(ResolutionState &state)
+{
+ return state.idx == 0;
+}
+
+bool Node::resolve(ResolutionState &state)
+{
+ // Try to mark this note as visited, do nothing if already has been visited
+ if (state.markVisited(this)) {
+ // Add this node to the result if it matches the current description
+ if (state.matches(type())) {
+ state.addToResult(this);
+ return true;
+ } else {
+ continueResolve(state);
+ }
+ }
+ return false;
+}
+
+void Node::continueResolve(ResolutionState &state)
{
// 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)
+bool Node::continueResolveIndex(const Index &index, ResolutionState &state) {
+ Rooted<Node> h = index.resolve(state.currentName());
+ if (h != nullptr) {
+ ResolutionState advancedState = state.advance();
+ return h->resolve(advancedState);
+ }
+ return false;
+}
+
+bool Node::continueResolveCompositum(Handle<Node> h, ResolutionState &state)
{
- // 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();
+ if (h->getName() == state.currentName()) {
+ ResolutionState advancedState = state.advance();
+ return h->resolve(advancedState);
+ } else if (resolutionAtBeginning(state)) {
+ return h->resolve(state);
}
- 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);
+ return false;
+}
+
+bool Node::continueResolveReference(Handle<Node> h, ResolutionState &state)
+{
+ if (resolutionAtBeginning(state)) {
+ ResolutionState forkedState = state.fork(this);
+ if (h->getName() == state.currentName()) {
+ ResolutionState advancedState = forkedState.advance();
+ return h->resolve(advancedState);
}
+ return h->resolve(forkedState);
}
+ return false;
+}
- // 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);
+std::vector<ResolutionResult> Node::resolve(
+ const std::vector<std::string> &path, const RttiBase &type)
+{
+ // Create the state variables
+ SharedResolutionState sharedState(path, type);
+ ResolutionState state(sharedState, this);
- return res.size();
+ // Call the internal resolve function, make sure the length of the given
+ // path is valid
+ if (path.size() > 0) {
+ continueResolveCompositum(this, state);
+ }
+
+ // Return the results
+ return sharedState.result;
}
-std::vector<Rooted<Managed>> Node::resolve(const std::vector<std::string> &path,
- Filter filter = nullptr,
- void *filterData = nullptr)
+std::vector<ResolutionResult> Node::resolve(const std::string &name,
+ const RttiBase &type)
{
- std::vector<Rooted<Managed>> res;
- VisitorSet visited;
- resolve(res, path, filter, filterData, 0, visited, nullptr);
- return res;
+ // Place the name in a vector and call the corresponding resolve function
+ return resolve(std::vector<std::string>{name}, type);
}
/* RTTI type registrations */
const Rtti<Node> RttiTypes::Node{"Node"};
}
+
diff --git a/src/core/model/Node.hpp b/src/core/model/Node.hpp
index a637b56..97ec16f 100644
--- a/src/core/model/Node.hpp
+++ b/src/core/model/Node.hpp
@@ -16,14 +16,21 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * @file Node.hpp
+ *
+ * Contains the definition of the Node class, the base class used by all model
+ * classes.
+ *
+ * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
+ */
+
#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>
@@ -34,48 +41,45 @@
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.
+ * Structure describing a single result obtained from the resolution function.
*/
-class Node : public Managed {
-public:
+struct ResolutionResult {
/**
- * 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.
+ * The actual node that was resolved.
*/
- using Filter = bool (*)(Handle<Managed> managed, void *data);
+ Rooted<Node> node;
/**
- * Hash functional used to convert pairs of nodes and int to hashes which
- * can be used within a unordered_set.
+ * Root node of the subtree in which the node was found. This e.g. points to
+ * the Domain in which a Structure was defined or the Typesystem in which a
+ * Type was defined. May be nullptr.
*/
- 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);
- }
- };
+ Rooted<Node> resolutionRoot;
/**
- * 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.
+ * Default constructor of the ResolutionResult class.
+ *
+ * @param node is a reference pointing at the actually found node.
+ * @param resolutionRoot is a reference to the root node of the subtree in
+ * which the node was found.
*/
- using VisitorSet =
- std::unordered_set<std::pair<const Node *, int>, VisitorHash>;
+ ResolutionResult(Handle<Node> node, Handle<Node> resolutionRoot)
+ : node(node), resolutionRoot(resolutionRoot)
+ {
+ }
+};
+
+// Forward declaration
+struct ResolutionState;
+/**
+ * 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 {
private:
/**
* Name of the node. As names are always looked up relative to a node,
@@ -97,29 +101,142 @@ private:
*/
void path(std::vector<std::string> &p) const;
+ /**
+ * Returns true if the resolution process is just at the beginning (no part
+ * of the path has been matched yet).
+ *
+ * @param state is used internally to manage the resolution process.
+ */
+ static bool resolutionAtBeginning(ResolutionState &state);
+
+ /**
+ * Method used internally for resolving nodes with a certain name and type
+ * within the object graph.
+ *
+ * @param state is used internally to manage the resolution process.
+ * @return true if an matching element was found within this subtree, false
+ * otherwise.
+ * @return true if at least one new node has been found that matches the
+ * criteria given for the resolution.
+ */
+ bool resolve(ResolutionState &state);
+
+ /**
+ * Method used internally to check whether the given index has an entry
+ * which matches the one currently needed to continue the path.
+ *
+ * @param index is a reference to the index from which the currently active
+ * path element should be looked up.
+ * @param state is used internally to manage the resolution process.
+ * @return true if at least one new node has been found that matches the
+ * criteria given for the resolution.
+ */
+ bool continueResolveIndex(const Index &index, ResolutionState &state);
+
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.
+ * this function do not need to do anything but call the
+ * continueResolveComposita() and/or continueResolveReferences() methods on
+ * any index or list of references and pass the resolution state to these
+ * methods.
+ *
+ * @param state is used internally to manage the resolution process.
+ */
+ virtual void continueResolve(ResolutionState &state);
+
+ /**
+ * Tries to advance the resolution process with the compositum pointed at
+ * by h. If a part of the resolution path has already been matched, only
+ * decends into the given node if the path can be continued. Otherwise
+ * always decends into the node to search for potential beginnings of the
+ * path.
+ *
+ * @param h is a handle at a compositum (a node the current node consists of
+ * or explicitly defines).
+ * @param state is used internally to manage the resolution process.
+ * @return true if at least one new node has been found that matches the
+ * criteria given for the resolution.
+ */
+ bool continueResolveCompositum(Handle<Node> h, ResolutionState &state);
+
+ /**
+ * Calls continueResolveCompositum() for each element in the given
+ * container.
+ *
+ * @param container is a container containing compositum nodes for which the
+ * continueResolveCompositum() method should be called.
+ * @param state is used internally to manage the resolution process.
+ * @return true if at least one new node has been found that matches the
+ * criteria given for the resolution.
+ */
+ template <class T>
+ bool continueResolveComposita(T &container, ResolutionState &state)
+ {
+ bool res = false;
+ for (auto elem : container) {
+ res = continueResolveCompositum(elem, state) | res;
+ }
+ return res;
+ }
+
+ /**
+ * Calls continueResolveCompositum() for each element in the given
+ * container. Uses the given index to speed up the resolution process.
+ *
+ * @param container is a container containing compositum nodes for which the
+ * continueResolveCompositum() method should be called.
+ * @param index is the Index instance of the given container and is used to
+ * speed up the resolution process.
+ * @param state is used internally to manage the resolution process.
+ * @return true if at least one new node has been found that matches the
+ * criteria given for the resolution.
+ */
+ template <class T>
+ bool continueResolveComposita(T &container, const Index &index,
+ ResolutionState &state)
+ {
+ if (continueResolveIndex(index, state)) {
+ return true;
+ } else if (resolutionAtBeginning(state)) {
+ return continueResolveComposita(container, state);
+ }
+ return false;
+ }
+
+ /**
+ * Tries to search for the requested node in another subtree to which a
+ * reference exists from this node.
+ *
+ * @param h is a handle pointing at the node in the subtree.
+ * @param state is used internally to manage the resolution process.
+ * @return true if at least one new node has been found that matches the
+ * criteria given for the resolution.
+ */
+ bool continueResolveReference(Handle<Node> h, ResolutionState &state);
+
+ /**
+ * Tries to search for the requested node in another subtree to which a
+ * reference exists from this node.
*
- * @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.
+ * @param h is a handle pointing at the node in the subtree.
+ * @param state is used internally to manage the resolution process.
+ * @return true if at least one new node has been found that matches the
+ * criteria given for the resolution.
*/
- virtual void doResolve(std::vector<Rooted<Managed>> &res,
- const std::vector<std::string> &path, Filter filter,
- void *filterData, unsigned idx, VisitorSet &visited);
+ template <class T>
+ bool continueResolveReferences(T &container, ResolutionState &state)
+ {
+ if (resolutionAtBeginning(state)) {
+ bool res = false;
+ for (auto elem : container) {
+ res = continueResolveReference(elem, state) | res;
+ }
+ return res;
+ }
+ return false;
+ }
public:
/**
@@ -158,12 +275,7 @@ public:
/**
* 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; }
+ const std::string &getName() const { return name; }
/**
* Specifies whether the node has a name, e.g. whether the current name is
@@ -206,94 +318,41 @@ public:
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.
+ * @param type specifies the type of the node that should be located.
+ * @return a vector containing ResolutionResult structures which describe
+ * the resolved elements.
*/
- std::vector<Rooted<Managed>> resolve(const char *, Filter filter,
- void *filterData)
- {
- return resolve(std::vector<std::string>{name}, filter, filterData);
- }
+ std::vector<ResolutionResult> resolve(const std::vector<std::string> &path,
+ const RttiBase &type);
/**
* 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.
+ * @param type specifies the type of the node that should be located.
+ * @return a vector containing ResolutionResult structures which describe
+ * the resolved elements.
*/
- std::vector<Rooted<Managed>> resolve(const std::string &name)
- {
- return resolve(std::vector<std::string>{name}, nullptr, nullptr);
- }
+ std::vector<ResolutionResult> resolve(const std::string &name,
+ const RttiBase &type);
};
-// TODO: Use a different listener here for updating name maps
-
+/**
+ * The NodeVector class is a vector capable of automatically maintaining an
+ * index used for the resolution of node names.
+ *
+ * @tparam T is the type that should be stored in the NodeVector. Must be a
+ * descendant of the Node class.
+ * @tparam Listener is the listener class that should be used to build the
+ * internal index. Should either be Index or a reference to (&Index) in case a
+ * shared index is used.
+ */
template <class T, class Listener = Index>
class NodeVector
: public ManagedGenericList<T, std::vector<Handle<T>>,
@@ -303,9 +362,29 @@ public:
ListAccessor<Handle<T>>, Listener>;
using Base::ManagedGenericList;
- Index& getIndex() { return this->listener;}
+ /**
+ * Returns the reference to the internal index.
+ */
+ const Index &getIndex() const { return this->listener; }
+
+ /**
+ * Returns the reference to the internal index.
+ */
+ Index &getIndex() { return this->listener; }
+
};
+/**
+ * The NodeMap class is a map class capable of automatically maintaining an
+ * index used for the resolution of node names.
+ *
+ * @tparam K is the key type that should be stored in the NodeMap.
+ * @tparam T is the value type that should be stored in the NodeMap. Must be a
+ * descendant of the Node class.
+ * @tparam Listener is the listener class that should be used to build the
+ * internal index. Should either be Index or a reference to (&Index) in case a
+ * shared index is used.
+ */
template <class K, class T, class Listener = Index>
class NodeMap
: public ManagedGenericMap<K, T, std::map<K, Handle<T>>,
@@ -316,7 +395,15 @@ public:
MapAccessor<std::pair<K, Handle<T>>>, Listener>;
using Base::ManagedGenericMap;
- Index& getIndex() { return this->listener;}
+ /**
+ * Returns the reference to the internal index.
+ */
+ const Index &getIndex() const { return this->listener; }
+
+ /**
+ * Returns the reference to the internal index.
+ */
+ Index &getIndex() { return this->listener; }
};
namespace RttiTypes {
diff --git a/src/core/model/Typesystem.cpp b/src/core/model/Typesystem.cpp
index 2945635..f082f39 100644
--- a/src/core/model/Typesystem.cpp
+++ b/src/core/model/Typesystem.cpp
@@ -318,20 +318,19 @@ bool StructType::doBuild(Variant &data, Logger &logger) const
return buildFromArrayOrMap(data, logger, false);
}
-Rooted<StructType> StructType::createValidated(Manager &mgr, std::string name,
- Handle<Typesystem> system,
- Handle<StructType> parent,
- NodeVector<Attribute> attributes,
- Logger &logger)
+Rooted<StructType> StructType::createValidated(
+ Manager &mgr, std::string name, Handle<Typesystem> system,
+ Handle<StructType> parentStructure, NodeVector<Attribute> attributes,
+ Logger &logger)
{
// Check the attributes for validity and uniqueness
std::map<std::string, size_t> attributeNames;
NodeVector<Attribute> collectedAttributes;
// Copy the attributes from the parent structure
- if (parent != nullptr) {
- attributeNames = parent->attributeNames;
- collectedAttributes = parent->attributes;
+ if (parentStructure != nullptr) {
+ attributeNames = parentStructure->attributeNames;
+ collectedAttributes = parentStructure->attributes;
}
// Check the attributes for validity and uniqueness
@@ -348,10 +347,11 @@ Rooted<StructType> StructType::createValidated(Manager &mgr, std::string name,
if (!res.second) {
logger.error(std::string("Attribute with name \"") + attrName +
std::string("\" defined multiple times"));
- if (parent != nullptr && parent->indexOf(attrName) >= 0) {
+ if (parentStructure != nullptr &&
+ parentStructure->indexOf(attrName) >= 0) {
logger.note(std::string("Attribute \"") + attrName +
std::string("\" was defined in parent class \"") +
- parent->getName() + std::string("\""));
+ parentStructure->getName() + std::string("\""));
}
}
@@ -360,8 +360,8 @@ Rooted<StructType> StructType::createValidated(Manager &mgr, std::string name,
}
// Call the private constructor
- return new StructType(mgr, name, system, parent, collectedAttributes,
- attributeNames);
+ return new StructType(mgr, name, system, parentStructure,
+ collectedAttributes, attributeNames);
}
Variant StructType::create() const
@@ -383,8 +383,8 @@ bool StructType::derivedFrom(Handle<StructType> other) const
if (other == this) {
return true;
}
- if (parent != nullptr) {
- return parent->derivedFrom(other);
+ if (parentStructure != nullptr) {
+ return parentStructure->derivedFrom(other);
}
return false;
}
@@ -438,24 +438,27 @@ SystemTypesystem::SystemTypesystem(Manager &mgr)
/* RTTI type registrations */
namespace RttiTypes {
-const Rtti<model::Type> Type{"Type", {&Node}};
-const Rtti<model::StringType> StringType{"StringType", {&Type}};
-const Rtti<model::IntType> IntType{"IntType", {&Type}};
-const Rtti<model::DoubleType> DoubleType{"DoubleType", {&Type}};
-const Rtti<model::BoolType> BoolType{"BoolType", {&Type}};
-const Rtti<model::EnumType> EnumType{"EnumType", {&Type}};
-const Rtti<model::StructType> StructType{"StructType", {&Type}, {&Attribute}};
-const Rtti<model::ArrayType> ArrayType{"ArrayType", {&Type}};
-const Rtti<model::UnknownType> UnknownType{"UnknownType", {&Type}};
-const Rtti<model::Constant> Constant{"Constant", {&Node}};
-const Rtti<model::Attribute> Attribute{"Attribute", {&Node}};
-const Rtti<model::Typesystem> Typesystem{
- "Typesystem",
- {&Node},
- {&StringType, &IntType, &DoubleType, &BoolType, &EnumType, &StructType,
- &Constant}};
-const Rtti<model::SystemTypesystem> SystemTypesystem{"SystemTypesystem",
- {&Typesystem}};
+const Rtti<model::Type> Type = RttiBuilder("Type").parent(&Node);
+const Rtti<model::StringType> StringType =
+ RttiBuilder("StringType").parent(&Type);
+const Rtti<model::IntType> IntType = RttiBuilder("IntType").parent(&Type);
+const Rtti<model::DoubleType> DoubleType =
+ RttiBuilder("DoubleType").parent(&Type);
+const Rtti<model::BoolType> BoolType = RttiBuilder("BoolType").parent(&Type);
+const Rtti<model::EnumType> EnumType = RttiBuilder("EnumType").parent(&Type);
+const Rtti<model::StructType> StructType =
+ RttiBuilder("StructType").parent(&Type).composedOf(&Attribute);
+const Rtti<model::ArrayType> ArrayType = RttiBuilder("ArrayType").parent(&Type);
+const Rtti<model::UnknownType> UnknownType =
+ RttiBuilder("UnknownType").parent(&Type);
+const Rtti<model::Constant> Constant = RttiBuilder("Constant").parent(&Node);
+const Rtti<model::Attribute> Attribute = RttiBuilder("Attribute").parent(&Node);
+const Rtti<model::Typesystem> Typesystem =
+ RttiBuilder("Typesystem").parent(&Node).composedOf(
+ {&StringType, &IntType, &DoubleType, &BoolType, &EnumType, &StructType,
+ &Constant});
+const Rtti<model::SystemTypesystem> SystemTypesystem =
+ RttiBuilder("SystemTypesystem").parent(&Typesystem);
}
}
diff --git a/src/core/model/Typesystem.hpp b/src/core/model/Typesystem.hpp
index b492b25..c0e0fb1 100644
--- a/src/core/model/Typesystem.hpp
+++ b/src/core/model/Typesystem.hpp
@@ -432,7 +432,7 @@ private:
* Reference to the parent structure type (or nullptr if the struct type is
* not derived from any other struct type).
*/
- const Owned<StructType> parent;
+ const Owned<StructType> parentStructure;
/**
* Vector containing references to all attribute descriptors.
@@ -530,15 +530,16 @@ private:
* @param name is the name of the EnumType instance. Should be a valid
* identifier.
* @param system is a reference to the parent Typesystem instance.
- * @param parent is a reference to the StructType this type is derived from,
- * may be nullptr.
+ * @param parentStructure is a reference to the StructType this type is
+ * derived from, may be nullptr.
* @param attributes is a vector containing the struct type attributes.
*/
StructType(Manager &mgr, std::string name, Handle<Typesystem> system,
- Handle<StructType> parent, NodeVector<Attribute> attributes,
+ Handle<StructType> parentStructure,
+ NodeVector<Attribute> attributes,
std::map<std::string, size_t> attributeNames)
: Type(mgr, std::move(name), system, false),
- parent(acquire(parent)),
+ parentStructure(acquire(parentStructure)),
attributes(this, std::move(attributes)),
attributeNames(std::move(attributeNames))
{
@@ -569,18 +570,17 @@ public:
* @param name is the name of the EnumType instance. Should be a valid
* identifier.
* @param system is a reference to the parent Typesystem instance.
- * @param parent is a reference to the StructType this type is derived from,
- * may be nullptr.
+ * @param parentStructure is a reference to the StructType this type is
+ * derived from, may be nullptr.
* @param attributes is a vector containing the struct type attributes.
* The attributes are checked for validity (their names must be a valid
* identifiers) and uniqueness (each value must exist exactly once).
* @param logger is the Logger instance into which errors should be written.
*/
- static Rooted<StructType> createValidated(Manager &mgr, std::string name,
- Handle<Typesystem> system,
- Handle<StructType> parent,
- NodeVector<Attribute> attributes,
- Logger &logger);
+ static Rooted<StructType> createValidated(
+ Manager &mgr, std::string name, Handle<Typesystem> system,
+ Handle<StructType> parentStructure, NodeVector<Attribute> attributes,
+ Logger &logger);
/**
* Creates a Variant containing a valid representation of a data instance of
@@ -618,7 +618,14 @@ public:
* @return a rooted handle pointing at the parent type or nullptr, if this
* struct type has no parent.
*/
- Rooted<StructType> getParent() const { return parent; }
+ Rooted<StructType> getParentStructure() const { return parentStructure; }
+
+ /**
+ * Returns a reference at the list containing all attributes.
+ *
+ * @return a const reference pointing at the attribute list.
+ */
+ const NodeVector<Attribute> &getAttributes() const { return attributes; }
/**
* Returns the index of the given attribute in a data array representing
@@ -973,7 +980,6 @@ extern const Rtti<model::Typesystem> Typesystem;
* Type information for the SystemTypesystem class.
*/
extern const Rtti<model::SystemTypesystem> SystemTypesystem;
-
}
}
diff --git a/test/core/managed/ManagerTest.cpp b/test/core/managed/ManagerTest.cpp
index d7c0c17..3d09fa1 100644
--- a/test/core/managed/ManagerTest.cpp
+++ b/test/core/managed/ManagerTest.cpp
@@ -503,13 +503,14 @@ TEST(Manager, fullyConnectedGraph)
constexpr int nElem = 64;
std::array<bool, nElem> a;
- Manager mgr(1);
+ Manager mgr;
{
Rooted<TestManaged> n = createFullyConnectedGraph(mgr, nElem, &a[0]);
for (bool v : a) {
ASSERT_TRUE(v);
}
}
+ mgr.sweep();
for (bool v : a) {
ASSERT_FALSE(v);
diff --git a/test/core/model/DomainTest.cpp b/test/core/model/DomainTest.cpp
index f937842..9cd5bec 100644
--- a/test/core/model/DomainTest.cpp
+++ b/test/core/model/DomainTest.cpp
@@ -28,19 +28,14 @@
namespace ousia {
namespace model {
-void assert_path(std::vector<Rooted<Managed>> &result, size_t idx,
- const RttiBase &expected_type,
+void assert_path(const ResolutionResult &res, const RttiBase &expected_type,
std::vector<std::string> expected_path)
{
- ASSERT_TRUE(result.size() > idx);
- // check class/type
- ASSERT_TRUE(result[idx]->isa(expected_type));
- // cast to node
- Rooted<Node> n = result[idx].cast<Node>();
- // extract actual path
- std::vector<std::string> actual_path = n->path();
- // check path
- ASSERT_EQ(expected_path, actual_path);
+ // Check class/type
+ ASSERT_TRUE(res.node->isa(expected_type));
+
+ // Check path
+ ASSERT_EQ(expected_path, res.node->path());
}
TEST(Domain, testDomainResolving)
@@ -52,43 +47,38 @@ TEST(Domain, testDomainResolving)
// Get the domain.
Rooted<Domain> domain = constructBookDomain(mgr, sys, logger);
- /*
- * Start with the "book" search keyword. This should resolve to the domain
- * itself (because it is called "book"), as well as the structure "book"
- * node.
- */
- std::vector<Rooted<Managed>> res =
- domain->resolve(std::vector<std::string>{"book"});
+ std::vector<ResolutionResult> res;
+
+ // There is one domain called "book"
+ res = domain->resolve("book", typeOf<Domain>());
+ ASSERT_EQ(1U, res.size());
+ assert_path(res[0], typeOf<Domain>(), {"book"});
- // First we expect the book domain.
- assert_path(res, 0, typeOf<Domain>(), {"book"});
- // Then the book structure.
- assert_path(res, 1, typeOf<StructuredClass>(), {"book", "book"});
- ASSERT_EQ(2, res.size());
+ // There is one domain called "book"
+ res = domain->resolve("book", typeOf<StructuredClass>());
+ ASSERT_EQ(1U, res.size());
+ assert_path(res[0], typeOf<StructuredClass>(), {"book", "book"});
// If we explicitly ask for the "book, book" path, then only the
// StructuredClass should be returned.
- res = domain->resolve(std::vector<std::string>{"book", "book"});
- assert_path(res, 0, typeOf<StructuredClass>(), {"book", "book"});
- ASSERT_EQ(1, res.size());
+ res = domain->resolve(std::vector<std::string>{"book", "book"},
+ typeOf<Domain>());
+ ASSERT_EQ(0U, res.size());
+
+ res = domain->resolve(std::vector<std::string>{"book", "book"},
+ typeOf<StructuredClass>());
+ ASSERT_EQ(1U, res.size());
// If we ask for "section" the result should be unique as well.
- res = domain->resolve(std::vector<std::string>{"section"});
- // TODO: Is that the path result we want?
- assert_path(res, 0, typeOf<StructuredClass>(), {"book", "section"});
- ASSERT_EQ(1, res.size());
-
- // If we ask for the path "book", "book", "" we reference the
- // FieldDescriptor of the StructuredClass "book".
- res = domain->resolve(std::vector<std::string>{"book", "book", ""});
- assert_path(res, 0, typeOf<FieldDescriptor>(), {"book", "book", ""});
- ASSERT_EQ(1, res.size());
-
- // If we ask for "paragraph" it is references two times in the Domain graph,
+ res = domain->resolve("section", typeOf<StructuredClass>());
+ ASSERT_EQ(1U, res.size());
+ assert_path(res[0], typeOf<StructuredClass>(), {"book", "section"});
+
+ // If we ask for "paragraph" it is referenced two times in the Domain graph,
// but should be returned only once.
- res = domain->resolve("paragraph");
- assert_path(res, 0, typeOf<StructuredClass>(), {"book", "paragraph"});
- ASSERT_EQ(1, res.size());
+ res = domain->resolve("paragraph", typeOf<StructuredClass>());
+ ASSERT_EQ(1U, res.size());
+ assert_path(res[0], typeOf<StructuredClass>(), {"book", "paragraph"});
}
}
}
diff --git a/test/core/model/NodeTest.cpp b/test/core/model/NodeTest.cpp
index 1c58e2c..334a311 100644
--- a/test/core/model/NodeTest.cpp
+++ b/test/core/model/NodeTest.cpp
@@ -22,20 +22,15 @@
#include <core/model/Node.hpp>
namespace ousia {
-namespace dom {
class TestNode : public Node {
private:
std::vector<Owned<Node>> children;
protected:
- void doResolve(std::vector<Rooted<Managed>> &res,
- const std::vector<std::string> &path, Filter filter,
- void *filterData, unsigned idx, VisitorSet &visited) override
+ void continueResolve(ResolutionState &state) override
{
- for (auto &n : children) {
- n->resolve(res, path, filter, filterData, idx, visited, nullptr);
- }
+ continueResolveComposita(children, state);
}
public:
@@ -49,6 +44,11 @@ public:
}
};
+namespace RttiTypes {
+const Rtti<ousia::TestNode> TestNode =
+ RttiBuilder("TestNode").parent(RttiTypes::Node).composedOf(&TestNode);
+}
+
TEST(Node, isRoot)
{
Manager mgr;
@@ -72,19 +72,21 @@ TEST(Node, simpleResolve)
Rooted<TestNode> child1 = root->addChild(new TestNode(mgr, "child1"));
Rooted<TestNode> child11 = child1->addChild(new TestNode(mgr, "child11"));
- std::vector<Rooted<Managed>> res;
- res = root->resolve(std::vector<std::string>{"root", "child1", "child11"});
- ASSERT_EQ(1, res.size());
- ASSERT_TRUE(child11 == *(res.begin()));
-
- res = root->resolve(std::vector<std::string>{"child1", "child11"});
- ASSERT_EQ(1, res.size());
- ASSERT_TRUE(child11 == *(res.begin()));
-
- res = root->resolve(std::vector<std::string>{"child11"});
- ASSERT_EQ(1, res.size());
- ASSERT_TRUE(child11 == *(res.begin()));
+ std::vector<ResolutionResult> res;
+ res = root->resolve(std::vector<std::string>{"root", "child1", "child11"},
+ RttiTypes::TestNode);
+ ASSERT_EQ(1U, res.size());
+ ASSERT_TRUE(child11 == res[0].node);
+
+ res = root->resolve(std::vector<std::string>{"child1", "child11"},
+ RttiTypes::TestNode);
+ ASSERT_EQ(1U, res.size());
+ ASSERT_TRUE(child11 == res[0].node);
+
+ res =
+ root->resolve(std::vector<std::string>{"child11"}, RttiTypes::TestNode);
+ ASSERT_EQ(1U, res.size());
+ ASSERT_TRUE(child11 == res[0].node);
}
}
-}