From 89f01a0a49f4fd23034d532b37d54d3f3f612082 Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Thu, 12 Feb 2015 19:31:50 +0100 Subject: added a method to retrieve all reachable default fields from a given descriptor. --- src/core/model/Domain.cpp | 99 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) (limited to 'src/core/model/Domain.cpp') diff --git a/src/core/model/Domain.cpp b/src/core/model/Domain.cpp index 619454c..6f33ebd 100644 --- a/src/core/model/Domain.cpp +++ b/src/core/model/Domain.cpp @@ -369,7 +369,106 @@ std::pair, bool> Descriptor::pathTo( NodeVector path = ousia::pathTo(this, logger, field, success); return std::make_pair(path, success); } + +template +static NodeVector collect(const Descriptor *start, F match) { + // result + NodeVector res; + // queue for breadth-first search of graph. + std::queue> q; + { + // initially put every field descriptor on the queue. + NodeVector 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 visited; + while (!q.empty()) { + Rooted 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 strct = n.cast(); + + // look through all fields. + NodeVector 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 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 field = n.cast(); + // 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 Descriptor::getDefaultFields() const +{ + // TODO: In principle a cast would be nicer here, but for now we copy. + NodeVector nodes = collect(this, [](Handle n) { + if (!n->isa(&RttiTypes::FieldDescriptor)) { + return false; + } + Handle f = n.cast(); + return f->getFieldType() == FieldDescriptor::FieldType::TREE && + f->isPrimitive(); + }); + NodeVector res; + for (auto n : nodes) { + res.push_back(n.cast()); + } + return res; } static ssize_t getFieldDescriptorIndex(const NodeVector &fds, -- cgit v1.2.3