/*
Ousía
Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include
#include
#include "Domain.hpp"
namespace ousia {
namespace model {
template
static void checkUniqueName(Handle parent, NodeVector vec,
Handle child, const std::string &parentClassName,
const std::string &childClassName)
{
std::set childNames;
for (auto &c : vec) {
childNames.insert(c->getName());
}
if (childNames.find(child->getName()) != childNames.end()) {
throw OusiaException(std::string("The ") + parentClassName + " " +
parent->getName() + " already has a " +
childClassName + " with name " + child->getName());
}
}
/* Class FieldDescriptor */
FieldDescriptor::FieldDescriptor(Manager &mgr, Handle parent,
Handle primitiveType, std::string name,
bool optional)
: Node(mgr, std::move(name), parent),
children(this),
fieldType(FieldType::PRIMITIVE),
primitiveType(acquire(primitiveType)),
optional(optional)
{
parent->addFieldDescriptor(this);
}
FieldDescriptor::FieldDescriptor(Manager &mgr, Handle parent,
FieldType fieldType, std::string name,
bool optional)
: Node(mgr, std::move(name), parent),
children(this),
fieldType(fieldType),
optional(optional)
{
parent->addFieldDescriptor(this);
}
/* Class Descriptor */
void Descriptor::continueResolve(ResolutionState &state)
{
if (attributesDescriptor != nullptr) {
const NodeVector &attributes =
attributesDescriptor->getAttributes();
continueResolveComposita(attributes, attributes.getIndex(), state);
}
continueResolveComposita(fieldDescriptors, fieldDescriptors.getIndex(),
state);
}
void Descriptor::addFieldDescriptor(Handle fd)
{
checkUniqueName(this, fieldDescriptors, fd, "Descriptor",
"FieldDescriptor");
fieldDescriptors.push_back(fd);
}
std::vector> Descriptor::pathTo(
Handle target) const
{
std::vector> path;
continuePath(target, path);
return path;
}
bool Descriptor::continuePath(Handle target,
std::vector> ¤tPath,
std::set ignoredFields,
bool exploreSuperclass,
bool exploreSubclasses) const
{
// check if we are at the target already
if (this == target) {
return true;
}
// a variable to determine if we already found a solution
bool found = false;
// the currently optimal path.
std::vector> optimum;
// use recursive depth-first search from the top to reach the given child
for (auto &fd : fieldDescriptors) {
if (!(ignoredFields.insert(fd->getName()).second)) {
// if we want to ignore that field, we continue.
continue;
}
for (auto &c : fd->getChildren()) {
// check if a child is the target node.
if (c == target) {
// if we have made the connection, stop the search.
currentPath.push_back(fd);
return true;
}
// look for transparent intermediate nodes.
if (c->transparent) {
// copy the path.
std::vector> cPath = currentPath;
cPath.push_back(fd);
cPath.push_back(c);
// recursion.
if (c->continuePath(target, cPath) &&
(!found || optimum.size() > cPath.size())) {
// look if this path is better than the current optimum.
optimum = std::move(cPath);
found = true;
}
}
}
}
if (isa(RttiTypes::StructuredClass)) {
const StructuredClass *tis = static_cast(this);
/*
* if this is a StructuredClass, we can also use the super class
* (at least for fields that are not overridden)
*/
if (exploreSuperclass && tis->getSuperclass() != nullptr) {
// copy the path.
std::vector> cPath = currentPath;
if (tis->getSuperclass()->continuePath(target, cPath, ignoredFields,
true, false) &&
(!found || optimum.size() > cPath.size())) {
// look if this path is better than the current optimum.
optimum = std::move(cPath);
found = true;
}
}
// we also can call the subclasses.
if (exploreSubclasses) {
for (auto &c : tis->getSubclasses()) {
// copy the path.
std::vector> cPath = currentPath;
if (c->continuePath(target, cPath, {}, false) &&
(!found || optimum.size() > cPath.size())) {
// look if this path is better than the current optimum.
optimum = std::move(cPath);
found = true;
}
}
}
}
// put the optimum in the given path reference.
currentPath = std::move(optimum);
// return if we found something.
return found;
}
void Descriptor::copyFieldDescriptor(Handle fd)
{
if (fd->getFieldType() == FieldDescriptor::FieldType::PRIMITIVE) {
/*
*To call the "new" operation is enough here, because the
* constructor will add the newly constructed FieldDescriptor to this
* Descriptor automatically.
*/
new FieldDescriptor(getManager(), this, fd->getPrimitiveType(),
fd->getName(), fd->optional);
} else {
new FieldDescriptor(getManager(), this, fd->getFieldType(),
fd->getName(), fd->optional);
}
}
/* Class StructuredClass */
StructuredClass::StructuredClass(Manager &mgr, std::string name,
Handle domain,
const Cardinality &cardinality,
Handle attributesDescriptor,
Handle superclass,
bool transparent, bool root)
: Descriptor(mgr, std::move(name), domain, attributesDescriptor),
cardinality(cardinality),
superclass(acquire(superclass)),
subclasses(this),
transparent(transparent),
root(root)
{
if (superclass != nullptr) {
superclass->subclasses.push_back(this);
}
if (!domain.isNull()) {
domain->addStructuredClass(this);
}
}
/* Class AnnotationClass */
AnnotationClass::AnnotationClass(
Manager &mgr, std::string name, Handle domain,
// TODO: What would be a wise default value for attributes?
Handle attributesDescriptor)
: Descriptor(mgr, std::move(name), domain, attributesDescriptor)
{
if (!domain.isNull()) {
domain->addAnnotationClass(this);
}
}
/* Class Domain */
void Domain::continueResolve(ResolutionState &state)
{
if (!continueResolveComposita(structuredClasses,
structuredClasses.getIndex(), state) |
continueResolveComposita(annotationClasses,
annotationClasses.getIndex(), state)) {
continueResolveReferences(typesystems, state);
}
}
void Domain::addStructuredClass(Handle s)
{
checkUniqueName(this, structuredClasses, s, "Domain", "StructuredClass");
structuredClasses.push_back(s);
}
void Domain::addAnnotationClass(Handle a)
{
checkUniqueName(this, annotationClasses, a, "Domain", "AnnotationClass");
annotationClasses.push_back(a);
}
}
/* Type registrations */
namespace RttiTypes {
const Rtti FieldDescriptor =
RttiBuilder("FieldDescriptor").parent(&Node);
const Rtti Descriptor =
RttiBuilder("Descriptor").parent(&Node);
const Rtti StructuredClass =
RttiBuilder("StructuredClass").parent(&Descriptor).composedOf(
&FieldDescriptor);
const Rtti AnnotationClass =
RttiBuilder("AnnotationClass").parent(&Descriptor);
const Rtti Domain =
RttiBuilder("Domain").parent(&Node).composedOf(
{&StructuredClass, &AnnotationClass});
}
}