diff options
author | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2015-01-16 22:46:41 +0100 |
---|---|---|
committer | Andreas Stöckel <andreas@somweyr.de> | 2015-01-16 22:46:41 +0100 |
commit | b64c3cdc7dfd8f46207cc6d74c644becc4ea1d42 (patch) | |
tree | fd57ec2eedd21974e93e4ae955690e4bcd442aa9 | |
parent | 378ff2235fdf32983ebf2186a9127e51cbe8a0ab (diff) | |
parent | 821648607f5e0c6702eefbc206c0421d1a347bda (diff) |
Merge branch 'master' of somweyr.de:ousia
-rw-r--r-- | src/core/model/Document.cpp | 68 | ||||
-rw-r--r-- | src/core/model/Document.hpp | 15 | ||||
-rw-r--r-- | src/core/model/Node.hpp | 85 |
3 files changed, 164 insertions, 4 deletions
diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp index 2f12acb..92791a4 100644 --- a/src/core/model/Document.cpp +++ b/src/core/model/Document.cpp @@ -92,7 +92,8 @@ int DocumentEntity::getFieldDescriptorIndex( } } -bool DocumentEntity::validate(Logger &logger) const +bool DocumentEntity::doValidate(Logger &logger, + std::set<ManagedUid> &visited) const { // TODO: check the validated form of Attributes // iterate over every field @@ -134,9 +135,16 @@ bool DocumentEntity::validate(Logger &logger) const // iterate over every actual child of this DocumentEntity for (auto &rc : fields[f]) { - if (!rc->isa(RttiTypes::StructuredEntity)) { + if (!rc->isa(RttiTypes::Anchor)) { + // Anchors are uninteresting and can be ignored. continue; } + if (!rc->isa(RttiTypes::DocumentPrimitive)) { + // For DocumentPrimitives we have to check the content type. + // TODO: Do that! + continue; + } + // otherwise this is a StructuredEntity Handle<StructuredEntity> c = rc.cast<StructuredEntity>(); ManagedUid id = c->getDescriptor()->getUid(); @@ -193,6 +201,23 @@ bool DocumentEntity::validate(Logger &logger) const } } } + + // go into recursion. + for (auto &f : fields) { + for (auto &n : f) { + if (!visited.insert(n->getUid()).second) { + logger.error("The given document contains a cycle!"); + return false; + } + if (n->isValidated()) { + continue; + } + if (!n->validate(logger, visited)) { + return false; + } + } + } + return true; } @@ -222,6 +247,17 @@ StructuredEntity::StructuredEntity(Manager &mgr, Handle<Document> doc, doc->setRoot(this); } +bool StructuredEntity::doValidate(Logger &logger, + std::set<ManagedUid> &visited) const +{ + // check if the parent is set. + if (getParent() == nullptr) { + return false; + } + // check the validity as a DocumentEntity. + return DocumentEntity::doValidate(logger, visited); +} + /* Class AnnotationEntity */ AnnotationEntity::AnnotationEntity(Manager &mgr, Handle<Document> parent, @@ -236,6 +272,34 @@ AnnotationEntity::AnnotationEntity(Manager &mgr, Handle<Document> parent, parent->annotations.push_back(this); } +bool AnnotationEntity::doValidate(Logger &logger, + std::set<ManagedUid> &visited) const +{ + // check if this AnnotationEntity is correctly registered at its document. + if (getParent() == nullptr || !getParent()->isa(RttiTypes::Document)) { + return false; + } + Handle<Document> doc = getParent().cast<Document>(); + bool found = false; + for (auto &a : doc->getAnnotations()) { + if (a == this) { + found = true; + break; + } + } + if (!found) { + logger.error("This annotation was not registered at the document."); + return false; + } + + // check the validity as a DocumentEntity. + if (!DocumentEntity::doValidate(logger, visited)) { + return false; + } + // TODO: then check if the anchors are in the correct document. + return true; +} + /* Class Document */ void Document::continueResolve(ResolutionState &state) diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp index c70a6a3..b73e07d 100644 --- a/src/core/model/Document.hpp +++ b/src/core/model/Document.hpp @@ -108,6 +108,8 @@ #ifndef _OUSIA_MODEL_DOCUMENT_HPP_ #define _OUSIA_MODEL_DOCUMENT_HPP_ +#include <set> + #include <core/managed/ManagedContainer.hpp> #include <core/common/Variant.hpp> @@ -159,6 +161,8 @@ protected: fields[getFieldDescriptorIndex(fieldName, true)].push_back(s); } + bool doValidate(Logger &logger, std::set<ManagedUid> &visited) const; + public: /** * The constructor for a DocumentEntity. Node that this does not inherit @@ -256,8 +260,6 @@ public: return fields[getFieldDescriptorIndex(fieldDescriptor, true)]; } - bool validate(Logger& logger) const; - // TODO: Change this to move methods. // /** // * This adds a StructureNode to the field with the given name. If an @@ -343,6 +345,8 @@ public: * common superclass for StructuredEntity, Anchor and DocumentPrimitive. */ class StructureNode : public Node { + friend DocumentEntity; + public: /** * Constructor for a StructureNode at the root. @@ -364,6 +368,10 @@ public: * information please refer to the header documentation above. */ class StructuredEntity : public StructureNode, public DocumentEntity { +protected: + bool doValidate(Logger &logger, + std::set<ManagedUid> &visited) const override; + public: /** * Constructor for a StructuredEntity in the Structure Tree. @@ -505,6 +513,9 @@ class AnnotationEntity : public Node, public DocumentEntity { private: Owned<Anchor> start; Owned<Anchor> end; +protected: + bool doValidate(Logger &logger, + std::set<ManagedUid> &visited) const override; public: /** diff --git a/src/core/model/Node.hpp b/src/core/model/Node.hpp index e8adbaa..3763395 100644 --- a/src/core/model/Node.hpp +++ b/src/core/model/Node.hpp @@ -29,6 +29,7 @@ #define _OUSIA_NODE_HPP_ #include <map> +#include <set> #include <string> #include <vector> @@ -40,6 +41,7 @@ namespace ousia { // Forward declarations +class Logger; class RttiType; template <class T> class Rtti; @@ -103,6 +105,11 @@ private: * Reference to a parent node instace. */ Owned<Node> parent; + /** + * A "dirty" flag that signifies if this Node has been validated already + * or not. + */ + mutable bool validated = false; /** * Private version of the "path" function used to construct the path. Calls @@ -263,6 +270,59 @@ protected: return false; } + /** + * This method should be called if the internal state of this Node is + * changed such that a new validation run has to be made. + */ + void invalidate() const { validated = false; } + + /** + * The convention for this function is as follows: + * 1.) The child should validate itself and return false, if constraints are + * not met. Errors should be logged if and only if false is returned. + * 3.) It should call validate on all children. + * If some child returns false this method should return false as well. + * 4.) If all children could be validated this method should return true. + * + * Note that this implementation does not have to touch the visited set. + * You can use it for validation purposes, however (e.g. to detect cycles + * in the graph). + * + * The default and trivial behaviour of this function is to return true. + * + * @param logger is a logger for error messages if false is returned. + * @param visited is a set containing the ManagedUids of all children + * that already have been visited. + * @return true if this is a valid node and false if it is not. + */ + virtual bool doValidate(Logger &logger, std::set<ManagedUid> &visited) const + { + return true; + } + + /** + * A wrapper for doValidate that takes care of not visiting children twice, + * and handling the validated flag. + */ + bool validate(Logger &logger, std::set<ManagedUid> &visited) const { + if (!visited.insert(getUid()).second) { + // if we have visited this Node already within this run, return + // the validated flag. + return validated; + } + if(validated){ + // if this is validated, return true. + return true; + } + if(!doValidate(logger, visited)){ + // if this can not be validated, return false. + return false; + } + // if it could be validated, set the validated flag. + validated = true; + return true; + } + public: /** * Initializes the node with empty name and parent. @@ -361,6 +421,31 @@ public: */ std::vector<ResolutionResult> resolve(const std::string &name, const RttiType &type); + + /** + * Returns true if this node has been validated. Note that a 'false' return + * value does _not_ imply that this Node is invalid. It merely says that + * validity of this node is uncertain. The opposite is true, however: If + * this node is invalid, the validated flag will be false. + */ + bool isValidated() const { return validated; } + + /** + * Checks whether this node is valid and returns true if it is and false + * if it is not. If the node is invalid further information will be appended + * to the logger. If this is valid this will also set the "validated" flag + * to "true". + * + * @param logger is a logger where errors will be logged if this + * Node is invalid. + * + * @return true if this Node is valid. + */ + bool validate(Logger &logger) + { + std::set<ManagedUid> visited; + return validate(logger, visited); + } }; /** |