summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/model/Node.cpp98
-rw-r--r--test/core/model/NodeTest.cpp173
2 files changed, 215 insertions, 56 deletions
diff --git a/src/core/model/Node.cpp b/src/core/model/Node.cpp
index d12e92b..930fbff 100644
--- a/src/core/model/Node.cpp
+++ b/src/core/model/Node.cpp
@@ -102,57 +102,52 @@ public:
* 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, bool atStartNode = true)
- : shared(shared),
- idx(0),
- resolutionRoot(resolutionRoot),
- atStartNode(atStartNode)
- {
- }
-
- /**
* Reference at the resolution state that is shared between the various
* resolution paths.
*/
SharedResolutionState &shared;
/**
+ * Current resolution root node or nullptr if no resolution root node has
+ * been set yet.
+ */
+ Node *resolutionRoot;
+
+ /**
* Current index within the given path.
*/
int idx;
/**
- * Current resolution root node or nullptr if no resolution root node has
- * been set yet.
+ * Set to true if the resolution currently is in the subtree in which the
+ * node resolution process was started (no reference boundary has been
+ * passed yet).
*/
- Node *resolutionRoot;
+ bool inStartTree;
/**
- * Set to true if the resolution currently is at the node at which the
- * resolution process was started.
+ * Set to true, once a compositum has been found.
*/
- bool atStartNode;
+ bool foundCompositum;
+
+ /**
+ * 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, int idx = 0,
+ bool inStartTree = true)
+ : shared(shared),
+ resolutionRoot(resolutionRoot),
+ idx(idx),
+ inStartTree(inStartTree),
+ foundCompositum(false)
+ {
+ }
/**
* Adds a node to the result.
@@ -193,21 +188,31 @@ public:
*/
bool typeMatches(const RttiBase &type) { return type.isa(shared.type); }
+ bool canContainType(const RttiBase &type)
+ {
+ return type.composedOf(shared.type);
+ }
+
const std::string &currentName() { return shared.path[idx]; }
ResolutionState advance()
{
- return ResolutionState{shared, idx + 1, resolutionRoot};
+ return ResolutionState{shared, resolutionRoot, idx + 1, false};
}
ResolutionState fork(Node *newResolutionRoot)
{
- return ResolutionState{shared, newResolutionRoot, false};
+ return ResolutionState{shared, newResolutionRoot, 0, false};
}
- bool canFollowReferences() { return idx == 0 && atStartNode; }
+ bool canFollowReferences()
+ {
+ return idx == 0 && inStartTree && !foundCompositum;
+ }
bool canFollowComposita() { return idx == 0; }
+
+ size_t resultCount() { return shared.result.size(); }
};
/* Class Node */
@@ -249,7 +254,8 @@ bool Node::resolve(ResolutionState &state)
{
// Try to mark this note as visited, do nothing if already has been visited
if (state.markVisited(this)) {
- std::cout << "visiting " << name << std::endl;
+ std::cout << "visiting " << name << " (" << state.idx << ")"
+ << std::endl;
// Add this node to the result if it matches the current description
if (state.atEndOfPath()) {
@@ -259,7 +265,9 @@ bool Node::resolve(ResolutionState &state)
return true;
}
} else {
+ size_t resCount = state.resultCount();
continueResolve(state);
+ return state.resultCount() > resCount;
}
}
return false;
@@ -275,7 +283,10 @@ 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);
+ if (h->resolve(advancedState)) {
+ state.foundCompositum = true;
+ return true;
+ }
}
return false;
}
@@ -287,6 +298,7 @@ bool Node::continueResolveCompositum(Handle<Node> h, ResolutionState &state)
if (h->getName() == state.currentName()) {
ResolutionState advancedState = state.advance();
if (h->resolve(advancedState)) {
+ state.foundCompositum = true;
return true;
}
}
@@ -302,8 +314,10 @@ bool Node::continueResolveCompositum(Handle<Node> h, ResolutionState &state)
bool Node::continueResolveReference(Handle<Node> h, ResolutionState &state)
{
// We can only follow references if we currently are at the beginning of the
- // path and this node is the root node
- if (canFollowReferences(state)) {
+ // path and this node is the root node. Additionally only follow a reference
+ // if the node the reference points to is known to contain the type that is
+ // currently asked for in the resolution process
+ if (canFollowReferences(state) && state.canContainType(h->type())) {
std::cout << "following reference to " << h->getName() << std::endl;
ResolutionState forkedState = state.fork(this);
return continueResolveCompositum(h, forkedState);
@@ -321,7 +335,7 @@ std::vector<ResolutionResult> Node::resolve(
// Kickstart the resolution process by treating this very node as compositum
std::cout << "------------" << std::endl;
std::cout << "resolving: ";
- for (auto s: path) {
+ for (auto s : path) {
std::cout << s << " ";
}
std::cout << " of type " << type.name << std::endl;
diff --git a/test/core/model/NodeTest.cpp b/test/core/model/NodeTest.cpp
index 334a311..880ce33 100644
--- a/test/core/model/NodeTest.cpp
+++ b/test/core/model/NodeTest.cpp
@@ -24,23 +24,35 @@
namespace ousia {
class TestNode : public Node {
-private:
- std::vector<Owned<Node>> children;
-
protected:
void continueResolve(ResolutionState &state) override
{
- continueResolveComposita(children, state);
+ continueResolveComposita(composita, composita.getIndex(), state);
+ continueResolveReferences(references, state);
}
public:
- using Node::Node;
+ NodeVector<TestNode> composita;
+ NodeVector<TestNode> references;
- Rooted<TestNode> addChild(Handle<TestNode> node)
+ TestNode(Manager &mgr, Handle<Node> parent = nullptr)
+ : Node(mgr, parent), composita(this), references(this)
{
- Owned<TestNode> nd = acquire(node);
- children.push_back(nd);
- return nd;
+ }
+
+ TestNode(Manager &mgr, std::string name, Handle<Node> parent = nullptr)
+ : Node(mgr, name, parent), composita(this), references(this)
+ {
+ }
+
+ Rooted<TestNode> addCompositum(Handle<TestNode> n) {
+ composita.push_back(n);
+ return n;
+ }
+
+ Rooted<TestNode> addReference(Handle<TestNode> n) {
+ references.push_back(n);
+ return n;
}
};
@@ -51,7 +63,7 @@ const Rtti<ousia::TestNode> TestNode =
TEST(Node, isRoot)
{
- Manager mgr;
+ Manager mgr{1};
Rooted<TestNode> n1{new TestNode(mgr)};
Rooted<TestNode> n2{new TestNode(mgr)};
Rooted<TestNode> n3{new TestNode(mgr, n2)};
@@ -65,12 +77,37 @@ TEST(Node, isRoot)
ASSERT_FALSE(n3->isRoot());
}
-TEST(Node, simpleResolve)
+TEST(Node, resolveCompositaSimple)
+{
+ Manager mgr{1};
+ Rooted<TestNode> root{new TestNode(mgr, "root")};
+ Rooted<TestNode> child1 = root->addCompositum(new TestNode(mgr, "child1"));
+ Rooted<TestNode> child11 = child1->addCompositum(new TestNode(mgr, "child11"));
+
+ 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);
+}
+
+TEST(Node, resolveCompositaDouble)
{
- Manager mgr;
+ Manager mgr{1};
Rooted<TestNode> root{new TestNode(mgr, "root")};
- Rooted<TestNode> child1 = root->addChild(new TestNode(mgr, "child1"));
- Rooted<TestNode> child11 = child1->addChild(new TestNode(mgr, "child11"));
+ Rooted<TestNode> root2 = root->addCompositum(new TestNode(mgr, "root"));
+ Rooted<TestNode> child1 = root2->addCompositum(new TestNode(mgr, "child1"));
+ Rooted<TestNode> child11 = child1->addCompositum(new TestNode(mgr, "child11"));
std::vector<ResolutionResult> res;
res = root->resolve(std::vector<std::string>{"root", "child1", "child11"},
@@ -89,4 +126,112 @@ TEST(Node, simpleResolve)
ASSERT_TRUE(child11 == res[0].node);
}
+TEST(Node, resolveAmbigousComposita)
+{
+ Manager mgr{1};
+ Rooted<TestNode> root{new TestNode(mgr, "root")};
+ Rooted<TestNode> a = root->addCompositum(new TestNode(mgr, "a"));
+ Rooted<TestNode> b = root->addCompositum(new TestNode(mgr, "b"));
+ Rooted<TestNode> child1 = a->addCompositum(new TestNode(mgr, "child1"));
+ Rooted<TestNode> child11 = child1->addCompositum(new TestNode(mgr, "child11"));
+ Rooted<TestNode> child12 = b->addCompositum(new TestNode(mgr, "child1"));
+ Rooted<TestNode> child112 = child12->addCompositum(new TestNode(mgr, "child11"));
+
+ std::vector<ResolutionResult> res;
+ res = root->resolve(std::vector<std::string>{"child1", "child11"},
+ RttiTypes::TestNode);
+ ASSERT_EQ(2U, res.size());
+ ASSERT_TRUE(child11 == res[0].node || child11 == res[1].node);
+ ASSERT_TRUE(child112 == res[0].node || child112 == res[1].node);
+
+ res =
+ root->resolve(std::vector<std::string>{"child11"}, RttiTypes::TestNode);
+ ASSERT_EQ(2U, res.size());
+ ASSERT_TRUE(child11 == res[0].node || child11 == res[1].node);
+ ASSERT_TRUE(child112 == res[0].node || child112 == res[1].node);
+}
+
+TEST(Node, resolveReferences)
+{
+ Manager mgr{1};
+ Rooted<TestNode> root{new TestNode(mgr, "root")};
+ Rooted<TestNode> a = root->addReference(new TestNode(mgr, "a"));
+ Rooted<TestNode> b = root->addReference(new TestNode(mgr, "b"));
+ Rooted<TestNode> child1 = a->addCompositum(new TestNode(mgr, "child1"));
+ Rooted<TestNode> child11 = child1->addCompositum(new TestNode(mgr, "child11"));
+ Rooted<TestNode> child12 = b->addCompositum(new TestNode(mgr, "child1"));
+ Rooted<TestNode> child112 = child12->addCompositum(new TestNode(mgr, "child11"));
+
+ std::vector<ResolutionResult> res;
+ res = root->resolve(std::vector<std::string>{"a", "child1", "child11"},
+ RttiTypes::TestNode);
+ ASSERT_EQ(1U, res.size());
+ ASSERT_TRUE(child11 == res[0].node);
+
+ res = root->resolve(std::vector<std::string>{"b", "child1", "child11"},
+ RttiTypes::TestNode);
+ ASSERT_EQ(1U, res.size());
+ ASSERT_TRUE(child112 == res[0].node);
+
+ res = root->resolve(std::vector<std::string>{"child1", "child11"},
+ RttiTypes::TestNode);
+ ASSERT_EQ(2U, res.size());
+ ASSERT_TRUE(child11 == res[0].node || child11 == res[1].node);
+ ASSERT_TRUE(child112 == res[0].node || child112 == res[1].node);
+
+ res =
+ root->resolve(std::vector<std::string>{"child11"}, RttiTypes::TestNode);
+ ASSERT_EQ(2U, res.size());
+ ASSERT_TRUE(child11 == res[0].node || child11 == res[1].node);
+ ASSERT_TRUE(child112 == res[0].node || child112 == res[1].node);
+
+ res =
+ root->resolve(std::vector<std::string>{"child1"}, RttiTypes::TestNode);
+ ASSERT_EQ(2U, res.size());
+ ASSERT_TRUE(child1 == res[0].node || child1 == res[1].node);
+ ASSERT_TRUE(child12 == res[0].node || child12 == res[1].node);
+}
+
+TEST(Node, resolveReferencesAndComposita)
+{
+ Manager mgr{1};
+ Rooted<TestNode> root{new TestNode(mgr, "root")};
+ Rooted<TestNode> a = root->addReference(new TestNode(mgr, "a"));
+ Rooted<TestNode> b = root->addReference(new TestNode(mgr, "b"));
+ Rooted<TestNode> child1 = a->addCompositum(new TestNode(mgr, "child1"));
+ Rooted<TestNode> child11 = child1->addCompositum(new TestNode(mgr, "child11"));
+ Rooted<TestNode> child12 = b->addCompositum(new TestNode(mgr, "child1"));
+ Rooted<TestNode> child112 = child12->addCompositum(new TestNode(mgr, "child11"));
+ Rooted<TestNode> child13 = root->addCompositum(new TestNode(mgr, "child1"));
+
+ std::vector<ResolutionResult> res;
+ res = root->resolve(std::vector<std::string>{"a", "child1", "child11"},
+ RttiTypes::TestNode);
+ ASSERT_EQ(1U, res.size());
+ ASSERT_TRUE(child11 == res[0].node);
+
+ res = root->resolve(std::vector<std::string>{"b", "child1", "child11"},
+ RttiTypes::TestNode);
+ ASSERT_EQ(1U, res.size());
+ ASSERT_TRUE(child112 == res[0].node);
+
+ res = root->resolve(std::vector<std::string>{"child1", "child11"},
+ RttiTypes::TestNode);
+ ASSERT_EQ(2U, res.size());
+ ASSERT_TRUE(child11 == res[0].node || child11 == res[1].node);
+ ASSERT_TRUE(child112 == res[0].node || child112 == res[1].node);
+
+ res =
+ root->resolve(std::vector<std::string>{"child11"}, RttiTypes::TestNode);
+ ASSERT_EQ(2U, res.size());
+ ASSERT_TRUE(child11 == res[0].node || child11 == res[1].node);
+ ASSERT_TRUE(child112 == res[0].node || child112 == res[1].node);
+
+ // Resolving for "child1" should not descend into the referenced nodes
+ res =
+ root->resolve(std::vector<std::string>{"child1"}, RttiTypes::TestNode);
+ ASSERT_EQ(1U, res.size());
+ ASSERT_TRUE(child13 == res[0].node);
+}
+
}