From e2f008689e9199c43757ca095fbe1623088e0c1e Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Tue, 3 Mar 2015 19:07:26 +0100 Subject: fixed a bug in addStructureNode. Document as parent was not properly considered. --- src/core/model/Document.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/core') diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp index 62dad11..1e1620d 100644 --- a/src/core/model/Document.cpp +++ b/src/core/model/Document.cpp @@ -328,8 +328,10 @@ void DocumentEntity::addStructureNode(Handle s, const size_t &i) if (par != nullptr) { if (par->isa(&RttiTypes::StructuredEntity)) { par.cast()->removeStructureNode(s); - } else { + } else if(par->isa(&RttiTypes::AnnotationEntity)){ par.cast()->removeStructureNode(s); + } else if(par->isa(&RttiTypes::Document)){ + par.cast()->setRoot(nullptr); } } s->setParent(subInst); -- cgit v1.2.3 From 68c66558cd7c8e64dd0d3b934ccb58603f8b9836 Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Tue, 3 Mar 2015 19:07:48 +0100 Subject: prevented cycles in DocumentEntity::searchStartAnchor --- src/core/model/Document.cpp | 31 +++++++++++++++++++++---------- src/core/model/Document.hpp | 20 +++++++++++--------- test/core/model/DocumentTest.cpp | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 19 deletions(-) (limited to 'src/core') diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp index 1e1620d..1fd429b 100644 --- a/src/core/model/Document.cpp +++ b/src/core/model/Document.cpp @@ -466,7 +466,7 @@ static bool matchStartAnchor(Handle desc, template Rooted DocumentEntity::searchStartAnchorInField( Handle desc, const std::string &name, Iterator begin, - Iterator end) + Iterator end, std::unordered_set &visited) { for (Iterator it = begin; it != end; it++) { Handle strct = *it; @@ -481,7 +481,7 @@ Rooted DocumentEntity::searchStartAnchorInField( // search downwards. Rooted a = strct.cast()->searchStartAnchorDownwards( - desc, name); + desc, name, visited); if (a != nullptr) { return a; } @@ -491,8 +491,12 @@ Rooted DocumentEntity::searchStartAnchorInField( } Rooted DocumentEntity::searchStartAnchorDownwards( - Handle desc, const std::string &name) + Handle desc, const std::string &name, + std::unordered_set &visited) { + if (!visited.insert(this).second) { + return nullptr; + } if (fields.empty()) { return nullptr; } @@ -500,13 +504,17 @@ Rooted DocumentEntity::searchStartAnchorDownwards( NodeVector children = fields[fields.size() - 1]; // search it from back to front. return searchStartAnchorInField(desc, name, children.rbegin(), - children.rend()); + children.rend(), visited); } Rooted DocumentEntity::searchStartAnchorUpwards( Handle desc, const std::string &name, - const DocumentEntity *child) + const DocumentEntity *child, + std::unordered_set &visited) { + if (!visited.insert(this).second) { + return nullptr; + } if (fields.empty()) { return nullptr; } @@ -522,7 +530,8 @@ Rooted DocumentEntity::searchStartAnchorUpwards( // to the child. if (it != children.rend()) { it++; - return searchStartAnchorInField(desc, name, it, children.rend()); + return searchStartAnchorInField(desc, name, it, children.rend(), + visited); } throw OusiaException("Internal error: Child node not found in parent!"); } @@ -531,11 +540,13 @@ Rooted DocumentEntity::searchStartAnchor(size_t fieldIdx, Handle desc, const std::string &name) { + std::unordered_set visited; + visited.insert(this); // get the correct field. NodeVector children = fields[fieldIdx]; // search it from back to front. Rooted a = searchStartAnchorInField(desc, name, children.rbegin(), - children.rend()); + children.rend(), visited); // if we found the Anchor, return it. if (a != nullptr) { return a; @@ -551,11 +562,11 @@ Rooted DocumentEntity::searchStartAnchor(size_t fieldIdx, if (subInst->getParent()->isa(&RttiTypes::StructuredEntity)) { return subInst->getParent() .cast() - ->searchStartAnchorUpwards(desc, name, this); + ->searchStartAnchorUpwards(desc, name, this, visited); } if (subInst->getParent()->isa(&RttiTypes::AnnotationEntity)) { subInst->getParent().cast()->searchStartAnchorUpwards( - desc, name, this); + desc, name, this, visited); } return nullptr; } @@ -987,4 +998,4 @@ const Rtti AnnotationEntity = .parent(&Node) .composedOf({&StructuredEntity, &DocumentPrimitive, &Anchor}); } -} +} \ No newline at end of file diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp index 81e2f41..2f82127 100644 --- a/src/core/model/Document.hpp +++ b/src/core/model/Document.hpp @@ -157,16 +157,18 @@ private: void invalidateSubInstance(); template - Rooted searchStartAnchorInField(Handle desc, - const std::string &name, - Iterator begin, Iterator end); + Rooted searchStartAnchorInField( + Handle desc, const std::string &name, Iterator begin, + Iterator end, std::unordered_set &visited); - Rooted searchStartAnchorDownwards(Handle desc, - const std::string &name); + Rooted searchStartAnchorDownwards( + Handle desc, const std::string &name, + std::unordered_set &visited); - Rooted searchStartAnchorUpwards(Handle desc, - const std::string &name, - const DocumentEntity *child); + Rooted searchStartAnchorUpwards( + Handle desc, const std::string &name, + const DocumentEntity *child, + std::unordered_set &visited); protected: bool doValidate(Logger &logger) const; @@ -1090,4 +1092,4 @@ extern const Rtti Anchor; } } -#endif /* _OUSIA_MODEL_DOCUMENT_HPP_ */ +#endif /* _OUSIA_MODEL_DOCUMENT_HPP_ */ \ No newline at end of file diff --git a/test/core/model/DocumentTest.cpp b/test/core/model/DocumentTest.cpp index 9362af8..8ae9475 100644 --- a/test/core/model/DocumentTest.cpp +++ b/test/core/model/DocumentTest.cpp @@ -75,6 +75,41 @@ TEST(DocumentEntity, searchStartAnchor) ASSERT_EQ(b, root->searchStartAnchor(0, Alpha, "myAnno")); } + +TEST(DocumentEntity, searchStartAnchorCycles) +{ + // create a trivial ontology. + Logger logger; + Manager mgr{1}; + Rooted sys{new SystemTypesystem(mgr)}; + Rooted ontology{new Ontology(mgr, sys, "trivial")}; + // we only have one StructuredClass that may have itself as a child. + Rooted A = ontology->createStructuredClass( + "A", Cardinality::any(), nullptr, false, true); + Rooted A_field = A->createFieldDescriptor(logger).first; + A_field->addChild(A); + // create an AnnotationClass. + Rooted Alpha = ontology->createAnnotationClass("Alpha"); + // validate this ontology. + ASSERT_TRUE(ontology->validate(logger)); + + // create a trivial but cyclic document. + Rooted doc{new Document(mgr, "myDoc")}; + Rooted root = doc->createRootStructuredEntity(A); + // add an Anchor. + Rooted a = root->createChildAnchor(); + // create an AnnotationEntity with the Anchor as start. + doc->createChildAnnotation(Alpha, a, nullptr, Variant::mapType{}, "myAnno"); + // add the cyclic reference. + root->addStructureNode(root, 0); + // We should be able to find the Anchor now if we look for it. There should + // be no loops. + ASSERT_EQ(a, root->searchStartAnchor(0)); + ASSERT_EQ(a, root->searchStartAnchor(0, Alpha)); + ASSERT_EQ(a, root->searchStartAnchor(0, nullptr, "myAnno")); + ASSERT_EQ(a, root->searchStartAnchor(0, Alpha, "myAnno")); +} + TEST(DocumentEntity, searchStartAnchorUpwards) { // create a trivial ontology. -- cgit v1.2.3