summaryrefslogtreecommitdiff
path: root/src/core/model/Domain.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/model/Domain.cpp')
-rw-r--r--src/core/model/Domain.cpp481
1 files changed, 249 insertions, 232 deletions
diff --git a/src/core/model/Domain.cpp b/src/core/model/Domain.cpp
index 8288099..ae20068 100644
--- a/src/core/model/Domain.cpp
+++ b/src/core/model/Domain.cpp
@@ -27,6 +27,201 @@
namespace ousia {
+/* Helper Functions */
+
+struct PathState {
+ std::shared_ptr<PathState> pred;
+ Node *node;
+ size_t length;
+
+ PathState(std::shared_ptr<PathState> pred, Node *node)
+ : pred(pred), node(node)
+ {
+ if (pred == nullptr) {
+ length = 1;
+ } else {
+ length = pred->length + 1;
+ }
+ }
+};
+
+static void constructPath(std::shared_ptr<PathState> state,
+ NodeVector<Node> &vec)
+{
+ if (state->pred != nullptr) {
+ constructPath(state->pred, vec);
+ }
+ vec.push_back(state->node);
+}
+
+static NodeVector<Node> pathTo(const Node *start, Logger &logger,
+ Handle<Node> target, bool &success)
+{
+ success = false;
+ // shortest path.
+ 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 = desc->getFieldDescriptors();
+
+ for (auto fd : fields) {
+ if (fd == target) {
+ // if we have found the target directly, return without search.
+ success = true;
+ return shortest;
+ }
+ if (fd->getFieldType() == FieldDescriptor::FieldType::TREE) {
+ states.push(std::make_shared<PathState>(nullptr, fd.get()));
+ }
+ }
+ } else {
+ const FieldDescriptor *field =
+ static_cast<const FieldDescriptor *>(start);
+ // initially put every child and its subclasses to the queue.
+ for (auto c : field->getChildrenWithSubclasses()) {
+ // if we have found the target directly, return without search.
+ if (c == target) {
+ success = true;
+ return shortest;
+ }
+ if (c->isTransparent()) {
+ states.push(std::make_shared<PathState>(nullptr, c.get()));
+ }
+ }
+ }
+ // set of visited nodes.
+ std::unordered_set<const Node *> visited;
+ while (!states.empty()) {
+ std::shared_ptr<PathState> current = states.front();
+ states.pop();
+ // do not proceed if this node was already visited.
+ if (!visited.insert(current->node).second) {
+ continue;
+ }
+ // also do not proceed if we can't get better than the current shortest
+ // path anymore.
+ if (!shortest.empty() && current->length > shortest.size()) {
+ continue;
+ }
+
+ bool fin = false;
+ if (current->node->isa(&RttiTypes::StructuredClass)) {
+ const StructuredClass *strct =
+ static_cast<const StructuredClass *>(current->node);
+
+ // look through all fields.
+ NodeVector<FieldDescriptor> fields = strct->getFieldDescriptors();
+ for (auto fd : fields) {
+ // if we found our target, break off the search in this branch.
+ if (fd == target) {
+ fin = true;
+ continue;
+ }
+ // only continue in the TREE field.
+ if (fd->getFieldType() == FieldDescriptor::FieldType::TREE) {
+ states.push(std::make_shared<PathState>(current, fd.get()));
+ }
+ }
+ } else {
+ // otherwise this is a FieldDescriptor.
+ const FieldDescriptor *field =
+ static_cast<const FieldDescriptor *>(current->node);
+ // and we proceed by visiting all permitted children.
+ for (auto c : field->getChildrenWithSubclasses()) {
+ // if we found our target, break off the search in this branch.
+ if (c == target) {
+ fin = true;
+ continue;
+ }
+ // We only allow to continue our path via transparent children.
+ if (c->isTransparent()) {
+ states.push(std::make_shared<PathState>(current, c.get()));
+ }
+ }
+ }
+ // check if we are finished.
+ if (fin) {
+ success = true;
+ // if so we look if we found a shorter path than the current minimum
+ if (shortest.empty() || current->length < shortest.size()) {
+ NodeVector<Node> newPath;
+ constructPath(current, newPath);
+ shortest = newPath;
+ } else if (current->length == shortest.size()) {
+ // if the length is the same the result is ambigous and we log
+ // an error.
+ NodeVector<Node> newPath;
+ constructPath(current, newPath);
+ logger.error(
+ std::string("Can not unambigously create a path from \"") +
+ start->getName() + "\" to \"" + target->getName() + "\".");
+ logger.note("Dismissed the path:", SourceLocation{},
+ MessageMode::NO_CONTEXT);
+ for (auto n : newPath) {
+ logger.note(n->getName());
+ }
+ }
+ }
+ }
+ return shortest;
+}
+
+template <typename F>
+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;
+ // 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()) {
+ Rooted<Node> n = q.front();
+ q.pop();
+ // do not proceed if this node was already visited.
+ if (!visited.insert(n.get()).second) {
+ continue;
+ }
+
+ if (n->isa(&RttiTypes::StructuredClass)) {
+ Rooted<StructuredClass> strct = n.cast<StructuredClass>();
+
+ // look through all fields.
+ NodeVector<FieldDescriptor> fields = strct->getFieldDescriptors();
+ for (auto fd : fields) {
+ // note matches.
+ if (match(fd)) {
+ res.push_back(fd);
+ }
+ // only continue in the TREE field.
+ if (fd->getFieldType() == FieldDescriptor::FieldType::TREE) {
+ q.push(fd);
+ }
+ }
+ } else {
+ // otherwise this is a FieldDescriptor.
+ Rooted<FieldDescriptor> field = n.cast<FieldDescriptor>();
+ // and we proceed by visiting all permitted children.
+ for (auto c : field->getChildrenWithSubclasses()) {
+ // note matches.
+ if (match(c)) {
+ res.push_back(c);
+ }
+ // We only continue our search via transparent children.
+ if (c->isTransparent()) {
+ q.push(c);
+ }
+ }
+ }
+ }
+ return res;
+}
+
/* Class FieldDescriptor */
FieldDescriptor::FieldDescriptor(Manager &mgr, Handle<Type> primitiveType,
@@ -116,7 +311,7 @@ bool FieldDescriptor::doValidate(Logger &logger) const
* there are duplicates.
*/
std::set<std::string> names;
- for (Handle<StructuredClass> c : children) {
+ for (Handle<StructuredClass> c : getChildrenWithSubclasses()) {
if (!names.insert(c->getName()).second) {
logger.error(std::string("Field \"") + getName() +
"\" had multiple children with the name \"" +
@@ -129,6 +324,25 @@ bool FieldDescriptor::doValidate(Logger &logger) const
return valid;
}
+static void gatherSubclasses(NodeVector<StructuredClass> &res,
+ Handle<StructuredClass> strct)
+{
+ for (auto sub : strct->getSubclasses()) {
+ res.push_back(sub);
+ gatherSubclasses(res, sub);
+ }
+}
+
+NodeVector<StructuredClass> FieldDescriptor::getChildrenWithSubclasses() const
+{
+ NodeVector<StructuredClass> res;
+ for (auto c : children) {
+ res.push_back(c);
+ gatherSubclasses(res, c);
+ }
+ return res;
+}
+
bool FieldDescriptor::removeChild(Handle<StructuredClass> c)
{
auto it = children.find(c);
@@ -140,6 +354,38 @@ bool FieldDescriptor::removeChild(Handle<StructuredClass> c)
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)
@@ -209,152 +455,6 @@ bool Descriptor::doValidate(Logger &logger) const
return valid & continueValidationCheckDuplicates(fds, logger);
}
-struct PathState {
- std::shared_ptr<PathState> pred;
- Node *node;
- size_t length;
-
- PathState(std::shared_ptr<PathState> pred, Node *node)
- : pred(pred), node(node)
- {
- if (pred == nullptr) {
- length = 1;
- } else {
- length = pred->length + 1;
- }
- }
-};
-
-static void constructPath(std::shared_ptr<PathState> state,
- NodeVector<Node> &vec)
-{
- if (state->pred != nullptr) {
- constructPath(state->pred, vec);
- }
- vec.push_back(state->node);
-}
-
-static NodeVector<Node> pathTo(const Descriptor *start, Logger &logger,
- Handle<Node> target, bool &success)
-{
- success = false;
- // shortest path.
- NodeVector<Node> shortest;
- // state queue for breadth-first search.
- std::queue<std::shared_ptr<PathState>> states;
- {
- // initially put every field descriptor on the queue.
- NodeVector<FieldDescriptor> fields = start->getFieldDescriptors();
-
- for (auto fd : fields) {
- if (fd == target) {
- // if we have found the target directly, return without search.
- success = true;
- return shortest;
- }
- if (fd->getFieldType() == FieldDescriptor::FieldType::TREE) {
- states.push(std::make_shared<PathState>(nullptr, fd.get()));
- }
- }
- }
- // set of visited nodes.
- std::unordered_set<const Node *> visited;
- while (!states.empty()) {
- std::shared_ptr<PathState> current = states.front();
- states.pop();
- // do not proceed if this node was already visited.
- if (!visited.insert(current->node).second) {
- continue;
- }
- // also do not proceed if we can't get better than the current shortest
- // path anymore.
- if (!shortest.empty() && current->length > shortest.size()) {
- continue;
- }
-
- bool fin = false;
- if (current->node->isa(&RttiTypes::StructuredClass)) {
- const StructuredClass *strct =
- static_cast<const StructuredClass *>(current->node);
-
- // look through all fields.
- NodeVector<FieldDescriptor> fields = strct->getFieldDescriptors();
- for (auto fd : fields) {
- // if we found our target, break off the search in this branch.
- if (fd == target) {
- fin = true;
- continue;
- }
- // only continue in the TREE field.
- if (fd->getFieldType() == FieldDescriptor::FieldType::TREE) {
- states.push(std::make_shared<PathState>(current, fd.get()));
- }
- }
-
- /*
- * Furthermore we have to consider that all subclasses of this
- * StructuredClass are allowed in place of this StructuredClass as
- * well, so we continue the search for them as well.
- */
-
- NodeVector<StructuredClass> subs = strct->getSubclasses();
- for (auto sub : subs) {
- // if we found our target, break off the search in this branch.
- if (sub == target) {
- fin = true;
- current = current->pred;
- continue;
- }
- // We only continue our path via transparent classes.
- if (sub->isTransparent()) {
- states.push(
- std::make_shared<PathState>(current->pred, sub.get()));
- }
- }
- } else {
- // otherwise this is a FieldDescriptor.
- const FieldDescriptor *field =
- static_cast<const FieldDescriptor *>(current->node);
- // and we proceed by visiting all permitted children.
- for (auto c : field->getChildren()) {
- // if we found our target, break off the search in this branch.
- if (c == target) {
- fin = true;
- continue;
- }
- // We only allow to continue our path via transparent children.
- if (c->isTransparent()) {
- states.push(std::make_shared<PathState>(current, c.get()));
- }
- }
- }
- // check if we are finished.
- if (fin) {
- success = true;
- // if so we look if we found a shorter path than the current minimum
- if (shortest.empty() || current->length < shortest.size()) {
- NodeVector<Node> newPath;
- constructPath(current, newPath);
- shortest = newPath;
- } else if (current->length == shortest.size()) {
- // if the length is the same the result is ambigous and we log
- // an error.
- NodeVector<Node> newPath;
- constructPath(current, newPath);
- logger.error(
- std::string("Can not unambigously create a path from \"") +
- start->getName() + "\" to \"" + target->getName() + "\".");
- logger.note("Dismissed the path:", SourceLocation{},
- MessageMode::NO_CONTEXT);
- for (auto n : newPath) {
- logger.note(n->getName());
- }
- }
- }
- }
- return shortest;
-}
-
NodeVector<Node> Descriptor::pathTo(Handle<StructuredClass> target,
Logger &logger) const
{
@@ -370,89 +470,6 @@ std::pair<NodeVector<Node>, bool> Descriptor::pathTo(
return std::make_pair(path, success);
}
-template <typename F>
-static NodeVector<Node> collect(const Descriptor *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);
- }
- }
- }
- // set of visited nodes.
- std::unordered_set<const Node *> visited;
- while (!q.empty()) {
- Rooted<Node> n = q.front();
- q.pop();
- // do not proceed if this node was already visited.
- if (!visited.insert(n.get()).second) {
- continue;
- }
-
- if (n->isa(&RttiTypes::StructuredClass)) {
- Rooted<StructuredClass> strct = n.cast<StructuredClass>();
-
- // look through all fields.
- NodeVector<FieldDescriptor> fields = strct->getFieldDescriptors();
- for (auto fd : fields) {
- // note matches.
- if (match(fd)) {
- res.push_back(fd);
- }
- // only continue in the TREE field.
- if (fd->getFieldType() == FieldDescriptor::FieldType::TREE) {
- q.push(fd);
- }
- }
-
- /*
- * Furthermore we have to consider that all subclasses of this
- * StructuredClass are allowed in place of this StructuredClass as
- * well, so we continue the search for them as well.
- */
-
- NodeVector<StructuredClass> subs = strct->getSubclasses();
- for (auto sub : subs) {
- // note matches.
- if (match(sub)) {
- res.push_back(sub);
- }
- // We only continue our search via transparent classes.
- if (sub->isTransparent()) {
- q.push(sub);
- }
- }
- } else {
- // otherwise this is a FieldDescriptor.
- Rooted<FieldDescriptor> field = n.cast<FieldDescriptor>();
- // and we proceed by visiting all permitted children.
- for (auto c : field->getChildren()) {
- // note matches.
- if (match(c)) {
- res.push_back(c);
- }
- // We only continue our search via transparent children.
- if (c->isTransparent()) {
- q.push(c);
- }
- }
- }
- }
- return res;
-}
-
NodeVector<FieldDescriptor> Descriptor::getDefaultFields() const
{
// TODO: In principle a cast would be nicer here, but for now we copy.
@@ -605,7 +622,7 @@ void Descriptor::copyFieldDescriptor(Handle<FieldDescriptor> fd, Logger &logger)
copy = Rooted<FieldDescriptor>{
new FieldDescriptor(getManager(), this, fd->getFieldType(),
fd->getName(), fd->isOptional())};
- for (auto &c : fd->getChildren()) {
+ for (auto c : fd->getChildren()) {
copy->addChild(c);
}
}
@@ -940,4 +957,4 @@ const Rtti Domain = RttiBuilder<ousia::Domain>("Domain")
.parent(&RootNode)
.composedOf({&StructuredClass, &AnnotationClass});
}
-}
+} \ No newline at end of file