summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-01-16 16:34:09 +0100
committerAndreas Stöckel <andreas@somweyr.de>2015-01-16 16:34:09 +0100
commite3caf907184286b795fadc1991cf69348f97d192 (patch)
tree1167037d70ab4dfa23676ca5c8a23682b16b23b8 /src
parent9ea137094077eee7f7e80f25871cc91592982e4b (diff)
parent9929838e62d9c17647d74be54af5853e8b613c4b (diff)
Merge branch 'master' of somweyr.de:ousia
Diffstat (limited to 'src')
-rw-r--r--src/core/RangeSet.hpp51
-rw-r--r--src/core/managed/Managed.hpp21
-rw-r--r--src/core/model/Document.cpp113
-rw-r--r--src/core/model/Document.hpp2
-rw-r--r--src/core/model/Domain.cpp65
-rw-r--r--src/core/model/Domain.hpp30
6 files changed, 229 insertions, 53 deletions
diff --git a/src/core/RangeSet.hpp b/src/core/RangeSet.hpp
index 3b351c3..2c138dc 100644
--- a/src/core/RangeSet.hpp
+++ b/src/core/RangeSet.hpp
@@ -205,7 +205,7 @@ protected:
* end of the list if no such element was found.
*/
typename std::set<Range<T>, RangeComp<T>>::iterator firstOverlapping(
- const Range<T> &r, const bool allowNeighbours)
+ const Range<T> &r, const bool allowNeighbours) const
{
// Find the element with the next larger start value compared to the
// start value given in r.
@@ -265,7 +265,7 @@ public:
* @param r is the range for which the containment should be checked.
* @return true if the above condition is met, false otherwise.
*/
- bool contains(const Range<T> &r)
+ bool contains(const Range<T> &r) const
{
auto it = firstOverlapping(r, false);
if (it != ranges.end()) {
@@ -275,12 +275,29 @@ public:
}
/**
+ * Checks whether this range Set S contains a given value v, which is
+ * the case if at least one contained range R contains v.
+ *
+ * @param v is some value.
+ * @return true if at least one Range r returns true for r.inRange(v)
+ */
+ bool contains(const T &v) const
+ {
+ for (auto &r : ranges) {
+ if (r.inRange(v)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Checks whether this range set S1 contains the given range set S2:
*
* @param s is the range for which the containment should be checked.
* @return true if the above condition is met, false otherwise.
*/
- bool contains(const RangeSet<T> &s)
+ bool contains(const RangeSet<T> &s) const
{
bool res = true;
for (Range<T> &r : s.ranges) {
@@ -290,6 +307,29 @@ public:
}
/**
+ * Returns the minimum value that is still covered by this RangeSet.
+ *
+ * @return the minimum value that is still covered by this RangeSet.
+ */
+ T min() const { return ranges.begin()->start; }
+
+ /**
+ * Returns the maximum value that is still covered by this RangeSet.
+ *
+ * @return the maximum value that is still covered by this RangeSet.
+ */
+ T max() const
+ {
+ T max = ranges.begin()->end;
+ for (Range<T> &r : ranges) {
+ if (r.end > max) {
+ max = r.end;
+ }
+ }
+ return std::move(max);
+ }
+
+ /**
* Empties the set.
*/
void clear() { ranges.clear(); }
@@ -297,7 +337,10 @@ public:
/**
* Returns the current list of ranges as a const reference.
*/
- const std::set<Range<T>, RangeComp<T>> &getRanges() { return this->ranges; }
+ const std::set<Range<T>, RangeComp<T>> &getRanges() const
+ {
+ return this->ranges;
+ }
};
}
diff --git a/src/core/managed/Managed.hpp b/src/core/managed/Managed.hpp
index dd1a23a..e98e95e 100644
--- a/src/core/managed/Managed.hpp
+++ b/src/core/managed/Managed.hpp
@@ -94,6 +94,24 @@ public:
Manager &getManager() { return mgr; }
/**
+ * Returns the unique identifier (UID) of this object. Valid UIDs are
+ * positive non-zero values.
+ *
+ * @return the unique id of the object.
+ */
+ ManagedUid getUid() const
+ {
+ /*
+ * Dear Bjarne Stroustroup, dear gods of C++, please excuse this
+ * const_cast, for I did try other means but was not able to apply them
+ * and in my despair turned to this folly, this ugliness, this heresy!
+ * I pledge my life to better programming and promise that this cast
+ * will do no harm to anyone.
+ */
+ return mgr.getUid(const_cast<Managed *>(this));
+ }
+
+ /**
* Acquires a reference to the object wraped in the given handle -- creates
* a new Owned handle instance with this Managed instance as owner and the
* given object handle as the referenced object.
@@ -151,8 +169,7 @@ public:
* object. The event id must be used when unregistering event handlers.
*/
EventId registerEvent(EventType type, EventHandler handler,
- Handle<Managed> owner,
- void *data = nullptr);
+ Handle<Managed> owner, void *data = nullptr);
/**
* Unregisters the event handler with the given signature.
diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp
index 299b427..2f12acb 100644
--- a/src/core/model/Document.cpp
+++ b/src/core/model/Document.cpp
@@ -18,6 +18,9 @@
#include "Document.hpp"
+#include <map>
+#include <set>
+
#include <core/common/Exceptions.hpp>
#include <core/common/Rtti.hpp>
@@ -89,17 +92,121 @@ int DocumentEntity::getFieldDescriptorIndex(
}
}
+bool DocumentEntity::validate(Logger &logger) const
+{
+ // TODO: check the validated form of Attributes
+ // iterate over every field
+ for (unsigned int f = 0; f < fields.size(); f++) {
+ // we can do a faster check if this field is empty.
+ if (fields[f].size() == 0) {
+ // if this field is optional, an empty field is valid anyways.
+ if (descriptor->getFieldDescriptors()[f]->optional) {
+ continue;
+ }
+ /*
+ * if it is not optional we have to chack if zero is a valid
+ * cardinality.
+ */
+ for (auto &ac :
+ descriptor->getFieldDescriptors()[f]->getChildren()) {
+ const size_t min = ac->getCardinality().min();
+ if (min > 0) {
+ logger.error(
+ std::string("Field ") +
+ descriptor->getFieldDescriptors()[f]->getName() +
+ " was empty but needs at least " + std::to_string(min) +
+ " elements of class " + ac->getName() +
+ " according to the definition of " +
+ descriptor->getName());
+ return false;
+ }
+ }
+ continue;
+ }
+
+ // create a set of allowed classes identified by their unique id.
+ std::set<ManagedUid> accs;
+ for (auto &ac : descriptor->getFieldDescriptors()[f]->getChildren()) {
+ accs.insert(ac->getUid());
+ }
+ // store the actual numbers of children for each child class in a map
+ std::map<ManagedUid, unsigned int> nums;
+
+ // iterate over every actual child of this DocumentEntity
+ for (auto &rc : fields[f]) {
+ if (!rc->isa(RttiTypes::StructuredEntity)) {
+ continue;
+ }
+ Handle<StructuredEntity> c = rc.cast<StructuredEntity>();
+
+ ManagedUid id = c->getDescriptor()->getUid();
+ // check if its class is allowed.
+ bool allowed = accs.find(id) != accs.end();
+ /*
+ * if it is not allowed directly, we have to check if the class is a
+ * child of a permitted class.
+ */
+ if (!allowed) {
+ for (auto &ac :
+ descriptor->getFieldDescriptors()[f]->getChildren()) {
+ if (c->getDescriptor()
+ .cast<StructuredClass>()
+ ->isSubclassOf(ac)) {
+ allowed = true;
+ id = ac->getUid();
+ }
+ }
+ }
+ if (!allowed) {
+ logger.error(std::string("An instance of ") +
+ c->getDescriptor()->getName() +
+ " is not allowed as child of an instance of " +
+ descriptor->getName() + " in field " +
+ descriptor->getFieldDescriptors()[f]->getName());
+ return false;
+ }
+ // note the number of occurences.
+ const auto &n = nums.find(id);
+ if (n != nums.end()) {
+ n->second++;
+ } else {
+ nums.emplace(id, 1);
+ }
+ }
+
+ // now check if the cardinalities are right.
+ for (auto &ac : descriptor->getFieldDescriptors()[f]->getChildren()) {
+ const auto &n = nums.find(ac->getUid());
+ unsigned int num = 0;
+ if (n != nums.end()) {
+ num = n->second;
+ }
+ if (!ac->getCardinality().contains(num)) {
+ logger.error(
+ std::string("Field ") +
+ descriptor->getFieldDescriptors()[f]->getName() + " had " +
+ std::to_string(num) + " elements of class " +
+ ac->getName() +
+ ", which is invalid according to the definition of " +
+ descriptor->getName());
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
/* Class StructureNode */
StructureNode::StructureNode(Manager &mgr, std::string name,
Handle<Node> parent, const std::string &fieldName)
: Node(mgr, std::move(name), parent)
{
- if(parent->isa(RttiTypes::StructuredEntity)){
+ if (parent->isa(RttiTypes::StructuredEntity)) {
parent.cast<StructuredEntity>()->addStructureNode(this, fieldName);
- } else if(parent->isa(RttiTypes::AnnotationEntity)){
+ } else if (parent->isa(RttiTypes::AnnotationEntity)) {
parent.cast<AnnotationEntity>()->addStructureNode(this, fieldName);
- } else{
+ } else {
throw OusiaException("The proposed parent was no DocumentEntity!");
}
}
diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp
index be8b5c8..c70a6a3 100644
--- a/src/core/model/Document.hpp
+++ b/src/core/model/Document.hpp
@@ -256,6 +256,8 @@ public:
return fields[getFieldDescriptorIndex(fieldDescriptor, true)];
}
+ bool validate(Logger& logger) const;
+
// TODO: Change this to move methods.
// /**
// * This adds a StructureNode to the field with the given name. If an
diff --git a/src/core/model/Domain.cpp b/src/core/model/Domain.cpp
index f1b91cc..2ac2d8d 100644
--- a/src/core/model/Domain.cpp
+++ b/src/core/model/Domain.cpp
@@ -28,8 +28,7 @@ namespace model {
template <class T>
static void checkUniqueName(Handle<Node> parent, NodeVector<T> vec,
- Handle<T> child,
- const std::string &parentClassName,
+ Handle<T> child, const std::string &parentClassName,
const std::string &childClassName)
{
std::set<std::string> childNames;
@@ -37,6 +36,7 @@ static void checkUniqueName(Handle<Node> parent, NodeVector<T> vec,
childNames.insert(c->getName());
}
if (childNames.find(child->getName()) != childNames.end()) {
+ //TODO: Do we really want to have an exception here?
throw OusiaException(std::string("The ") + parentClassName + " " +
parent->getName() + " already has a " +
childClassName + " with name " + child->getName());
@@ -96,31 +96,15 @@ std::vector<Rooted<Node>> Descriptor::pathTo(
return path;
}
-static bool pathEquals(const Descriptor &a, const Descriptor &b)
-{
- // We assume that two Descriptors are equal if their names and domain names
- // are equal.
- if (a.getName() != b.getName()) {
- return false;
- }
- Handle<Domain> aDom = a.getParent().cast<Domain>();
- Handle<Domain> bDom = b.getParent().cast<Domain>();
- return aDom->getName() == bDom->getName();
-}
-
bool Descriptor::continuePath(Handle<StructuredClass> target,
std::vector<Rooted<Node>> &currentPath,
std::set<std::string> ignoredFields,
bool exploreSuperclass,
bool exploreSubclasses) const
{
- // TODO: REMOVE
- std::string targetName = target->getName();
- std::string thisName = getName();
- std::string currentPathName;
- for (auto &n : currentPath) {
- currentPathName += ".";
- currentPathName += n->getName();
+ // 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;
@@ -133,7 +117,8 @@ bool Descriptor::continuePath(Handle<StructuredClass> target,
continue;
}
for (auto &c : fd->getChildren()) {
- if (pathEquals(*c, *target)) {
+ // 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;
@@ -161,11 +146,11 @@ bool Descriptor::continuePath(Handle<StructuredClass> target,
* if this is a StructuredClass, we can also use the super class
* (at least for fields that are not overridden)
*/
- if (exploreSuperclass && !tis->getIsA().isNull()) {
+ if (exploreSuperclass && tis->getSuperclass() != nullptr) {
// copy the path.
std::vector<Rooted<Node>> cPath = currentPath;
- if (tis->getIsA()->continuePath(target, cPath, ignoredFields, true,
- false) &&
+ 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);
@@ -203,13 +188,11 @@ void Descriptor::copyFieldDescriptor(Handle<FieldDescriptor> fd)
* constructor will add the newly constructed FieldDescriptor to this
* Descriptor automatically.
*/
- new FieldDescriptor(getManager(), this,
- fd->getPrimitiveType(),
- fd->getName(), fd->optional);
+ new FieldDescriptor(getManager(), this, fd->getPrimitiveType(),
+ fd->getName(), fd->optional);
} else {
- new FieldDescriptor(getManager(), this,
- fd->getFieldType(),
- fd->getName(), fd->optional);
+ new FieldDescriptor(getManager(), this, fd->getFieldType(),
+ fd->getName(), fd->optional);
}
}
@@ -219,23 +202,33 @@ StructuredClass::StructuredClass(Manager &mgr, std::string name,
Handle<Domain> domain,
const Cardinality &cardinality,
Handle<StructType> attributesDescriptor,
- Handle<StructuredClass> isa, bool transparent,
- bool root)
+ Handle<StructuredClass> superclass,
+ bool transparent, bool root)
: Descriptor(mgr, std::move(name), domain, attributesDescriptor),
cardinality(cardinality),
- isa(acquire(isa)),
+ superclass(acquire(superclass)),
subclasses(this),
transparent(transparent),
root(root)
{
- if (!isa.isNull()) {
- isa->subclasses.push_back(this);
+ if (superclass != nullptr) {
+ superclass->subclasses.push_back(this);
}
if (!domain.isNull()) {
domain->addStructuredClass(this);
}
}
+bool StructuredClass::isSubclassOf(Handle<StructuredClass> c) const{
+ if(c == nullptr || superclass == nullptr){
+ return false;
+ }
+ if(c == superclass){
+ return true;
+ }
+ return superclass->isSubclassOf(c);
+}
+
/* Class AnnotationClass */
AnnotationClass::AnnotationClass(
diff --git a/src/core/model/Domain.hpp b/src/core/model/Domain.hpp
index 791d563..ac02ec7 100644
--- a/src/core/model/Domain.hpp
+++ b/src/core/model/Domain.hpp
@@ -324,6 +324,10 @@ public:
*/
const NodeVector<StructuredClass> &getChildren() const { return children; }
+ /*
+ *TODO: This should check whether another class is permitted that is a
+ * superclass of this one.
+ */
/**
* Adds a StructuredClass whose instances shall be allowed as children in
* the StructureTree of instances of this field.
@@ -546,7 +550,7 @@ typedef RangeSet<size_t> Cardinality;
class StructuredClass : public Descriptor {
private:
const Cardinality cardinality;
- Owned<StructuredClass> isa;
+ Owned<StructuredClass> superclass;
NodeVector<StructuredClass> subclasses;
public:
@@ -570,7 +574,7 @@ public:
* @param attributesDescriptor is a StructType that specifies the attribute
* keys as well as value domains for this
* Descriptor.
- * @param isa references a parent StructuredClass. Please
+ * @param superclass references a parent StructuredClass. Please
* look for more information on inheritance in
* the class documentation above. The default is
* a null reference, meaning no super class.
@@ -585,7 +589,7 @@ public:
const Cardinality &cardinality,
Handle<StructType> attributesDescriptor = nullptr,
// TODO: What would be a wise default value for isa?
- Handle<StructuredClass> isa = nullptr,
+ Handle<StructuredClass> superclass = nullptr,
bool transparent = false, bool root = false);
/**
@@ -596,13 +600,23 @@ public:
const Cardinality &getCardinality() const { return cardinality; }
/**
- * Returns the parent of this StructuredClass in the class inheritance
- * hierarchy (!). This is not the same as the parents in the Structure Tree!
+ * Returns the superclass of this StructuredClass. This is not the same as
+ * the parents in the Structure Tree!
+ *
+ * @return the superclass of this StructuredClass.
+ */
+ Rooted<StructuredClass> getSuperclass() const { return superclass; }
+
+ /**
+ * Returns true if this class is a subclass of the given class. It does not
+ * return true if the other class is equal to the given class.
+ *
+ * @param c is another class that might or might not be a superclass of this
+ * one
+ * @return true if this class is a subclass of the given class.
*
- * @return the parent of this StructuredClass in the class inheritance
- * hierarchy (!).
*/
- Rooted<StructuredClass> getIsA() const { return isa; }
+ bool isSubclassOf(Handle<StructuredClass> c) const;
/**
* Returns the StructuredClasses that are subclasses of this class. This