Refactored function validators

This commit is contained in:
Borna Rajković 2022-05-15 11:17:05 +02:00
parent e7fd7df154
commit 05fa2abbb0
11 changed files with 195 additions and 74 deletions

View File

@ -1,3 +1,4 @@
#include <algorithm>
#include "addressspace.h"
namespace domain {

View File

@ -61,7 +61,7 @@ std::optional<ValidationError> 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);

View File

@ -29,14 +29,19 @@ public:
std::vector<ValidationError> validateAttribute(InstanceAttribute *attribute, ValidationContext context);
std::optional<ValidationError> validateRule(Rule rule, ValidationContext context);
ComdelValidator(std::map<std::string, FunctionCallback> callbacks): callbacks(callbacks) {}
ComdelValidator(std::vector<FunctionValidator*> validators) {
for(auto* validator: validators) {
validator->clear();
this->validators.insert(std::make_pair(validator->getName(), validator));
}
}
private:
std::map<std::string, FunctionCallback> callbacks;
std::map<std::string, FunctionValidator*> 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);
};
}

View File

@ -1,45 +1,138 @@
#include <map>
#include "functionsignature.h"
namespace domain {
FunctionSignature add(std::string name, std::vector<Value::ValueType> types, FunctionCallback callback) {
return {name, types, callback};
}
class DivisibleValidator: public FunctionValidator {
public:
DivisibleValidator(): FunctionValidator("divisible", {Value::INT, Value::INT}) {}
std::vector<FunctionSignature> getSupportedFunctions() {
std::vector<FunctionSignature> s;
s.push_back(add("divisible", std::vector<Value::ValueType>{Value::INT, Value::INT},[](std::vector<Value> values) {
bool validate(std::vector<Value> values) override {
if(validateSignature(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::ValueType>{Value::INT, Value::INT}, [](std::vector<Value> values) {
}
return false;
}
void clear() override {}
};
class LessThenValidator: public FunctionValidator {
public:
LessThenValidator(): FunctionValidator("less_then", {Value::INT, Value::INT}) {}
bool validate(std::vector<Value> values) override {
if(validateSignature(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::ValueType>{Value::INT, Value::INT}, [](std::vector<Value> values) {
}
return false;
}
void clear() override {}
};
class GreaterThenValidator: public FunctionValidator {
public:
GreaterThenValidator(): FunctionValidator("greater_then", {Value::INT, Value::INT}) {}
bool validate(std::vector<Value> values) override {
if(validateSignature(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::ValueType>{Value::ADDRESS_SPACE, Value::INT}, [](std::vector<Value> values) {
}
return false;
}
void clear() override {}
};
class ContainsAddressValidator: public FunctionValidator {
public:
ContainsAddressValidator(): FunctionValidator("contains_address", {Value::ADDRESS_SPACE, Value::INT}) {}
bool validate(std::vector<Value> values) override {
if(validateSignature(values)) {
AddressSpace space = values[0].asAddressSpace();
long long address = values[1].asInt();
return space.contains(address);
}));
s.push_back(add("contains", std::vector<Value::ValueType>{Value::ADDRESS_SPACE, Value::INT, Value::INT}, [](std::vector<Value> values) {
}
return false;
}
void clear() override {}
};
class ContainsValidator: public FunctionValidator {
public:
ContainsValidator(): FunctionValidator("contains", {Value::ADDRESS_SPACE, Value::INT, Value::INT}) {}
bool validate(std::vector<Value> 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);
}));
s.push_back(add("unique", std::vector<Value::ValueType>{Value::ADDRESS_SPACE, Value::INT, Value::INT}, [](std::vector<Value> values) {
return true;
}));
}
return false;
}
void clear() override {}
};
return s;
class UniqueValidator: public FunctionValidator {
private:
std::map<std::string, std::vector<std::pair<long long int, long long int>>> 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<Value> 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<std::pair<long long int, long long int>>{}));
}
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<FunctionValidator*> getSupportedValidators() {
std::vector<FunctionValidator*> 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;
}
} // namespace domain

View File

@ -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<functional>
#include<vector>
@ -8,18 +8,46 @@
namespace domain {
typedef std::function<bool (std::vector<Value>)> FunctionCallback;
struct FunctionSignature {
class FunctionValidator {
private:
std::string name;
std::vector<Value::ValueType> params;
FunctionCallback callback;
std::vector<Value::ValueType> signature;
FunctionSignature(std::string name, std::vector<Value::ValueType> params, FunctionCallback callback): name(name), params(params), callback(callback) {}
protected:
FunctionValidator(std::string name, std::vector<Value::ValueType> signature) {
this->name = name;
this->signature = signature;
}
public:
std::string getName() {
return name;
}
std::vector<Value::ValueType> getSignature() {
return signature;
}
bool validateSignature(std::vector<Value> signature) {
if(this->signature.size() != signature.size()) {
return false;
}
for(int i=0; i<this->signature.size(); i++) {
if(this->signature[i] != signature[i].getType()) {
return false;
}
}
return true;
}
virtual bool validate(std::vector<Value> values) = 0;
virtual void clear() = 0;
};
std::vector<FunctionSignature> getSupportedFunctions();
std::vector<FunctionValidator*> getSupportedValidators();
} // namespace domain
#endif // DOMAIN_FUNCTIONSIGNATURE_H
#endif // DOMAIN_FUNCTION_VALIDATOR_H

View File

@ -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;
}

View File

@ -15,7 +15,7 @@ namespace domain {
struct RuleContext {
std::map<std::string, AddressSpace> addressSpaces;
std::map<std::string, Value> attributes;
std::map<std::string, FunctionCallback> function;
std::map<std::string, FunctionValidator*> function;
};
class Condition {

View File

@ -102,8 +102,8 @@ Popup::PopupType toType(PopupNode::PopupType type)
return Popup::ON_DEMAND;
}
SchemaCreator::SchemaCreator(std::vector<FunctionSignature> signatures)
: signatures(std::move(signatures))
SchemaCreator::SchemaCreator(std::vector<FunctionValidator*> validators)
: validators(std::move(validators))
{}
std::optional<Library> SchemaCreator::loadLibrary(LibraryNode node)
@ -736,19 +736,19 @@ std::optional<Condition> 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<Value> params;
for(uint j=0; j<signature.params.size(); j++) {
for(uint j=0; j<validator->getSignature().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);

View File

@ -61,7 +61,7 @@ class SchemaCreator
std::vector<SourceError> errors;
std::vector<FunctionSignature> signatures;
std::vector<FunctionValidator*> validators;
std::optional<AddressSpace> loadAddressSpace(AddressSpaceNode node);
std::optional<Component> loadComponent(ComponentNode node);
@ -130,7 +130,7 @@ class SchemaCreator
}
public:
SchemaCreator(std::vector<FunctionSignature> signatures);
SchemaCreator(std::vector<FunctionValidator*> validators);
std::vector<SourceError> getErrors() {
return errors;

View File

@ -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<std::string, domain::FunctionCallback> 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;

View File

@ -30,7 +30,7 @@ public:
std::optional<domain::Library> library = std::nullopt;
domain::Schema* schema = nullptr;
std::vector<domain::FunctionSignature> signatures;
std::vector<domain::FunctionValidator*> validators;
void setupUi();
void clear();