diff options
-rw-r--r-- | src/core/model/Document.cpp | 26 | ||||
-rw-r--r-- | src/core/model/Document.hpp | 30 | ||||
-rw-r--r-- | src/core/model/Domain.cpp | 117 | ||||
-rw-r--r-- | src/core/model/Domain.hpp | 99 | ||||
-rw-r--r-- | test/core/model/DomainTest.cpp | 36 | ||||
-rw-r--r-- | test/core/model/TestAdvanced.hpp | 24 | ||||
-rw-r--r-- | test/core/model/TestDocumentBuilder.hpp | 2 | ||||
-rw-r--r-- | test/core/model/TestDomain.hpp | 17 |
8 files changed, 197 insertions, 154 deletions
diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp index 022b91c..eca24e7 100644 --- a/src/core/model/Document.cpp +++ b/src/core/model/Document.cpp @@ -58,7 +58,8 @@ int DocumentEntity::getFieldDescriptorIndex(const std::string &fieldName, } } if (enforce) { - throw OusiaException("No field for the given name exists!"); + throw OusiaException(descriptor->getName() + + " has no field with name " + fieldName); } else { return -1; } @@ -80,15 +81,27 @@ int DocumentEntity::getFieldDescriptorIndex( f++; } if (enforce) { - throw OusiaException( - "The given FieldDescriptor is not specified in the Descriptor of " - "this " - "node."); + throw OusiaException(descriptor->getName() + + " has no field with name " + + fieldDescriptor->getName()); } else { return -1; } } +/* Class AnnotationEntity */ + +AnnotationEntity::AnnotationEntity(Manager &mgr, Handle<Document> parent, + Handle<AnnotationClass> descriptor, Handle<Anchor> start, + Handle<Anchor> end, Variant attributes, std::string name) + : Node(mgr, std::move(name), parent), + DocumentEntity(this, descriptor, attributes), + start(acquire(start)), + end(acquire(end)) +{ + parent->annotations.push_back(this); +} + /* Class Document */ void Document::continueResolve(ResolutionState &state) @@ -109,8 +122,7 @@ const Rtti<model::Document> Document = const Rtti<model::StructureNode> StructureNode = RttiBuilder("StructureNode").parent(&Node); const Rtti<model::AnnotationEntity> AnnotationEntity = - RttiBuilder("AnnotationEntity").parent(&Node).composedOf( - &StructureNode); + RttiBuilder("AnnotationEntity").parent(&Node).composedOf(&StructureNode); const Rtti<model::StructuredEntity> StructuredEntity = RttiBuilder("StructuredEntity").parent(&StructureNode).composedOf( {&StructureNode}); diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp index 357b752..15a5ec8 100644 --- a/src/core/model/Document.hpp +++ b/src/core/model/Document.hpp @@ -427,7 +427,9 @@ public: * The constructor for an AnnotationEntity. * * @param mgr is the Manager instance. - * @param parent is the Document this AnnotationEntity is part of. + * @param parent is the Document this AnnotationEntity is part of. The + * constructor will automatically register this + * AnnotationEntity at that document. * @param descriptor is the AnnotationClass of this AnnotationEntity. * @param start is the start Anchor of this AnnotationEntity. It has to * be part of the Document given as parent. @@ -441,13 +443,7 @@ public: AnnotationEntity(Manager &mgr, Handle<Document> parent, Handle<AnnotationClass> descriptor, Handle<Anchor> start, Handle<Anchor> end, Variant attributes = {}, - std::string name = "") - : Node(mgr, std::move(name), parent), - DocumentEntity(this, descriptor, attributes), - start(acquire(start)), - end(acquire(end)) - { - } + std::string name = ""); /** * Returns the start Anchor of this AnnotationEntity. @@ -470,6 +466,9 @@ public: * document and the AnnotationEntities that span over Anchors in this Document. */ class Document : public Node { + +friend AnnotationEntity; + private: // TODO: Might there be several roots? E.g. metadata? Owned<StructuredEntity> root; @@ -511,21 +510,6 @@ public: } /** - * Adds an AnnotationEntity to this document. The Anchors used as start and - * end of this AnnotationEntity have to be part of this document. - */ - void addAnnotation(Handle<AnnotationEntity> a) { annotations.push_back(a); } - /** - * Adds multiple AnnotationEntities to this document. The Anchors used as - * start and end of these AnnotationEntities have to be part of this - * document. - */ - void addAnnotations(const std::vector<Handle<AnnotationEntity>> &as) - { - annotations.insert(annotations.end(), as.begin(), as.end()); - } - - /** * Returns a const reference to the NodeVector of Domains that are used * within this Document. * diff --git a/src/core/model/Domain.cpp b/src/core/model/Domain.cpp index be9aa05..f1b91cc 100644 --- a/src/core/model/Domain.cpp +++ b/src/core/model/Domain.cpp @@ -26,8 +26,48 @@ namespace ousia { namespace model { +template <class T> +static void checkUniqueName(Handle<Node> parent, NodeVector<T> vec, + Handle<T> child, + const std::string &parentClassName, + const std::string &childClassName) +{ + std::set<std::string> childNames; + for (auto &c : vec) { + childNames.insert(c->getName()); + } + if (childNames.find(child->getName()) != childNames.end()) { + throw OusiaException(std::string("The ") + parentClassName + " " + + parent->getName() + " already has a " + + childClassName + " with name " + child->getName()); + } +} + /* Class FieldDescriptor */ +FieldDescriptor::FieldDescriptor(Manager &mgr, Handle<Descriptor> parent, + Handle<Type> primitiveType, std::string name, + bool optional) + : Node(mgr, std::move(name), parent), + children(this), + fieldType(FieldType::PRIMITIVE), + primitiveType(acquire(primitiveType)), + optional(optional) +{ + parent->addFieldDescriptor(this); +} + +FieldDescriptor::FieldDescriptor(Manager &mgr, Handle<Descriptor> parent, + FieldType fieldType, std::string name, + bool optional) + : Node(mgr, std::move(name), parent), + children(this), + fieldType(fieldType), + optional(optional) +{ + parent->addFieldDescriptor(this); +} + /* Class Descriptor */ void Descriptor::continueResolve(ResolutionState &state) @@ -41,6 +81,13 @@ void Descriptor::continueResolve(ResolutionState &state) state); } +void Descriptor::addFieldDescriptor(Handle<FieldDescriptor> fd) +{ + checkUniqueName(this, fieldDescriptors, fd, "Descriptor", + "FieldDescriptor"); + fieldDescriptors.push_back(fd); +} + std::vector<Rooted<Node>> Descriptor::pathTo( Handle<StructuredClass> target) const { @@ -111,8 +158,8 @@ bool Descriptor::continuePath(Handle<StructuredClass> target, if (isa(RttiTypes::StructuredClass)) { const StructuredClass *tis = static_cast<const StructuredClass *>(this); /* - * if this is a StructuredClass, we can also use the super class (at - * least for fields that are not overridden) + * if this is a StructuredClass, we can also use the super class + * (at least for fields that are not overridden) */ if (exploreSuperclass && !tis->getIsA().isNull()) { // copy the path. @@ -148,6 +195,60 @@ bool Descriptor::continuePath(Handle<StructuredClass> target, return found; } +void Descriptor::copyFieldDescriptor(Handle<FieldDescriptor> fd) +{ + if (fd->getFieldType() == FieldDescriptor::FieldType::PRIMITIVE) { + /* + *To call the "new" operation is enough here, because the + * constructor will add the newly constructed FieldDescriptor to this + * Descriptor automatically. + */ + new FieldDescriptor(getManager(), this, + fd->getPrimitiveType(), + fd->getName(), fd->optional); + } else { + new FieldDescriptor(getManager(), this, + fd->getFieldType(), + fd->getName(), fd->optional); + } +} + +/* Class StructuredClass */ + +StructuredClass::StructuredClass(Manager &mgr, std::string name, + Handle<Domain> domain, + const Cardinality &cardinality, + Handle<StructType> attributesDescriptor, + Handle<StructuredClass> isa, bool transparent, + bool root) + : Descriptor(mgr, std::move(name), domain, attributesDescriptor), + cardinality(cardinality), + isa(acquire(isa)), + subclasses(this), + transparent(transparent), + root(root) +{ + if (!isa.isNull()) { + isa->subclasses.push_back(this); + } + if (!domain.isNull()) { + domain->addStructuredClass(this); + } +} + +/* Class AnnotationClass */ + +AnnotationClass::AnnotationClass( + Manager &mgr, std::string name, Handle<Domain> domain, + // TODO: What would be a wise default value for attributes? + Handle<StructType> attributesDescriptor) + : Descriptor(mgr, std::move(name), domain, attributesDescriptor) +{ + if (!domain.isNull()) { + domain->addAnnotationClass(this); + } +} + /* Class Domain */ void Domain::continueResolve(ResolutionState &state) @@ -159,6 +260,18 @@ void Domain::continueResolve(ResolutionState &state) continueResolveReferences(typesystems, state); } } + +void Domain::addStructuredClass(Handle<StructuredClass> s) +{ + checkUniqueName(this, structuredClasses, s, "Domain", "StructuredClass"); + structuredClasses.push_back(s); +} + +void Domain::addAnnotationClass(Handle<AnnotationClass> a) +{ + checkUniqueName(this, annotationClasses, a, "Domain", "AnnotationClass"); + annotationClasses.push_back(a); +} } /* Type registrations */ diff --git a/src/core/model/Domain.hpp b/src/core/model/Domain.hpp index 4b26917..791d563 100644 --- a/src/core/model/Domain.hpp +++ b/src/core/model/Domain.hpp @@ -292,14 +292,7 @@ public: */ FieldDescriptor(Manager &mgr, Handle<Descriptor> parent, Handle<Type> primitiveType, std::string name = "", - bool optional = false) - : Node(mgr, std::move(name), parent), - children(this), - fieldType(FieldType::PRIMITIVE), - primitiveType(acquire(primitiveType)), - optional(optional) - { - } + bool optional = false); /** * This is the constructor for non-primitive fields. You have to provide @@ -318,13 +311,7 @@ public: */ FieldDescriptor(Manager &mgr, Handle<Descriptor> parent, FieldType fieldType = FieldType::TREE, - std::string name = "", bool optional = false) - : Node(mgr, std::move(name), parent), - children(this), - fieldType(fieldType), - optional(optional) - { - } + std::string name = "", bool optional = false); /** * Returns a const reference to the NodeVector of StructuredClasses whose @@ -389,6 +376,9 @@ public: * */ class Descriptor : public Node { + +friend FieldDescriptor; + private: Owned<StructType> attributesDescriptor; NodeVector<FieldDescriptor> fieldDescriptors; @@ -401,6 +391,11 @@ private: protected: void continueResolve(ResolutionState &state) override; + + /** + * Adds a FieldDescriptor and checks for name uniqueness. + */ + void addFieldDescriptor(Handle<FieldDescriptor> fd); public: Descriptor(Manager &mgr, std::string name, Handle<Domain> domain, @@ -436,20 +431,11 @@ public: } /** - * Adds a FieldDescriptor to this Descriptor. + * Copies a FieldDescriptor that belongs to another Descriptor to this + * Descriptor. This will throw an exception if a FieldDescriptor with the + * given name already exists. */ - void addFieldDescriptor(Handle<FieldDescriptor> fd) - { - fieldDescriptors.push_back(fd); - } - - /** - * Adds multiple FieldDescriptors to this Descriptor. - */ - void addFieldDescriptors(const std::vector<Handle<FieldDescriptor>> &fds) - { - fieldDescriptors.insert(fieldDescriptors.end(), fds.begin(), fds.end()); - } + void copyFieldDescriptor(Handle<FieldDescriptor> fd); /** * This tries to construct the shortest possible path of this Descriptor @@ -600,18 +586,7 @@ public: Handle<StructType> attributesDescriptor = nullptr, // TODO: What would be a wise default value for isa? Handle<StructuredClass> isa = nullptr, - bool transparent = false, bool root = false) - : Descriptor(mgr, std::move(name), domain, attributesDescriptor), - cardinality(cardinality), - isa(acquire(isa)), - subclasses(this), - transparent(transparent), - root(root) - { - if (!isa.isNull()) { - isa->subclasses.push_back(this); - } - } + bool transparent = false, bool root = false); /** * Returns the Cardinality of this StructuredClass (as a RangeSet). @@ -672,10 +647,7 @@ public: */ AnnotationClass(Manager &mgr, std::string name, Handle<Domain> domain, // TODO: What would be a wise default value for attributes? - Handle<StructType> attributesDescriptor) - : Descriptor(mgr, std::move(name), domain, attributesDescriptor) - { - } + Handle<StructType> attributesDescriptor = nullptr); }; /** @@ -684,6 +656,10 @@ public: * to certain Structures? */ class Domain : public Node { + +friend StructuredClass; +friend AnnotationClass; + private: NodeVector<StructuredClass> structuredClasses; NodeVector<AnnotationClass> annotationClasses; @@ -694,6 +670,9 @@ private: protected: void continueResolve(ResolutionState &state) override; + void addStructuredClass(Handle<StructuredClass> s); + void addAnnotationClass(Handle<AnnotationClass> a); + public: /** * The constructor for a new domain. Note that this is an empty Domain and @@ -726,22 +705,6 @@ public: } /** - * Adds a StructuredClass to this Domain. - */ - void addStructuredClass(Handle<StructuredClass> s) - { - structuredClasses.push_back(s); - } - - /** - * Adds multiple StructuredClasses to this Domain. - */ - void addStructuredClasses(const std::vector<Handle<StructuredClass>> &ss) - { - structuredClasses.insert(structuredClasses.end(), ss.begin(), ss.end()); - } - - /** * Returns a const reference to the NodeVector of AnnotationClasses that are * part of this Domain. * @@ -754,22 +717,6 @@ public: } /** - * Adds an AnnotationClass to this Domain. - */ - void addAnnotationClass(Handle<AnnotationClass> a) - { - annotationClasses.push_back(a); - } - - /** - * Adds multiple AnnotationClasses to this Domain. - */ - void addAnnotationClasses(const std::vector<Handle<AnnotationClass>> &as) - { - annotationClasses.insert(annotationClasses.end(), as.begin(), as.end()); - } - - /** * Returns a const reference to the NodeVector of TypeSystems that are * references in this Domain. * diff --git a/test/core/model/DomainTest.cpp b/test/core/model/DomainTest.cpp index af00151..772130c 100644 --- a/test/core/model/DomainTest.cpp +++ b/test/core/model/DomainTest.cpp @@ -158,55 +158,55 @@ TEST(Descriptor, pathToAdvanced) // Let's create the classes that we need first Rooted<StructuredClass> A{new StructuredClass( mgr, "A", domain, any, {nullptr}, {nullptr}, false, true)}; - domain->addStructuredClass(A); + Rooted<StructuredClass> start{new StructuredClass( mgr, "start", domain, any, {nullptr}, A, false, false)}; - domain->addStructuredClass(start); + Rooted<StructuredClass> B{new StructuredClass( mgr, "B", domain, any, {nullptr}, {nullptr}, true, false)}; - domain->addStructuredClass(B); + Rooted<StructuredClass> C{ new StructuredClass(mgr, "C", domain, any, {nullptr}, B, true, false)}; - domain->addStructuredClass(C); + Rooted<StructuredClass> D{new StructuredClass( mgr, "D", domain, any, {nullptr}, {nullptr}, true, false)}; - domain->addStructuredClass(D); + Rooted<StructuredClass> E{new StructuredClass( mgr, "E", domain, any, {nullptr}, {nullptr}, true, false)}; - domain->addStructuredClass(E); + Rooted<StructuredClass> target{ new StructuredClass(mgr, "target", domain, any)}; - domain->addStructuredClass(target); + // We create two fields for A Rooted<FieldDescriptor> A_field{new FieldDescriptor(mgr, A)}; - A->addFieldDescriptor(A_field); + A_field->addChild(target); Rooted<FieldDescriptor> A_field2{new FieldDescriptor( mgr, A, FieldDescriptor::FieldType::SUBTREE, "second")}; - A->addFieldDescriptor(A_field2); + A_field2->addChild(B); // We create no field for B // One for C Rooted<FieldDescriptor> C_field{new FieldDescriptor(mgr, C)}; - C->addFieldDescriptor(C_field); + C_field->addChild(target); // one for start Rooted<FieldDescriptor> start_field{new FieldDescriptor(mgr, start)}; - start->addFieldDescriptor(start_field); + start_field->addChild(D); // One for D Rooted<FieldDescriptor> D_field{new FieldDescriptor(mgr, D)}; - D->addFieldDescriptor(D_field); + D_field->addChild(E); // One for E Rooted<FieldDescriptor> E_field{new FieldDescriptor(mgr, E)}; - E->addFieldDescriptor(E_field); + E_field->addChild(target); - - #ifdef MANAGER_GRAPHVIZ_EXPORT - // dump the manager state - mgr.exportGraphviz("nastyDomain.dot"); - #endif + +#ifdef MANAGER_GRAPHVIZ_EXPORT + // dump the manager state + mgr.exportGraphviz("nastyDomain.dot"); +#endif // and now we should be able to find the shortest path as suggested std::vector<Rooted<Node>> path = start->pathTo(target); diff --git a/test/core/model/TestAdvanced.hpp b/test/core/model/TestAdvanced.hpp index 696fbed..15a4042 100644 --- a/test/core/model/TestAdvanced.hpp +++ b/test/core/model/TestAdvanced.hpp @@ -58,11 +58,9 @@ static Rooted<Domain> constructHeadingDomain(Manager &mgr, // set up heading StructuredClass. Rooted<StructuredClass> heading{new StructuredClass( mgr, "heading", domain, card, {nullptr}, {nullptr}, true)}; - // as field we actually want to refer to the field of paragraph. + // as field want to copy the field of paragraph. Rooted<StructuredClass> p = resolveDescriptor(bookDomain, "paragraph"); - heading->addFieldDescriptor(p->getFieldDescriptors()[0]); - // add the class to the domain. - domain->addStructuredClass(heading); + heading->copyFieldDescriptor(p->getFieldDescriptors()[0]); // create a new field for headings in each section type. std::vector<std::string> secclasses{"book", "section", "subsection", "paragraph"}; @@ -71,7 +69,6 @@ static Rooted<Domain> constructHeadingDomain(Manager &mgr, Rooted<FieldDescriptor> heading_field{new FieldDescriptor( mgr, desc, FieldDescriptor::FieldType::SUBTREE, "heading")}; heading_field->addChild(heading); - desc->addFieldDescriptor(heading_field); } return domain; } @@ -94,9 +91,9 @@ static Rooted<Domain> constructListDomain(Manager &mgr, // set up item StructuredClass; Rooted<StructuredClass> item{new StructuredClass( mgr, "item", domain, any, {nullptr}, {nullptr}, false)}; - domain->addStructuredClass(item); - // as field we actually want to refer to the field of paragraph. - item->addFieldDescriptor(p->getFieldDescriptors()[0]); + + // as field we want to copy the field of paragraph. + item->copyFieldDescriptor(p->getFieldDescriptors()[0]); // set up list StructuredClasses. std::vector<std::string> listTypes{"ol", "ul"}; for (auto &listType : listTypes) { @@ -104,8 +101,6 @@ static Rooted<Domain> constructListDomain(Manager &mgr, mgr, listType, domain, any, {nullptr}, p, false)}; Rooted<FieldDescriptor> list_field{new FieldDescriptor(mgr, list)}; list_field->addChild(item); - list->addFieldDescriptor(list_field); - domain->addStructuredClass(list); } return domain; } @@ -121,11 +116,11 @@ static Rooted<Domain> constructEmphasisDomain(Manager &mgr, Rooted<Domain> domain{new Domain(mgr, sys, "emphasis")}; // create AnnotationClasses Rooted<AnnotationClass> em{ - new AnnotationClass(mgr, "emphasized", domain, {nullptr})}; - domain->addAnnotationClass(em); + new AnnotationClass(mgr, "emphasized", domain)}; + Rooted<AnnotationClass> strong{ - new AnnotationClass(mgr, "strong", domain, {nullptr})}; - domain->addAnnotationClass(strong); + new AnnotationClass(mgr, "strong", domain)}; + return domain; } @@ -338,4 +333,3 @@ static Rooted<Document> constructAdvancedDocument(Manager &mgr, Logger &logger, } #endif /* _TEST_DOCUMENT_HPP_ */ - diff --git a/test/core/model/TestDocumentBuilder.hpp b/test/core/model/TestDocumentBuilder.hpp index 081e934..5896802 100644 --- a/test/core/model/TestDocumentBuilder.hpp +++ b/test/core/model/TestDocumentBuilder.hpp @@ -295,8 +295,6 @@ Rooted<AnnotationEntity> buildAnnotationEntity( Rooted<AnnotationEntity> anno{new AnnotationEntity( document->getManager(), document, descriptor.cast<AnnotationClass>(), start, end, attributes, name)}; - // append the new entity to the document - document->addAnnotation(anno); // and return it. return anno; } diff --git a/test/core/model/TestDomain.hpp b/test/core/model/TestDomain.hpp index 48db57a..f6b8805 100644 --- a/test/core/model/TestDomain.hpp +++ b/test/core/model/TestDomain.hpp @@ -44,40 +44,37 @@ static Rooted<Domain> constructBookDomain(Manager &mgr, // Set up the "book" node. Rooted<StructuredClass> book{new StructuredClass( mgr, "book", domain, single, {nullptr}, {nullptr}, false, true)}; - domain->addStructuredClass(book); + // The structure field of it. Rooted<FieldDescriptor> book_field{new FieldDescriptor(mgr, book)}; - book->addFieldDescriptor(book_field); // From there on the "section". Rooted<StructuredClass> section{ new StructuredClass(mgr, "section", domain, any)}; book_field->addChild(section); - domain->addStructuredClass(section); + // And the field of it. Rooted<FieldDescriptor> section_field{new FieldDescriptor(mgr, section)}; - section->addFieldDescriptor(section_field); // We also add the "paragraph", which is transparent. Rooted<StructuredClass> paragraph{new StructuredClass( mgr, "paragraph", domain, any, {nullptr}, {nullptr}, true)}; section_field->addChild(paragraph); book_field->addChild(paragraph); - domain->addStructuredClass(paragraph); + // And the field of it. Rooted<FieldDescriptor> paragraph_field{ new FieldDescriptor(mgr, paragraph)}; - paragraph->addFieldDescriptor(paragraph_field); // We append "subsection" to section. Rooted<StructuredClass> subsection{ new StructuredClass(mgr, "subsection", domain, any)}; section_field->addChild(subsection); - domain->addStructuredClass(subsection); + // And the field of it. Rooted<FieldDescriptor> subsection_field{ new FieldDescriptor(mgr, subsection)}; - subsection->addFieldDescriptor(subsection_field); + // and we add the paragraph to subsections fields subsection_field->addChild(paragraph); @@ -85,12 +82,11 @@ static Rooted<Domain> constructBookDomain(Manager &mgr, Rooted<StructuredClass> text{new StructuredClass( mgr, "text", domain, any, {nullptr}, {nullptr}, true)}; paragraph_field->addChild(text); - domain->addStructuredClass(text); + // ... and has a primitive field. Rooted<FieldDescriptor> text_field{new FieldDescriptor( mgr, text, domain->getTypesystems()[0]->getTypes()[0], "content", false)}; - text->addFieldDescriptor(text_field); return domain; } @@ -98,4 +94,3 @@ static Rooted<Domain> constructBookDomain(Manager &mgr, } #endif /* _TEST_DOMAIN_HPP_ */ - |