From 05fa2abbb0652f4b8fafc998b6c7153c0b1376ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Borna=20Rajkovi=C4=87?= Date: Sun, 15 May 2022 11:17:05 +0200 Subject: [PATCH] Refactored function validators --- comdel/domain/addressspace.cpp | 1 + comdel/domain/comdelvalidator.cpp | 2 +- comdel/domain/comdelvalidator.h | 13 ++- comdel/domain/functionsignature.cpp | 165 ++++++++++++++++++++++------ comdel/domain/functionsignature.h | 48 ++++++-- comdel/domain/rule.cpp | 2 +- comdel/domain/rule.h | 2 +- comdel/domain/schemacreator.cpp | 16 +-- comdel/domain/schemacreator.h | 4 +- mainwindow.cpp | 14 +-- mainwindow.h | 2 +- 11 files changed, 195 insertions(+), 74 deletions(-) diff --git a/comdel/domain/addressspace.cpp b/comdel/domain/addressspace.cpp index a573f8d..076d271 100644 --- a/comdel/domain/addressspace.cpp +++ b/comdel/domain/addressspace.cpp @@ -1,3 +1,4 @@ +#include #include "addressspace.h" namespace domain { diff --git a/comdel/domain/comdelvalidator.cpp b/comdel/domain/comdelvalidator.cpp index f2fad6e..da9736a 100644 --- a/comdel/domain/comdelvalidator.cpp +++ b/comdel/domain/comdelvalidator.cpp @@ -61,7 +61,7 @@ std::optional ComdelValidator::validateRule(Rule rule, Validati RuleContext ruleContext; ruleContext.addressSpaces = context.addressSpaces; ruleContext.attributes = context.attributes; - ruleContext.function = callbacks; + ruleContext.function = validators; auto action = rule.evaluate(ruleContext); if (action) { std::string message = this->populateMessage(action->getMessage(), context); diff --git a/comdel/domain/comdelvalidator.h b/comdel/domain/comdelvalidator.h index e801062..387b478 100644 --- a/comdel/domain/comdelvalidator.h +++ b/comdel/domain/comdelvalidator.h @@ -29,14 +29,19 @@ public: std::vector validateAttribute(InstanceAttribute *attribute, ValidationContext context); std::optional validateRule(Rule rule, ValidationContext context); - ComdelValidator(std::map callbacks): callbacks(callbacks) {} + ComdelValidator(std::vector validators) { + for(auto* validator: validators) { + validator->clear(); + this->validators.insert(std::make_pair(validator->getName(), validator)); + } + } private: - std::map callbacks; + std::map validators; - std::string populateMessage(string basicString, ValidationContext context); + std::string populateMessage(string message, ValidationContext context); - string replacePlaceholder(string basicString, const string basicString1, Value value); + string replacePlaceholder(string message, const string name, Value value); }; } diff --git a/comdel/domain/functionsignature.cpp b/comdel/domain/functionsignature.cpp index 4f9aa23..575cfae 100644 --- a/comdel/domain/functionsignature.cpp +++ b/comdel/domain/functionsignature.cpp @@ -1,45 +1,138 @@ +#include #include "functionsignature.h" namespace domain { -FunctionSignature add(std::string name, std::vector types, FunctionCallback callback) { - return {name, types, callback}; +class DivisibleValidator: public FunctionValidator { +public: + DivisibleValidator(): FunctionValidator("divisible", {Value::INT, Value::INT}) {} + + bool validate(std::vector values) override { + if(validateSignature(values)) { + long long first = values[0].asInt(); + long long second = values[1].asInt(); + return (first % second) == 0; + } + return false; + } + void clear() override {} +}; + +class LessThenValidator: public FunctionValidator { +public: + LessThenValidator(): FunctionValidator("less_then", {Value::INT, Value::INT}) {} + + bool validate(std::vector values) override { + if(validateSignature(values)) { + long long first = values[0].asInt(); + long long second = values[1].asInt(); + return first < second; + } + return false; + } + void clear() override {} +}; + +class GreaterThenValidator: public FunctionValidator { +public: + GreaterThenValidator(): FunctionValidator("greater_then", {Value::INT, Value::INT}) {} + + bool validate(std::vector values) override { + if(validateSignature(values)) { + long long first = values[0].asInt(); + long long second = values[1].asInt(); + return first > second; + } + return false; + } + void clear() override {} +}; + + +class ContainsAddressValidator: public FunctionValidator { +public: + ContainsAddressValidator(): FunctionValidator("contains_address", {Value::ADDRESS_SPACE, Value::INT}) {} + + bool validate(std::vector values) override { + if(validateSignature(values)) { + AddressSpace space = values[0].asAddressSpace(); + long long address = values[1].asInt(); + return space.contains(address); + } + return false; + } + void clear() override {} +}; + + +class ContainsValidator: public FunctionValidator { +public: + ContainsValidator(): FunctionValidator("contains", {Value::ADDRESS_SPACE, Value::INT, Value::INT}) {} + + bool validate(std::vector values) override { + if(validateSignature(values)) { + AddressSpace space = values[0].asAddressSpace(); + long long start = values[1].asInt(); + long long size = values[1].asInt(); + return space.contains(start, start + size); + } + return false; + } + void clear() override {} +}; + + + + +class UniqueValidator: public FunctionValidator { + +private: + std::map>> spaces; + + bool overlaps(long long int start1, long long int end1, long long int start2, long long int end2) { + return std::max((long long int)0, std::min(end1, end2) - std::max(start1, start2)) > 0; + } + +public: + UniqueValidator(): FunctionValidator("unique", {Value::ADDRESS_SPACE, Value::INT, Value::INT}) {} + + bool validate(std::vector values) override { + if(validateSignature(values)) { + std::string space = values[0].asAddressSpace().getName(); + long long int start = values[1].asInt(); + long long int end = start + values[2].asInt(); + if(spaces.count(space) == 0) { + spaces.insert(std::make_pair(space, std::vector>{})); + } + for(auto& s: spaces[space]) { + if(overlaps(s.first, s.second, start, end)) { + return false; + } + } + spaces[space].push_back(std::make_pair(start, end)); + return true; + } + return false; + } + void clear() override { + spaces.clear(); + } +}; + + +std::vector getSupportedValidators() { + std::vector validators; + + validators.push_back(new DivisibleValidator()); + validators.push_back(new LessThenValidator()); + validators.push_back(new GreaterThenValidator()); + validators.push_back(new ContainsAddressValidator()); + validators.push_back(new ContainsValidator()); + validators.push_back(new UniqueValidator()); + + return validators; } -std::vector getSupportedFunctions() { - std::vector s; - s.push_back(add("divisible", std::vector{Value::INT, Value::INT},[](std::vector values) { - long long first = values[0].asInt(); - long long second = values[1].asInt(); - return (first % second) == 0; - })); - s.push_back(add("less_then", std::vector{Value::INT, Value::INT}, [](std::vector values) { - long long first = values[0].asInt(); - long long second = values[1].asInt(); - return first < second; - })); - s.push_back(add("greater_then", std::vector{Value::INT, Value::INT}, [](std::vector values) { - long long first = values[0].asInt(); - long long second = values[1].asInt(); - return first > second; - })); - s.push_back(add("contains_address", std::vector{Value::ADDRESS_SPACE, Value::INT}, [](std::vector values) { - AddressSpace space = values[0].asAddressSpace(); - long long address = values[1].asInt(); - return space.contains(address); - })); - s.push_back(add("contains", std::vector{Value::ADDRESS_SPACE, Value::INT, Value::INT}, [](std::vector values) { - AddressSpace space = values[0].asAddressSpace(); - long long start = values[1].asInt(); - long long size = values[1].asInt(); - return space.contains(start, start + size); - })); - s.push_back(add("unique", std::vector{Value::ADDRESS_SPACE, Value::INT, Value::INT}, [](std::vector values) { - return true; - })); - - return s; -} } // namespace domain diff --git a/comdel/domain/functionsignature.h b/comdel/domain/functionsignature.h index 9defddd..961628d 100644 --- a/comdel/domain/functionsignature.h +++ b/comdel/domain/functionsignature.h @@ -1,5 +1,5 @@ -#ifndef DOMAIN_FUNCTION_SIGNATURE_H -#define DOMAIN_FUNCTION_SIGNATURE_H +#ifndef DOMAIN_FUNCTION_VALIDATOR_H +#define DOMAIN_FUNCTION_VALIDATOR_H #include #include @@ -8,18 +8,46 @@ namespace domain { -typedef std::function)> FunctionCallback; - -struct FunctionSignature { +class FunctionValidator { +private: std::string name; - std::vector params; - FunctionCallback callback; + std::vector signature; - FunctionSignature(std::string name, std::vector params, FunctionCallback callback): name(name), params(params), callback(callback) {} +protected: + FunctionValidator(std::string name, std::vector signature) { + this->name = name; + this->signature = signature; + } + +public: + + std::string getName() { + return name; + } + + std::vector getSignature() { + return signature; + } + + bool validateSignature(std::vector signature) { + if(this->signature.size() != signature.size()) { + return false; + } + + for(int i=0; isignature.size(); i++) { + if(this->signature[i] != signature[i].getType()) { + return false; + } + } + return true; + } + + virtual bool validate(std::vector values) = 0; + virtual void clear() = 0; }; -std::vector getSupportedFunctions(); +std::vector getSupportedValidators(); } // namespace domain -#endif // DOMAIN_FUNCTIONSIGNATURE_H +#endif // DOMAIN_FUNCTION_VALIDATOR_H diff --git a/comdel/domain/rule.cpp b/comdel/domain/rule.cpp index 3204d00..9619235 100644 --- a/comdel/domain/rule.cpp +++ b/comdel/domain/rule.cpp @@ -17,7 +17,7 @@ bool Condition::evaluate(RuleContext &context) { request.push_back(params[i]); } } - bool result = context.function[function](request); + bool result = context.function[function]->validate(request); return negated ? !result : result; } diff --git a/comdel/domain/rule.h b/comdel/domain/rule.h index 2bbc0d0..26caed5 100644 --- a/comdel/domain/rule.h +++ b/comdel/domain/rule.h @@ -15,7 +15,7 @@ namespace domain { struct RuleContext { std::map addressSpaces; std::map attributes; - std::map function; + std::map function; }; class Condition { diff --git a/comdel/domain/schemacreator.cpp b/comdel/domain/schemacreator.cpp index ce9c0c8..3fe8d2f 100644 --- a/comdel/domain/schemacreator.cpp +++ b/comdel/domain/schemacreator.cpp @@ -102,8 +102,8 @@ Popup::PopupType toType(PopupNode::PopupType type) return Popup::ON_DEMAND; } -SchemaCreator::SchemaCreator(std::vector signatures) - : signatures(std::move(signatures)) +SchemaCreator::SchemaCreator(std::vector validators) + : validators(std::move(validators)) {} std::optional SchemaCreator::loadLibrary(LibraryNode node) @@ -736,19 +736,19 @@ std::optional SchemaCreator::loadCondition(ConditionNode node) { std::string function = node.functionName.value; - for(auto & signature : signatures) { - if(signature.name == function) { - if(signature.params.size() == node.params.size()) { + for(auto & validator : validators) { + if(validator->getName() == function) { + if(validator->getSignature().size() == node.params.size()) { std::vector params; - for(uint j=0; jgetSignature().size(); j++) { bool exists = false; auto type = toType(node.params[j]); if (type.getType() == Value::UNDEFINED) { - if(current().doesAttributeExists(type.asReference(), signature.params[j])) { + if(current().doesAttributeExists(type.asReference(), validator->getSignature()[j])) { exists = true; type = Value::fromReference(type.asReference(), Value::ATTRIBUTE_REFERENCE); } - if(signature.params[j] == Value::ADDRESS_SPACE) { + if(validator->getSignature()[j] == Value::ADDRESS_SPACE) { if(hasAddressSpace(type.asReference())) { exists = true; type = Value::fromReference(type.asReference(), Value::ADDRESS_SPACE_REFERENCE); diff --git a/comdel/domain/schemacreator.h b/comdel/domain/schemacreator.h index 8ab600a..a0a8af2 100644 --- a/comdel/domain/schemacreator.h +++ b/comdel/domain/schemacreator.h @@ -61,7 +61,7 @@ class SchemaCreator std::vector errors; - std::vector signatures; + std::vector validators; std::optional loadAddressSpace(AddressSpaceNode node); std::optional loadComponent(ComponentNode node); @@ -130,7 +130,7 @@ class SchemaCreator } public: - SchemaCreator(std::vector signatures); + SchemaCreator(std::vector validators); std::vector getErrors() { return errors; diff --git a/mainwindow.cpp b/mainwindow.cpp index e0dc26b..4020308 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -24,7 +24,7 @@ MainWindow::MainWindow(QWidget *parent) setupUi(); // define allowed methods - signatures = domain::getSupportedFunctions(); + validators = domain::getSupportedValidators(); } void MainWindow::setupUi() @@ -79,7 +79,7 @@ void MainWindow::onLoadLibrary() { ParseContext parseContext; auto libraryNode = loadLibraryFromFile(&parseContext, filename.toStdString().c_str(), buffer); if(libraryNode) { - domain::SchemaCreator generator(signatures); + domain::SchemaCreator generator(validators); library = generator.loadLibrary(*libraryNode); for (auto& error : generator.getErrors()) { @@ -117,7 +117,7 @@ void MainWindow::onLoadSchema() { auto schemaNode = loadSchemaFromFile(&parseContext, filename.toStdString().c_str(), buffer); if(schemaNode) { - domain::SchemaCreator generator(signatures); + domain::SchemaCreator generator(validators); library = generator.loadLibrary(*schemaNode->library); librarySource = schemaNode->source->value; @@ -190,13 +190,7 @@ void MainWindow::onValidateSchema(bool /*toggled*/) { this->validationErrors.clear(); - std::map callbacks; - auto functions = domain::getSupportedFunctions(); - for(auto &func: functions) { - callbacks[func.name] = func.callback; - } - - domain::ComdelValidator validator{callbacks}; + domain::ComdelValidator validator{validators}; domain::ValidationContext context; context.instance = nullptr; diff --git a/mainwindow.h b/mainwindow.h index 1bce853..02a5164 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -30,7 +30,7 @@ public: std::optional library = std::nullopt; domain::Schema* schema = nullptr; - std::vector signatures; + std::vector validators; void setupUi(); void clear();