diff options
Diffstat (limited to 'src/core/model')
-rw-r--r-- | src/core/model/Document.cpp | 62 | ||||
-rw-r--r-- | src/core/model/Domain.cpp | 481 | ||||
-rw-r--r-- | src/core/model/Domain.hpp | 68 | ||||
-rw-r--r-- | src/core/model/Typesystem.cpp | 21 | ||||
-rw-r--r-- | src/core/model/Typesystem.hpp | 69 |
5 files changed, 427 insertions, 274 deletions
diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp index a2ba5cf..4e101fc 100644 --- a/src/core/model/Document.cpp +++ b/src/core/model/Document.cpp @@ -135,6 +135,15 @@ bool DocumentEntity::doValidate(Logger &logger) const continue; } + std::unordered_set<StructuredClass *> childClasses; + { + NodeVector<StructuredClass> tmp = + fieldDescs[f]->getChildrenWithSubclasses(); + for (auto s : tmp) { + childClasses.insert(s.get()); + } + } + // 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. @@ -145,7 +154,7 @@ bool DocumentEntity::doValidate(Logger &logger) const * if it is not optional we have to check if zero is a valid * cardinality. */ - for (auto childClass : fieldDescs[f]->getChildren()) { + for (auto childClass : childClasses) { const size_t min = childClass->getCardinality().asCardinality().min(); if (min > 0) { @@ -163,15 +172,10 @@ bool DocumentEntity::doValidate(Logger &logger) const continue; } - // create a set of allowed classes identified by their unique id. - std::set<ManagedUid> childClasses; - for (auto &childClass : fieldDescs[f]->getChildren()) { - childClasses.insert(childClass->getUid()); - } // store the actual numbers of children for each child class in a map - std::map<ManagedUid, unsigned int> nums; + std::unordered_map<StructuredClass *, unsigned int> nums; - // iterate over every actual child of this DocumentEntity + // iterate over every actual child of this field for (auto child : fields[f]) { // check if the parent reference is correct. if (child->getParent() != subInst) { @@ -195,25 +199,11 @@ bool DocumentEntity::doValidate(Logger &logger) const } // otherwise this is a StructuredEntity Handle<StructuredEntity> c = child.cast<StructuredEntity>(); + StructuredClass *classPtr = + c->getDescriptor().cast<StructuredClass>().get(); - ManagedUid id = c->getDescriptor()->getUid(); // check if its class is allowed. - bool allowed = childClasses.find(id) != childClasses.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 childClass : fieldDescs[f]->getChildren()) { - if (c->getDescriptor() - .cast<StructuredClass>() - ->isSubclassOf(childClass)) { - allowed = true; - id = childClass->getUid(); - } - } - } - if (!allowed) { + if (childClasses.find(classPtr) == childClasses.end()) { logger.error( std::string("An instance of \"") + c->getDescriptor()->getName() + @@ -224,18 +214,24 @@ bool DocumentEntity::doValidate(Logger &logger) const valid = false; continue; } - // note the number of occurences. - const auto &n = nums.find(id); - if (n != nums.end()) { - n->second++; - } else { - nums.emplace(id, 1); + // note the number of occurences for this class and all + // superclasses, because a subclass instance should count for + // superclasses as well. + while (classPtr != nullptr && + childClasses.find(classPtr) != childClasses.end()) { + const auto &n = nums.find(classPtr); + if (n != nums.end()) { + n->second++; + } else { + nums.emplace(classPtr, 1); + } + classPtr = classPtr->getSuperclass().get(); } } // now check if the cardinalities are right. - for (auto childClass : fieldDescs[f]->getChildren()) { - const auto &n = nums.find(childClass->getUid()); + for (auto childClass : childClasses) { + const auto &n = nums.find(childClass); unsigned int num = 0; if (n != nums.end()) { num = n->second; 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 diff --git a/src/core/model/Domain.hpp b/src/core/model/Domain.hpp index d921a9c..081435a 100644 --- a/src/core/model/Domain.hpp +++ b/src/core/model/Domain.hpp @@ -275,6 +275,17 @@ public: const NodeVector<StructuredClass> &getChildren() const { return children; } /** + * Returns all StructuredClasses whose instances are allowed as children in + * the Structure Tree of instances of this field including subclasses of + * children, which are allowed directly. + * + * @return all StructuredClasses whose instances are allowed as children in + * the Structure Tree of instances of this field including subclasses of + * children, which are allowed directly. + */ + NodeVector<StructuredClass> getChildrenWithSubclasses() const; + + /** * Adds a StructuredClass whose instances shall be allowed as children in * the StructureTree of instances of this field. */ @@ -368,6 +379,60 @@ public: invalidate(); optional = std::move(o); } + + /** + * This tries to construct the shortest possible path of this Descriptor + * to the given child Descriptor. Note that this method has the problem that + * an empty return path does NOT strictly imply that no such path could + * be constructed: We also return an empty vector if the given + * Descriptor is a direct child. Therefore we also return a bool value + * indicating that the path is valid or not. + * + * Implicitly this does a breadth-first search on the graph of + * StructuredClasses that are transparent. It also takes care of cycles. + * + * @param childDescriptor is a supposedly valid child Descriptor of this + * Descriptor. + * @return a tuple containing a path of FieldDescriptors and + * StructuredClasses between this Descriptor and the + * input Descriptor and a bool value indicating if + * the construction was successful. + * + */ + std::pair<NodeVector<Node>, bool> pathTo( + Handle<StructuredClass> childDescriptor, Logger &logger) const; + /** + * This tries to construct the shortest possible path of this Descriptor + * to the given FieldDescriptor. Note that this method has the problem that + * an empty return path does NOT strictly imply that no such path could + * be constructed: We also return an empty vector if the given + * FieldDescriptor is a direct child. Therefore we also return a bool value + * indicating that the path is valid or not. + * + * + * Implicitly this does a breadth-first search on the graph of + * StructuredClasses that are transparent. It also takes care of cycles. + * + * @param field is a FieldDescriptor that may be allowed as child of this + * Descriptor. + * @return a path of FieldDescriptors and StructuredClasses between + * this Descriptor and the input FieldDescriptor or an empty + * vector if no such path could be constructed. + */ + NodeVector<Node> pathTo(Handle<FieldDescriptor> field, + Logger &logger) const; + + /** + * Returns a vector of all TREE fields that are allowed as structure tree + * children of an instance of this Descriptor. This also makes use of + * transparency. + * The list is sorted by the number of transparent elements that have to be + * constructed to arrive at the respective FieldDescriptor. + * + * @return a vector of all TREE fields that are allowed as structure tree + * children of an instance of this Descriptor. + */ + NodeVector<FieldDescriptor> getDefaultFields() const; }; /** @@ -1111,5 +1176,4 @@ extern const Rtti Domain; } } -#endif /* _OUSIA_MODEL_DOMAIN_HPP_ */ - +#endif /* _OUSIA_MODEL_DOMAIN_HPP_ */
\ No newline at end of file diff --git a/src/core/model/Typesystem.cpp b/src/core/model/Typesystem.cpp index fb99f87..df2b9fb 100644 --- a/src/core/model/Typesystem.cpp +++ b/src/core/model/Typesystem.cpp @@ -109,6 +109,14 @@ bool StringType::doBuild(Variant &data, Logger &logger, return VariantConverter::toString(data, logger); } +/* Class CardinalityType */ + +bool CardinalityType::doBuild(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const +{ + return VariantConverter::toCardinality(data, logger); +} + /* Class EnumType */ EnumType::EnumType(Manager &mgr, std::string name, Handle<Typesystem> system) @@ -769,12 +777,14 @@ SystemTypesystem::SystemTypesystem(Manager &mgr) stringType(new StringType(mgr, this)), intType(new IntType(mgr, this)), doubleType(new DoubleType(mgr, this)), - boolType(new BoolType(mgr, this)) + boolType(new BoolType(mgr, this)), + cardinalityType(new CardinalityType(mgr, this)) { addType(stringType); addType(intType); addType(doubleType); addType(boolType); + addType(cardinalityType); } /* RTTI type registrations */ @@ -787,6 +797,8 @@ const Rtti IntType = RttiBuilder<ousia::IntType>("IntType").parent(&Type); const Rtti DoubleType = RttiBuilder<ousia::DoubleType>("DoubleType").parent(&Type); const Rtti BoolType = RttiBuilder<ousia::BoolType>("BoolType").parent(&Type); +const Rtti CardinalityType = + RttiBuilder<ousia::CardinalityType>("CardinalityType").parent(&Type); const Rtti EnumType = RttiBuilder<ousia::EnumType>("EnumType").parent(&Type); const Rtti StructType = RttiBuilder<ousia::StructType>("StructType") .parent(&Type) @@ -798,10 +810,9 @@ const Rtti Constant = RttiBuilder<ousia::Constant>("Constant").parent(&Node); const Rtti Attribute = RttiBuilder<ousia::Attribute>("Attribute").parent(&Node); const Rtti Typesystem = RttiBuilder<ousia::Typesystem>("Typesystem").parent(&RootNode).composedOf( - {&StringType, &IntType, &DoubleType, &BoolType, &EnumType, &StructType, - &Constant}); + {&StringType, &IntType, &DoubleType, &BoolType, &CardinalityType, + &EnumType, &StructType, &Constant}); const Rtti SystemTypesystem = RttiBuilder<ousia::SystemTypesystem>( "SystemTypesystem").parent(&Typesystem); } -} - +}
\ No newline at end of file diff --git a/src/core/model/Typesystem.hpp b/src/core/model/Typesystem.hpp index 53fb0df..39f777f 100644 --- a/src/core/model/Typesystem.hpp +++ b/src/core/model/Typesystem.hpp @@ -386,6 +386,55 @@ public: }; /** + * The CardinalityType class represents the cardinality type. There should be + * exactly one instance of this class available in a preloaded type system. + */ +class CardinalityType : public Type { +protected: + /** + * Expects the given variant to be a cardinality or a single int. + * + * @param data is a variant containing the data that should be checked. + * @param logger is the Logger instance into which errors should be written. + * @return true if the conversion was successful, false otherwise. + */ + bool doBuild(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const override; + +public: + /** + * Constructor of the CardinalityType class. Only one instance of + *CardinalityType should + * exist per project graph. + * + * @param mgr is the Manager instance to be used for the Node. + * @param name is the name of the type. + * @param system is a reference to the parent Typesystem instance. + */ + CardinalityType(Manager &mgr, Handle<Typesystem> system) + : Type(mgr, "cardinality", system, true) + { + } + + /** + * Creates a variant with the cardinality value "any". + * + * @return a Variant with the cardinality value "any". + */ + Variant create() const override { return Variant{Cardinality::any()}; } + + /** + * Returns the cardinality VariantType. + * + * @return the cardinality VariantType. + */ + std::vector<VariantType> getVariantTypes() const override + { + return {VariantType::CARDINALITY}; + } +}; + +/** * The EnumType class represents a user defined enumeration type. */ class EnumType : public Type { @@ -1298,6 +1347,11 @@ private: */ Handle<BoolType> boolType; + /** + * Reference to the cardinality type. + */ + Handle<CardinalityType> cardinalityType; + public: /** * Creates the SystemTypesystem containing all basic types (string, int, @@ -1335,6 +1389,13 @@ public: * @return a reference to the primitive BoolType instance. */ Rooted<BoolType> getBoolType() { return boolType; } + + /** + * Returns the cardinality type. + * + * @return a reference to the CardinalityType instance. + */ + Rooted<CardinalityType> getCardinalityType() { return cardinalityType; } }; /* RTTI type registrations */ @@ -1366,6 +1427,11 @@ extern const Rtti DoubleType; extern const Rtti BoolType; /** + * Type information for the CardinalityType class. + */ +extern const Rtti CardinalityType; + +/** * Type information for the EnumType class. */ extern const Rtti EnumType; @@ -1407,5 +1473,4 @@ extern const Rtti SystemTypesystem; } } -#endif /* _OUSIA_MODEL_TYPESYSTEM_HPP_ */ - +#endif /* _OUSIA_MODEL_TYPESYSTEM_HPP_ */
\ No newline at end of file |