diff options
| author | Benjamin Paassen <bpaassen@techfak.uni-bielefeld.de> | 2015-01-16 15:20:49 +0100 | 
|---|---|---|
| committer | Benjamin Paassen <bpaassen@techfak.uni-bielefeld.de> | 2015-01-16 15:20:49 +0100 | 
| commit | 9929838e62d9c17647d74be54af5853e8b613c4b (patch) | |
| tree | 732446f234419a0f1baa5208722e9236affd74bc /src | |
| parent | 8cf24170a4998e316c1b9c9bfd2b56e266c544cd (diff) | |
validate function for Domain::Descriptor.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/RangeSet.hpp | 51 | ||||
| -rw-r--r-- | src/core/model/Document.cpp | 107 | ||||
| -rw-r--r-- | src/core/model/Document.hpp | 2 | ||||
| -rw-r--r-- | src/core/model/Domain.cpp | 11 | ||||
| -rw-r--r-- | src/core/model/Domain.hpp | 15 | 
5 files changed, 182 insertions, 4 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/model/Document.cpp b/src/core/model/Document.cpp index fb39384..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,6 +92,110 @@ 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, 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 b4fea3c..2ac2d8d 100644 --- a/src/core/model/Domain.cpp +++ b/src/core/model/Domain.cpp @@ -36,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()); @@ -218,6 +219,16 @@ StructuredClass::StructuredClass(Manager &mgr, std::string name,  	}  } +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 8bc21e9..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. @@ -602,6 +606,17 @@ public:  	 * @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. +	 * +	 */ +	bool isSubclassOf(Handle<StructuredClass> c) const;  	/**  	 * Returns the StructuredClasses that are subclasses of this class. This | 
