diff options
author | Benjamin Paassen <bpaassen@techfak.uni-bielefeld.de> | 2015-02-15 18:16:24 +0100 |
---|---|---|
committer | Benjamin Paassen <bpaassen@techfak.uni-bielefeld.de> | 2015-02-15 18:16:24 +0100 |
commit | 6f3100acc766efb0a4d838fcdcd609c6de3c4297 (patch) | |
tree | 3ac0401ee9f00e9ca851093eb75189994dca1df1 /src/core/model | |
parent | b708dd4cce828c1089a18fefcc22804f7cdad908 (diff) |
added pathTo and getDefaultFields for FieldDescriptors.
Diffstat (limited to 'src/core/model')
-rw-r--r-- | src/core/model/Domain.cpp | 468 | ||||
-rw-r--r-- | src/core/model/Domain.hpp | 57 |
2 files changed, 308 insertions, 217 deletions
diff --git a/src/core/model/Domain.cpp b/src/core/model/Domain.cpp index 8288099..a68f00d 100644 --- a/src/core/model/Domain.cpp +++ b/src/core/model/Domain.cpp @@ -27,187 +27,7 @@ namespace ousia { -/* Class FieldDescriptor */ - -FieldDescriptor::FieldDescriptor(Manager &mgr, Handle<Type> primitiveType, - Handle<Descriptor> parent, FieldType fieldType, - std::string name, bool optional) - : Node(mgr, std::move(name), parent), - children(this), - fieldType(fieldType), - primitiveType(acquire(primitiveType)), - optional(optional), - primitive(true) -{ -} - -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), - primitive(false) -{ -} - -bool FieldDescriptor::doValidate(Logger &logger) const -{ - bool valid = true; - // check parent type - if (getParent() == nullptr) { - logger.error(std::string("Field \"") + getName() + "\" has no parent!", - *this); - valid = false; - } else if (!getParent()->isa(&RttiTypes::Descriptor)) { - logger.error(std::string("The parent of Field \"") + getName() + - "\" is not a descriptor!", - *this); - valid = false; - } - // check name - if (getName().empty()) { - if (fieldType != FieldType::TREE) { - logger.error(std::string("Field \"") + getName() + - "\" is not the main field but has an empty name!", - *this); - valid = false; - } - } else { - valid = valid & validateName(logger); - } - - // check consistency of FieldType with the rest of the FieldDescriptor. - if (primitive) { - if (children.size() > 0) { - logger.error(std::string("Field \"") + getName() + - "\" is supposed to be primitive but has " - "registered child classes!", - *this); - valid = false; - } - if (primitiveType == nullptr) { - logger.error(std::string("Field \"") + getName() + - "\" is supposed to be primitive but has " - "no primitive type!", - *this); - valid = false; - } - } else { - if (primitiveType != nullptr) { - logger.error(std::string("Field \"") + getName() + - "\" is supposed to be non-primitive but has " - "a primitive type!", - *this); - valid = false; - } - // if this is not a primitive field we require at least one child. - if (children.empty()) { - logger.error(std::string("Field \"") + getName() + - "\" is non primitive but does not allow children!", - *this); - valid = false; - } - } - /* - * we are not allowed to call the validation functions of each child because - * this might lead to cycles. What we should do, however, is to check if - * there are duplicates. - */ - std::set<std::string> names; - for (Handle<StructuredClass> c : children) { - if (!names.insert(c->getName()).second) { - logger.error(std::string("Field \"") + getName() + - "\" had multiple children with the name \"" + - c->getName() + "\"", - *this); - valid = false; - } - } - - return valid; -} - -bool FieldDescriptor::removeChild(Handle<StructuredClass> c) -{ - auto it = children.find(c); - if (it != children.end()) { - invalidate(); - children.erase(it); - return true; - } - return false; -} - -/* Class Descriptor */ - -void Descriptor::doResolve(ResolutionState &state) -{ - const NodeVector<Attribute> &attributes = - attributesDescriptor->getAttributes(); - continueResolveComposita(attributes, attributes.getIndex(), state); - continueResolveComposita(fieldDescriptors, fieldDescriptors.getIndex(), - state); -} - -bool Descriptor::doValidate(Logger &logger) const -{ - bool valid = true; - // check parent type - if (getParent() == nullptr) { - logger.error( - std::string("Descriptor \"") + getName() + "\" has no parent!", - *this); - valid = false; - } else if (!getParent()->isa(&RttiTypes::Domain)) { - logger.error(std::string("The parent of Descriptor \"") + getName() + - "\" is not a Domain!", - *this); - valid = false; - } - // check name - if (getName().empty()) { - logger.error("The name of this Descriptor is empty!", *this); - valid = false; - } else { - valid = valid & validateName(logger); - } - // ensure that no attribute with the key "name" exists. - if (attributesDescriptor == nullptr) { - logger.error(std::string("Descriptor \"") + getName() + - "\" has no Attribute specification!"); - valid = false; - } else { - if (attributesDescriptor->hasAttribute("name")) { - logger.error( - std::string("Descriptor \"") + getName() + - "\" has an attribute \"name\" which is a reserved word!"); - valid = false; - } - valid = valid & attributesDescriptor->validate(logger); - } - // check that only one FieldDescriptor is of type TREE. - auto fds = Descriptor::getFieldDescriptors(); - bool hasTREE = false; - for (auto fd : fds) { - if (fd->getFieldType() == FieldDescriptor::FieldType::TREE) { - if (!hasTREE) { - hasTREE = true; - } else { - logger.error( - std::string("Descriptor \"") + getName() + - "\" has multiple TREE fields, which is not permitted", - *fd); - valid = false; - break; - } - } - } - - // check attributes and the FieldDescriptors - return valid & continueValidationCheckDuplicates(fds, logger); -} +/* Helper Functions */ struct PathState { std::shared_ptr<PathState> pred; @@ -234,7 +54,7 @@ static void constructPath(std::shared_ptr<PathState> state, vec.push_back(state->node); } -static NodeVector<Node> pathTo(const Descriptor *start, Logger &logger, +static NodeVector<Node> pathTo(const Node *start, Logger &logger, Handle<Node> target, bool &success) { success = false; @@ -242,9 +62,10 @@ static NodeVector<Node> pathTo(const Descriptor *start, Logger &logger, NodeVector<Node> shortest; // state queue for breadth-first search. std::queue<std::shared_ptr<PathState>> states; - { + if (start->isa(&RttiTypes::Descriptor)) { + const Descriptor *desc = static_cast<const Descriptor *>(start); // initially put every field descriptor on the queue. - NodeVector<FieldDescriptor> fields = start->getFieldDescriptors(); + NodeVector<FieldDescriptor> fields = desc->getFieldDescriptors(); for (auto fd : fields) { if (fd == target) { @@ -256,6 +77,21 @@ static NodeVector<Node> pathTo(const Descriptor *start, Logger &logger, states.push(std::make_shared<PathState>(nullptr, fd.get())); } } + } else { + const FieldDescriptor *field = + static_cast<const FieldDescriptor *>(start); + // initially put every child on the queue. + for (auto c : field->getChildren()) { + // if we have found the target directly, return without search. + if (c == target) { + success = true; + return shortest; + } + // We only allow to continue our path via transparent children. + if (c->isTransparent()) { + states.push(std::make_shared<PathState>(nullptr, c.get())); + } + } } // set of visited nodes. std::unordered_set<const Node *> visited; @@ -355,42 +191,15 @@ static NodeVector<Node> pathTo(const Descriptor *start, Logger &logger, return shortest; } -NodeVector<Node> Descriptor::pathTo(Handle<StructuredClass> target, - Logger &logger) const -{ - bool success = false; - return ousia::pathTo(this, logger, target, success); -} - -std::pair<NodeVector<Node>, bool> Descriptor::pathTo( - Handle<FieldDescriptor> field, Logger &logger) const -{ - bool success = false; - NodeVector<Node> path = ousia::pathTo(this, logger, field, success); - return std::make_pair(path, success); -} - template <typename F> -static NodeVector<Node> collect(const Descriptor *start, F match) +static NodeVector<Node> collect(const Node *start, F match) { // result NodeVector<Node> res; // queue for breadth-first search of graph. std::queue<Rooted<Node>> q; - { - // initially put every field descriptor on the queue. - NodeVector<FieldDescriptor> fields = start->getFieldDescriptors(); - - for (auto fd : fields) { - // note matches. - if (match(fd)) { - res.push_back(fd); - } - if (fd->getFieldType() == FieldDescriptor::FieldType::TREE) { - q.push(fd); - } - } - } + // put the initial node on the stack. + q.push(const_cast<Node *>(start)); // set of visited nodes. std::unordered_set<const Node *> visited; while (!q.empty()) { @@ -453,6 +262,235 @@ static NodeVector<Node> collect(const Descriptor *start, F match) return res; } +/* Class FieldDescriptor */ + +FieldDescriptor::FieldDescriptor(Manager &mgr, Handle<Type> primitiveType, + Handle<Descriptor> parent, FieldType fieldType, + std::string name, bool optional) + : Node(mgr, std::move(name), parent), + children(this), + fieldType(fieldType), + primitiveType(acquire(primitiveType)), + optional(optional), + primitive(true) +{ +} + +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), + primitive(false) +{ +} + +bool FieldDescriptor::doValidate(Logger &logger) const +{ + bool valid = true; + // check parent type + if (getParent() == nullptr) { + logger.error(std::string("Field \"") + getName() + "\" has no parent!", + *this); + valid = false; + } else if (!getParent()->isa(&RttiTypes::Descriptor)) { + logger.error(std::string("The parent of Field \"") + getName() + + "\" is not a descriptor!", + *this); + valid = false; + } + // check name + if (getName().empty()) { + if (fieldType != FieldType::TREE) { + logger.error(std::string("Field \"") + getName() + + "\" is not the main field but has an empty name!", + *this); + valid = false; + } + } else { + valid = valid & validateName(logger); + } + + // check consistency of FieldType with the rest of the FieldDescriptor. + if (primitive) { + if (children.size() > 0) { + logger.error(std::string("Field \"") + getName() + + "\" is supposed to be primitive but has " + "registered child classes!", + *this); + valid = false; + } + if (primitiveType == nullptr) { + logger.error(std::string("Field \"") + getName() + + "\" is supposed to be primitive but has " + "no primitive type!", + *this); + valid = false; + } + } else { + if (primitiveType != nullptr) { + logger.error(std::string("Field \"") + getName() + + "\" is supposed to be non-primitive but has " + "a primitive type!", + *this); + valid = false; + } + // if this is not a primitive field we require at least one child. + if (children.empty()) { + logger.error(std::string("Field \"") + getName() + + "\" is non primitive but does not allow children!", + *this); + valid = false; + } + } + /* + * we are not allowed to call the validation functions of each child because + * this might lead to cycles. What we should do, however, is to check if + * there are duplicates. + */ + std::set<std::string> names; + for (Handle<StructuredClass> c : children) { + if (!names.insert(c->getName()).second) { + logger.error(std::string("Field \"") + getName() + + "\" had multiple children with the name \"" + + c->getName() + "\"", + *this); + valid = false; + } + } + + return valid; +} + +bool FieldDescriptor::removeChild(Handle<StructuredClass> c) +{ + auto it = children.find(c); + if (it != children.end()) { + invalidate(); + children.erase(it); + return true; + } + return false; +} + +std::pair<NodeVector<Node>, bool> FieldDescriptor::pathTo( + Handle<StructuredClass> childDescriptor, Logger &logger) const +{ + bool success = false; + NodeVector<Node> path = + ousia::pathTo(this, logger, childDescriptor, success); + return std::make_pair(path, success); +} +NodeVector<Node> FieldDescriptor::pathTo(Handle<FieldDescriptor> field, + Logger &logger) const +{ + bool success = false; + return ousia::pathTo(this, logger, field, success); +} +NodeVector<FieldDescriptor> FieldDescriptor::getDefaultFields() const +{ + // TODO: In principle a cast would be nicer here, but for now we copy. + NodeVector<Node> nodes = collect(this, [](Handle<Node> n) { + if (!n->isa(&RttiTypes::FieldDescriptor)) { + return false; + } + Handle<FieldDescriptor> f = n.cast<FieldDescriptor>(); + return f->getFieldType() == FieldDescriptor::FieldType::TREE && + f->isPrimitive(); + }); + NodeVector<FieldDescriptor> res; + for (auto n : nodes) { + res.push_back(n.cast<FieldDescriptor>()); + } + return res; +} + +/* Class Descriptor */ + +void Descriptor::doResolve(ResolutionState &state) +{ + const NodeVector<Attribute> &attributes = + attributesDescriptor->getAttributes(); + continueResolveComposita(attributes, attributes.getIndex(), state); + continueResolveComposita(fieldDescriptors, fieldDescriptors.getIndex(), + state); +} + +bool Descriptor::doValidate(Logger &logger) const +{ + bool valid = true; + // check parent type + if (getParent() == nullptr) { + logger.error( + std::string("Descriptor \"") + getName() + "\" has no parent!", + *this); + valid = false; + } else if (!getParent()->isa(&RttiTypes::Domain)) { + logger.error(std::string("The parent of Descriptor \"") + getName() + + "\" is not a Domain!", + *this); + valid = false; + } + // check name + if (getName().empty()) { + logger.error("The name of this Descriptor is empty!", *this); + valid = false; + } else { + valid = valid & validateName(logger); + } + // ensure that no attribute with the key "name" exists. + if (attributesDescriptor == nullptr) { + logger.error(std::string("Descriptor \"") + getName() + + "\" has no Attribute specification!"); + valid = false; + } else { + if (attributesDescriptor->hasAttribute("name")) { + logger.error( + std::string("Descriptor \"") + getName() + + "\" has an attribute \"name\" which is a reserved word!"); + valid = false; + } + valid = valid & attributesDescriptor->validate(logger); + } + // check that only one FieldDescriptor is of type TREE. + auto fds = Descriptor::getFieldDescriptors(); + bool hasTREE = false; + for (auto fd : fds) { + if (fd->getFieldType() == FieldDescriptor::FieldType::TREE) { + if (!hasTREE) { + hasTREE = true; + } else { + logger.error( + std::string("Descriptor \"") + getName() + + "\" has multiple TREE fields, which is not permitted", + *fd); + valid = false; + break; + } + } + } + + // check attributes and the FieldDescriptors + return valid & continueValidationCheckDuplicates(fds, logger); +} + +NodeVector<Node> Descriptor::pathTo(Handle<StructuredClass> target, + Logger &logger) const +{ + bool success = false; + return ousia::pathTo(this, logger, target, success); +} + +std::pair<NodeVector<Node>, bool> Descriptor::pathTo( + Handle<FieldDescriptor> field, Logger &logger) const +{ + bool success = false; + NodeVector<Node> path = ousia::pathTo(this, logger, field, success); + return std::make_pair(path, success); +} + NodeVector<FieldDescriptor> Descriptor::getDefaultFields() const { // TODO: In principle a cast would be nicer here, but for now we copy. @@ -940,4 +978,4 @@ const Rtti Domain = RttiBuilder<ousia::Domain>("Domain") .parent(&RootNode) .composedOf({&StructuredClass, &AnnotationClass}); } -} +}
\ No newline at end of file diff --git a/src/core/model/Domain.hpp b/src/core/model/Domain.hpp index d921a9c..3f41ecf 100644 --- a/src/core/model/Domain.hpp +++ b/src/core/model/Domain.hpp @@ -368,6 +368,60 @@ public: invalidate(); optional = std::move(o); } + + /** + * This tries to construct the shortest possible path of this Descriptor + * to the given child Descriptor. Note that this method has the problem that + * an empty return path does NOT strictly imply that no such path could + * be constructed: We also return an empty vector if the given + * Descriptor is a direct child. Therefore we also return a bool value + * indicating that the path is valid or not. + * + * Implicitly this does a breadth-first search on the graph of + * StructuredClasses that are transparent. It also takes care of cycles. + * + * @param childDescriptor is a supposedly valid child Descriptor of this + * Descriptor. + * @return a tuple containing a path of FieldDescriptors and + * StructuredClasses between this Descriptor and the + * input Descriptor and a bool value indicating if + * the construction was successful. + * + */ + std::pair<NodeVector<Node>, bool> pathTo( + Handle<StructuredClass> childDescriptor, Logger &logger) const; + /** + * This tries to construct the shortest possible path of this Descriptor + * to the given FieldDescriptor. Note that this method has the problem that + * an empty return path does NOT strictly imply that no such path could + * be constructed: We also return an empty vector if the given + * FieldDescriptor is a direct child. Therefore we also return a bool value + * indicating that the path is valid or not. + * + * + * Implicitly this does a breadth-first search on the graph of + * StructuredClasses that are transparent. It also takes care of cycles. + * + * @param field is a FieldDescriptor that may be allowed as child of this + * Descriptor. + * @return a path of FieldDescriptors and StructuredClasses between + * this Descriptor and the input FieldDescriptor or an empty + * vector if no such path could be constructed. + */ + NodeVector<Node> pathTo(Handle<FieldDescriptor> field, + Logger &logger) const; + + /** + * Returns a vector of all TREE fields that are allowed as structure tree + * children of an instance of this Descriptor. This also makes use of + * transparency. + * The list is sorted by the number of transparent elements that have to be + * constructed to arrive at the respective FieldDescriptor. + * + * @return a vector of all TREE fields that are allowed as structure tree + * children of an instance of this Descriptor. + */ + NodeVector<FieldDescriptor> getDefaultFields() const; }; /** @@ -1111,5 +1165,4 @@ extern const Rtti Domain; } } -#endif /* _OUSIA_MODEL_DOMAIN_HPP_ */ - +#endif /* _OUSIA_MODEL_DOMAIN_HPP_ */
\ No newline at end of file |