summaryrefslogtreecommitdiff
path: root/src/core/model
diff options
context:
space:
mode:
authorBenjamin Paassen <bpaassen@techfak.uni-bielefeld.de>2015-02-15 18:16:24 +0100
committerBenjamin Paassen <bpaassen@techfak.uni-bielefeld.de>2015-02-15 18:16:24 +0100
commit6f3100acc766efb0a4d838fcdcd609c6de3c4297 (patch)
tree3ac0401ee9f00e9ca851093eb75189994dca1df1 /src/core/model
parentb708dd4cce828c1089a18fefcc22804f7cdad908 (diff)
added pathTo and getDefaultFields for FieldDescriptors.
Diffstat (limited to 'src/core/model')
-rw-r--r--src/core/model/Domain.cpp468
-rw-r--r--src/core/model/Domain.hpp57
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